Created
July 4, 2024 04:19
-
-
Save oneblackcrayon/3fae7eaa6eb05bf08ed6697bd6eff487 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: WooCommerce Custom Account Tabs | |
* Plugin URI: https://www.example.com/ | |
* description: PHP Class to generate new account tabs for WooCommerce My Account page | |
* Version: 1.0 | |
* Author: | |
* Author URI: https://gist.github.com/JiveDig/0d3658676127f30a098859228fc5d8eb | |
* License: GPL2 | |
* A class to create new WooCommerce account tabs. | |
* | |
* @version 0.1.0 | |
* | |
* @link https://gist.github.com/JiveDig/0d3658676127f30a098859228fc5d8eb | |
* | |
* 1. Register a new tab on the My Account page. | |
* 2. Optionally position the tab before or after an existing tab by endpoint name. | |
* Default is last item before logout, if it exists, otherwise it's added as last item. | |
* 3. Optionally add a condition to show or hide the tab. | |
* 4. Use `Mai_WooCommerce_Account_Tab::is_tab( $endpoint )` to check if the current page is the tab. | |
* This is useful for enqueueing scripts or styles only on the tab page. | |
* | |
* Example usage: | |
* add_action( 'woocommerce_init', function() { | |
* new Mai_WooCommerce_Account_Tab( | |
* [ | |
* 'endpoint' => 'new-endpoint', // Required. | |
* 'label' => __( 'New Endpoint', 'textdomain' ), // Required. | |
* 'content' => '', // Optional. String or callable. | |
* 'condition' => current_user_can( 'edit_posts' ), // Optional. Boolean or callable. | |
* 'position' => [ // Optional. | |
* 'after' => 'edit-account', | |
* ], | |
* ] | |
* ); | |
* }); | |
* | |
* // Helper method: | |
* `Mai_WooCommerce_Account_Tab::is_tab( 'new-endpoint' )` | |
* | |
* @return void | |
*/ | |
// Exit if accessed directly. | |
if ( ! defined( 'ABSPATH' ) ) exit; | |
if ( ! class_exists( 'Mai_WooCommerce_Account_Tab' ) ): | |
class Mai_WooCommerce_Account_Tab { | |
/** | |
* The args. | |
* | |
* @var array | |
*/ | |
protected $args; | |
/** | |
* Gets is started. | |
* | |
* @since 0.1.0 | |
*/ | |
function __construct( $args ) { | |
// Set the data. | |
$this->args = $this->sanitize( $args ); | |
// Bail if no args. | |
if ( ! $this->args ) { | |
return; | |
} | |
// Hooks. | |
$this->hooks(); | |
} | |
/** | |
* Checks if the current page is the account page endpoint. | |
* | |
* @since 0.1.0 | |
* | |
* @return bool | |
*/ | |
static function is_tab( $endpoint ) { | |
static $cache = []; | |
// Maybe return cached value. | |
if ( isset( $cache[ $endpoint ] ) ) { | |
return $cache; | |
} | |
// Set cache. | |
$cache[ $endpoint ] = class_exists( 'WooCommerce' ) && is_account_page() && is_wc_endpoint_url( $endpoint ); | |
return $cache[ $endpoint ]; | |
} | |
/** | |
* Runs hooks. | |
* | |
* @since 0.1.0 | |
*/ | |
function hooks() { | |
add_filter( 'woocommerce_get_query_vars', [ $this, 'add_query_vars' ] ); | |
add_filter( 'woocommerce_account_menu_items', [ $this, 'add_menu_items' ] ); | |
add_action( 'template_redirect', [ $this, 'do_redirect' ] ); | |
// Bail if no content. | |
if ( ! $this->args['content'] ) { | |
return; | |
} | |
add_action( "woocommerce_account_{$this->args['endpoint']}_endpoint", [ $this, 'do_content' ] ); | |
} | |
/** | |
* Adds WooCommerce query vars. | |
* Woo uses these to add the endpoint. | |
* | |
* @since 0.1.0 | |
* | |
* @param array $vars The existing query vars. | |
* | |
* @return array | |
*/ | |
function add_query_vars( $vars ) { | |
$vars[ $this->args['endpoint'] ] = $this->args['endpoint']; | |
return $vars; | |
} | |
/** | |
* Adds account menu item. | |
* | |
* @since 0.1.0 | |
* | |
* @param array $items The existing items. | |
* | |
* @return array | |
*/ | |
function add_menu_items( $items ) { | |
// Bail if condition is not met. | |
if ( ! $this->condition_met() ) { | |
return $items; | |
} | |
// Get values. | |
$location = array_key_first( $this->args['position'] ); | |
$item = reset( $this->args['position'] ); | |
// Bail if no location or item. | |
if ( ! $location || ! $item ) { | |
return $items; | |
} | |
// If the item exists. | |
if ( isset( $items[ $item ] ) ) { | |
// Add the new item. | |
switch ( $location ) { | |
case 'before': | |
$items = $this->insert_before( $items, $item, [ $this->args['endpoint'] => $this->args['label'] ] ); | |
break; | |
case 'after': | |
$items = $this->insert_after( $items, $item, [ $this->args['endpoint'] => $this->args['label'] ] ); | |
break; | |
} | |
} | |
// Doesn't exist, check for logout. | |
elseif ( isset( $items['customer-logout'] ) ) { | |
$items = $this->insert_before( $items, 'customer-logout', [ $this->args['endpoint'] => $this->args['label'] ] ); | |
} | |
// Fallback to the last item. | |
else { | |
$items[] = [ $this->args['endpoint'] => $this->args['label'] ]; | |
} | |
return $items; | |
} | |
/** | |
* Redirect endpoint if condition is not met. | |
* | |
* @since 0.1.0 | |
* | |
* @return void | |
*/ | |
function do_redirect() { | |
// Bail if not this endpoint. | |
if ( ! self::is_tab( $this->args['endpoint'] ) ) { | |
return; | |
} | |
// Bail if conditions are met. | |
if ( $this->condition_met() ) { | |
return; | |
} | |
// Safely redirect to the main account page. | |
wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) ); | |
exit; | |
} | |
/** | |
* Adds content to the tab. | |
* | |
* @since 0.1.0 | |
* | |
* @return string | |
*/ | |
function do_content() { | |
// Bail if condition is not met. | |
if ( ! $this->condition_met() ) { | |
return; | |
} | |
// If callable, run it. | |
if ( is_callable( $this->args['content'] ) ) { | |
call_user_func( $this->args['content'] ); | |
return; | |
} | |
// Output content. | |
echo $this->args['content']; | |
} | |
/** | |
* Checks if the condition is met. | |
* | |
* @since 0.1.0 | |
* | |
* @return bool | |
*/ | |
function condition_met() { | |
static $cache = null; | |
// Maybe return cached value. | |
if ( ! is_null( $cache ) ) { | |
return $cache; | |
} | |
// Bail if callable condition is not met. | |
if ( is_callable( $this->args['condition'] ) && (bool) ! call_user_func( $this->args['condition'] ) ) { | |
$cache = false; | |
return $cache; | |
} | |
// Bail if condition and it's not met. | |
if ( '' !== $this->args['condition'] && ! $this->args['condition'] ) { | |
$cache = false; | |
return $cache; | |
} | |
// Set cache. | |
$cache = true; | |
return $cache; | |
} | |
/** | |
* Insert a value or key/value pair before a specific key in an array. | |
* If key doesn't exist, value is appended to the end of the array. | |
* | |
* @since 0.1.0 | |
* | |
* @param array $array | |
* @param string $key | |
* @param array $new | |
* | |
* @return array | |
*/ | |
function insert_before( array $array, $key, array $new ) { | |
$keys = array_keys( $array ); | |
$index = array_search( $key, $keys ); | |
$pos = $index !== false ? $index : count( $array ); // If key doesn't exist, insert at the end. | |
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) ); | |
} | |
/** | |
* Insert a value or key/value pair after a specific key in an array. | |
* If key doesn't exist, value is appended to the end of the array. | |
* | |
* @since 0.1.0 | |
* | |
* @param array $array | |
* @param string $key | |
* @param array $new | |
* | |
* @return array | |
*/ | |
function insert_after( array $array, $key, array $new ) { | |
$keys = array_keys( $array ); | |
$index = array_search( $key, $keys ); | |
$pos = false === $index ? count( $array ) : $index + 1; | |
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) ); | |
} | |
/** | |
* Sanitizes the args. | |
* | |
* @since 0.1.0 | |
* | |
* @param array $args The args. | |
* | |
* @return array | |
*/ | |
function sanitize( $args ) { | |
$sanitized = []; | |
$args = wp_parse_args( $args, [ | |
'endpoint' => '', | |
'label' => '', | |
'content' => '', | |
'condition' => '', | |
'position' => [], | |
] ); | |
// Bail if no endpoint or label. | |
if ( ! $args['endpoint'] || ! $args['label'] ) { | |
return $sanitized; | |
} | |
// Sanitize. | |
foreach ( $args as $key => $value ) { | |
switch ( $key ) { | |
case 'endpoint': | |
$sanitized[ $key ] = sanitize_title( $value ); | |
break; | |
case 'label': | |
$sanitized[ $key ] = sanitize_text_field( $value ); | |
break; | |
default: | |
$sanitized[ $key ] = $value; | |
break; | |
} | |
} | |
return $sanitized; | |
} | |
} | |
endif; | |
function my_custom_flush_rewrite_rules() { | |
flush_rewrite_rules(); | |
} | |
add_action( 'wp_loaded', 'my_custom_flush_rewrite_rules' ); | |
/** | |
* Enqueue scripts and styles for the new tab. | |
* | |
* @return void | |
*/ | |
// add_action( 'wp_enqueue_scripts', function() { | |
// if ( ! class_exists( 'Mai_WooCommerce_Account_Tab' ) ) { | |
// return; | |
// } | |
// if ( ! Mai_WooCommerce_Account_Tab::is_tab( 'edit-profile' ) ) { | |
// return; | |
// } | |
// // Enqueue styles. | |
// wp_enqueue_style( 'my-style-handle', get_stylesheet_directory_uri() . '/assets/css/filename.css', [], '1.0.0' ); | |
// // Enqueue scripts. | |
// wp_enqueue_script( 'my-script-handle', get_stylesheet_directory_uri() . '/assets/js/filename.js', [], '1.0.0' ); | |
// }); | |
add_action( 'woocommerce_init', function() { | |
new Mai_WooCommerce_Account_Tab( | |
[ | |
'endpoint' => 'new-woo-endpoint', // Required. | |
'label' => __( 'New Woo Endpoint Content', 'textdomain' ), // Required. | |
'content' => '', // Optional. String or callable. | |
'condition' => current_user_can( 'read' ), // Optional. Boolean or callable. | |
'position' => [ // Optional. | |
'after' => 'edit-account', | |
], | |
] | |
); | |
}); | |
/** | |
* Add content to the new tab. | |
* | |
* @return void | |
*/ | |
add_action( 'woocommerce_account_new-woo-endpoint_endpoint', function() { | |
// Do your thing. | |
$page_id = 1840; // The page ID | |
$page_data = get_page( $page_id ); // You must pass in a variable to the get_page function. If you pass in a value (e.g. get_page ( 123 ); ), WordPress will generate an error. | |
$title = apply_filters('the_title', $page_data->post_title, $id = null); | |
$content = apply_filters('the_content', $page_data->post_content); // Get Content and retain Wordpress filters such as paragraph tags. Origin from: http://wordpress.org/support/topic/get_pagepost-and-no-paragraphs-problem | |
echo '<h2>'.$title.'</h2>'; | |
echo $content; // Output Content | |
}); | |
/* @link: https://gist.github.com/sandeshjangam/45c46654cd45c32f7bf02f342a45e37e?permalink_comment_id=3690575#gistcomment-3690575 */ | |
add_filter( 'woocommerce_account_menu_item_classes', function( $classes, $endpoint ){ | |
if( $endpoint == "new-woo-endpoint" ) { | |
$urlStub = "/new-woo-endpoint/"; //the url should end with this | |
if( substr_compare( $_SERVER['REQUEST_URI'], $urlStub, -strlen( $urlStub ) ) ===0 ) $classes[] = 'is-active'; | |
} | |
return $classes; | |
}, 10,2 ); | |
/** | |
* @snippet Remove Dashboard from My Account | |
* @author Misha Rudrastyh | |
* @link https://rudrastyh.com/woocommerce/remove-dashboard-from-my-account-menu.html | |
*/ | |
// remove menu link | |
add_filter( 'woocommerce_account_menu_items', 'misha_remove_my_account_dashboard' ); | |
function misha_remove_my_account_dashboard( $menu_links ){ | |
unset( $menu_links[ 'dashboard' ] ); | |
return $menu_links; | |
} | |
// perform a redirect | |
add_action( 'template_redirect', 'misha_redirect_to_orders_from_dashboard' ); | |
function misha_redirect_to_orders_from_dashboard(){ | |
if( is_account_page() && empty( WC()->query->get_current_endpoint() ) ){ | |
wp_safe_redirect( wc_get_account_endpoint_url( 'orders' ) ); | |
exit; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment