Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save oneblackcrayon/3fae7eaa6eb05bf08ed6697bd6eff487 to your computer and use it in GitHub Desktop.
Save oneblackcrayon/3fae7eaa6eb05bf08ed6697bd6eff487 to your computer and use it in GitHub Desktop.
<?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