1

I found a fantastic function which lets me create a tour for the site admins when visiting the dashboard for the first time. I managed to make it work really well, except when I tried to make two copies of this function to create two other tours in a different part of the dashboard. All 3 tours works great, except when I press Close on the second tour (called Visitors) it will register that I have closed the tour users_tour instead of the correct visitors_tour in the database. So somehow they collide. Maybe there is somewhere I have missed to create a unique function name causing this to happen.

This is the complete code (you will notice that the 3 are pretty much identical):

/**
 * Introduction Tour
 *
 * This class handles the pointers used in the introduction tour.
 * @package Popup Demo
 */

class Welcome_Tour {
    private $pointer_close_id_welcome = 'welcome_tour'; // Value can be cleared to retake tour
    // Class constructor. If user is on a pre pointer version bounce out.
    function __construct() {
        global $wp_version;
        // Pre 3.3 has no pointers
        if (version_compare($wp_version, '3.4', '<'))
            return false;
        // Version is updated
        add_action('admin_enqueue_scripts', array($this, 'welcome_enqueue'));
    }

    // Enqueue styles and scripts needed for the pointers.
    function welcome_enqueue() {
        if (!current_user_can('create_users') || current_user_can('update_core')) // Enable for site admins, disable for super admin
            return;
        // Assume pointer shouldn't be shown
        $enqueue_pointer_script_style = false;
        // Get array list of dismissed pointers for current user and convert it to array
        $dismissed_pointers = explode(',', get_user_meta(get_current_user_id(), 'dismissed_wp_pointers', true));
        // Check if our pointer is not among dismissed ones
        if (!in_array($this->pointer_close_id_welcome, $dismissed_pointers)) {
            $enqueue_pointer_script_style = true;
            // Add footer scripts using callback function
            add_action('admin_print_footer_scripts', array($this, 'welcome_intro_tour'));
        }
        // Enqueue pointer CSS and JS files, if needed
        if ($enqueue_pointer_script_style) {
            wp_enqueue_style('wp-pointer');
            wp_enqueue_script('wp-pointer');
        }
    }

    // Load the introduction tour
    function welcome_intro_tour() {
        $adminpages = array(
            // Array name is the unique ID of the screen @see: http://codex.wordpress.org/Function_Reference/get_current_screen
            'dashboard' => array(
                'content' => "<h3>" . __("Welcome", 'textdomain') . "</h3>"
                    . "<p>" . __("Congrats! Please take a moment and to take the tour.", 'textdomain') . "</p>", // Content for this pointer
                'id' => 'toplevel_page_clientside-view-site-logo', // ID of element where the pointer will point
                'position' => array(
                    'edge' => 'left', // Arrow position; change depending on where the element is located
                    'align' => 'center' // Alignment of Pointer
                ),
                'button2' => __('Next', 'textdomain'), // Text for the next button
                'function' => 'window.location="' . admin_url('edit.php?post_type=slide') . '";' // Where to take the user
            ),
            'edit-slide' => array(
                'content' => '<h3>' . __('Slides', 'textdomain') . '</h3><p>' . __('Here is where you can edit and reorder your future slides. But first we must create a slide, press Next.', 'textdomain') . '</p>',
                'id' => 'menu-posts-slide',

                'button2' => __('Next', 'textdomain'),
                'function' => 'window.location="' . admin_url('post-new.php?post_type=slide') . '";'
            ),
            'slide' => array(
                'content' => "<h3>" . __("Appearance", 'textdomain') . "</h3>"
                    . "<p>" . __("With your first slide created, let's go customize the appearance.", 'textdomain') . "</p>",
                'id' => 'menu-appearance',
                'button2' => __('Next', 'textdomain'),
                'function' => 'window.location="' . admin_url('customize.php?endtour=true') . '";'
            ),
        );
                // Disable tour on New Slide and only show it after Publish (Edit slide)
                global $post;
                if ($post->post_status === 'auto-draft') {
                    unset($adminpages['slide']);
                }

        $page = '';
        $screen = get_current_screen();
        // Check which page the user is on
        if (isset($_GET['page'])) {
            $page = $_GET['page'];
        }
        if (empty($page)) {
            $page = $screen->id;
        }
        $function = '';
        $button2 = '';
        $opt_arr = array();
        // Location the pointer points
        if (!empty($adminpages[$page]['id'])) {
            $id = '#' . $adminpages[$page]['id'];
        } else {
            $id = '#' . $screen->id;
        }
        // Options array for pointer used to send to JS
        if ('' != $page && in_array($page, array_keys($adminpages))) {
            $align = (is_rtl()) ? 'right' : 'left';
            $opt_arr = array(
                'content' => $adminpages[$page]['content'],
                'position' => array(
                    'edge' => (!empty($adminpages[$page]['position']['edge'])) ? $adminpages[$page]['position']['edge'] : 'left',
                    'align' => (!empty($adminpages[$page]['position']['align'])) ? $adminpages[$page]['position']['align'] : $align
                ),
                'pointerWidth' => 400
            );
            if (isset($adminpages[$page]['button2'])) {
                $button2 = (!empty($adminpages[$page]['button2'])) ? $adminpages[$page]['button2'] : __('Next', 'textdomain');
            }
            if (isset($adminpages[$page]['function'])) {
                $function = $adminpages[$page]['function'];
            }
        }
        $this->welcome_print_scripts($id, $opt_arr, __("Close", 'textdomain'), $button2, $function);
    }

    /**
     * Prints the pointer script
     * @param string $selector The CSS selector the pointer is attached to.
     * @param array $options The options for the pointer.
     * @param string $button1 Text for button 1
     * @param string|bool $button2 Text for button 2 (or false to not show it, defaults to false)
     * @param string $button2_function The JavaScript function to attach to button 2
     * @param string $button1_function The JavaScript function to attach to button 1
     */
    function welcome_print_scripts($selector, $options, $button1, $button2 = false, $button2_function = '', $button1_function = '') {
        ?>
        <script type="text/javascript">
            //<![CDATA[
            (function ($) {
                var welcome_pointer_options = <?php echo json_encode( $options ); ?>, setup;
                welcome_pointer_options = $.extend(welcome_pointer_options, {
                    buttons: function (event, t) {
                        button = jQuery('<a id="pointer-close" style="margin-left:5px" class="button-secondary">' + '<?php echo $button1; ?>' + '</a>');
                        button.bind('click.pointer', function () {
                            t.element.pointer('close');
                        });
                        return button;
                    }
                });
                setup = function () {
                    $('<?php echo $selector; ?>').pointer(welcome_pointer_options).pointer('open');
                    <?php
                    if ( $button2 ) { ?>
                    jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">' + '<?php echo $button2; ?>' + '</a>');
                    <?php } ?>
                    jQuery('#pointer-primary').click(function () {
                        <?php echo $button2_function; ?>
                    });
                    jQuery('#pointer-close').click(function () {
                        <?php if ( $button1_function == '' ) { ?>
                        $.post(ajaxurl, {
                            pointer: '<?php echo $this->pointer_close_id_welcome; ?>', // Pointer ID
                            action: 'dismiss-wp-pointer'
                        });
                        <?php } else { ?>
                        <?php echo $button1_function; ?>
                        <?php } ?>
                    });
                };
                if (welcome_pointer_options.position && welcome_pointer_options.position.defer_loading) {
                    $(window).bind('load.wp-pointers', setup);
                } else {
                    $(document).ready(setup);
                }
            })(jQuery);
            //]]>
        </script>
    <?php
    }
}
$welcome_tour = new Welcome_Tour();


/**
 * Visitors tour for site admins and users
 *
 * This class handles the pointers used in the introduction tour.
 * @package Popup Demo
 */

class Visitors_Tour {
    private $pointer_close_id_visitors = 'visitors_tour'; // Value can be cleared to retake tour

        // Class constructor. If user is on a pre pointer version bounce out.
    function __construct() {
        global $wp_version;
        // Pre 3.3 has no pointers
        if (version_compare($wp_version, '3.4', '<'))
            return false;
        // Version is updated
        add_action('admin_enqueue_scripts', array($this, 'visitors_enqueue'));
    }

    // Enqueue styles and scripts needed for the pointers.
    function visitors_enqueue() {
        if (current_user_can('update_core')) // Enable for everyone but super admin
            return;
        // Assume pointer shouldn't be shown
        $enqueue_pointer_script_style = false;
        // Get array list of dismissed pointers for current user and convert it to array
        $dismissed_pointers = explode(',', get_user_meta(get_current_user_id(), 'dismissed_wp_pointers', true));
        // Check if our pointer is not among dismissed ones
        if (!in_array($this->pointer_close_id_visitors, $dismissed_pointers)) {
            $enqueue_pointer_script_style = true;
            // Add footer scripts using callback function
            add_action('admin_print_footer_scripts', array($this, 'visitors_intro_tour'));
        }
        // Enqueue pointer CSS and JS files, if needed
        if ($enqueue_pointer_script_style) {
            wp_enqueue_style('wp-pointer');
            wp_enqueue_script('wp-pointer');
        }
    }

    // Load the introduction tour
    function visitors_intro_tour() {
        $adminpages = array(
            // Array name is the unique ID of the screen @see: http://codex.wordpress.org/Function_Reference/get_current_screen
            'edit-visitor' => array(
                'content' => "<h3>" . __("All Visitors", 'textdomain') . "</h3>"
                    . "<p>" . __("Here is where you can edit and reorder visitors. But first we must create a visitor, press Next.", 'textdomain') . "</p>", // Content for this pointer
                'id' => 'menu-posts-visitor', // ID of element where the pointer will point
                'position' => array(
                    'edge' => 'left', // Arrow position; change depending on where the element is located
                    'align' => 'center' // Alignment of Pointer
                ),
                'button2' => __('Next', 'textdomain'), // Text for the next button
                'function' => 'window.location="' . admin_url('post-new.php?post_type=visitor') . '";' // Where to take the user
            ),
            'visitor' => array(
                'content' => '<h3>' . __('New Visitors', 'textdomain') . '</h3><p>' . __('This is where you add new visitors, fill in Company name (if none, leave empty). Use the big editor to fill in the visitors names, separated with a new line (Enter). Select the start and end date and press Publish.', 'textdomain') . '</p>',
                'id' => 'menu-posts-visitor',
            ),
        );

        $page = '';
        $screen = get_current_screen();
        // Check which page the user is on
        if (isset($_GET['page'])) {
            $page = $_GET['page'];
        }
        if (empty($page)) {
            $page = $screen->id;
        }
        $function = '';
        $button2 = '';
        $opt_arr = array();
        // Location the pointer points
        if (!empty($adminpages[$page]['id'])) {
            $id = '#' . $adminpages[$page]['id'];
        } else {
            $id = '#' . $screen->id;
        }
        // Options array for pointer used to send to JS
        if ('' != $page && in_array($page, array_keys($adminpages))) {
            $align = (is_rtl()) ? 'right' : 'left';
            $opt_arr = array(
                'content' => $adminpages[$page]['content'],
                'position' => array(
                    'edge' => (!empty($adminpages[$page]['position']['edge'])) ? $adminpages[$page]['position']['edge'] : 'left',
                    'align' => (!empty($adminpages[$page]['position']['align'])) ? $adminpages[$page]['position']['align'] : $align
                ),
                'pointerWidth' => 400
            );
            if (isset($adminpages[$page]['button2'])) {
                $button2 = (!empty($adminpages[$page]['button2'])) ? $adminpages[$page]['button2'] : __('Next', 'textdomain');
            }
            if (isset($adminpages[$page]['function'])) {
                $function = $adminpages[$page]['function'];
            }
        }
        $this->visitors_print_scripts($id, $opt_arr, __("Close", 'textdomain'), $button2, $function);
    }

    /**
     * Prints the pointer script
     * @param string $selector The CSS selector the pointer is attached to.
     * @param array $options The options for the pointer.
     * @param string $button1 Text for button 1
     * @param string|bool $button2 Text for button 2 (or false to not show it, defaults to false)
     * @param string $button2_function The JavaScript function to attach to button 2
     * @param string $button1_function The JavaScript function to attach to button 1
     */
    function visitors_print_scripts($selector, $options, $button1, $button2 = false, $button2_function = '', $button1_function = '') {
        ?>
        <script type="text/javascript">
            //<![CDATA[
            (function ($) {
                var visitors_pointer_options = <?php echo json_encode( $options ); ?>, setup;
                visitors_pointer_options = $.extend(visitors_pointer_options, {
                    buttons: function (event, t) {
                        button = jQuery('<a id="pointer-close" style="margin-left:5px" class="button-secondary">' + '<?php echo $button1; ?>' + '</a>');
                        button.bind('click.pointer', function () {
                            t.element.pointer('close');
                        });
                        return button;
                    }
                });
                setup = function () {
                    $('<?php echo $selector; ?>').pointer(visitors_pointer_options).pointer('open');
                    <?php
                    if ( $button2 ) { ?>
                    jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">' + '<?php echo $button2; ?>' + '</a>');
                    <?php } ?>
                    jQuery('#pointer-primary').click(function () {
                        <?php echo $button2_function; ?>
                    });
                    jQuery('#pointer-close').click(function () {
                        <?php if ( $button1_function == '' ) { ?>
                        $.post(ajaxurl, {
                            pointer: '<?php echo $this->pointer_close_id_visitors; ?>', // Pointer ID
                            action: 'dismiss-wp-pointer'
                        });
                        <?php } else { ?>
                        <?php echo $button1_function; ?>
                        <?php } ?>
                    });
                };
                if (visitors_pointer_options.position && visitors_pointer_options.position.defer_loading) {
                    $(window).bind('load.wp-pointers', setup);
                } else {

                    $(document).ready(setup);
                }
            })(jQuery);
            //]]>
        </script>
    <?php
    }
}
$visitors_tour = new Visitors_Tour();


/**
 * Users tour for site admins
 *
 * This class handles the pointers used in the introduction tour.
 * @package Popup Demo
 */

class Users_Tour {
    private $pointer_close_id_users = 'users_tour'; // Value can be cleared to retake tour

        // Class constructor. If user is on a pre pointer version bounce out.
    function __construct() {
        global $wp_version;
        // Pre 3.3 has no pointers
        if (version_compare($wp_version, '3.4', '<'))
            return false;
        // Version is updated
        add_action('admin_enqueue_scripts', array($this, 'users_enqueue'));
    }

    // Enqueue styles and scripts needed for the pointers.
    function users_enqueue() {
        if (!current_user_can('create_users') || current_user_can('update_core')) // Enable for site admins, disable for super admin
            return;
        // Assume pointer shouldn't be shown
        $enqueue_pointer_script_style = false;
        // Get array list of dismissed pointers for current user and convert it to array
        $dismissed_pointers = explode(',', get_user_meta(get_current_user_id(), 'dismissed_wp_pointers', true));
        // Check if our pointer is not among dismissed ones
        if (!in_array($this->pointer_close_id_users, $dismissed_pointers)) {
            $enqueue_pointer_script_style = true;
            // Add footer scripts using callback function
            add_action('admin_print_footer_scripts', array($this, 'users_intro_tour'));
        }
        // Enqueue pointer CSS and JS files, if needed
        if ($enqueue_pointer_script_style) {
            wp_enqueue_style('wp-pointer');
            wp_enqueue_script('wp-pointer');
        }
    }

    // Load the introduction tour
    function users_intro_tour() {
        $adminpages = array(
            // Array name is the unique ID of the screen @see: http://codex.wordpress.org/Function_Reference/get_current_screen
            'users' => array(
                'content' => "<h3>" . __("All Users", 'textdomain') . "</h3>"
                    . "<p>" . __("Here you can manage your users. Press Next to add a new user.", 'textdomain') . "</p>", // Content for this pointer
                'id' => 'menu-users', // ID of element where the pointer will point
                'position' => array(
                    'edge' => 'left', // Arrow position; change depending on where the element is located
                    'align' => 'center' // Alignment of Pointer
                ),
                'button2' => __('Next', 'textdomain'), // Text for the next button
                'function' => 'window.location="' . admin_url('user-new.php') . '";' // Where to take the user
            ),
            'user' => array(
                'content' => '<h3>' . __('New User', 'textdomain') . '</h3><p>' . __('This is where you add new users.', 'textdomain') . '</p>',
                'id' => 'menu-users',
            ),
        );

        $page = '';
        $screen = get_current_screen();
        // Check which page the user is on
        if (isset($_GET['page'])) {
            $page = $_GET['page'];
        }
        if (empty($page)) {
            $page = $screen->id;
        }
        $function = '';
        $button2 = '';
        $opt_arr = array();
        // Location the pointer points
        if (!empty($adminpages[$page]['id'])) {
            $id = '#' . $adminpages[$page]['id'];
        } else {
            $id = '#' . $screen->id;
        }
        // Options array for pointer used to send to JS
        if ('' != $page && in_array($page, array_keys($adminpages))) {
            $align = (is_rtl()) ? 'right' : 'left';
            $opt_arr = array(
                'content' => $adminpages[$page]['content'],
                'position' => array(
                    'edge' => (!empty($adminpages[$page]['position']['edge'])) ? $adminpages[$page]['position']['edge'] : 'left',
                    'align' => (!empty($adminpages[$page]['position']['align'])) ? $adminpages[$page]['position']['align'] : $align
                ),
                'pointerWidth' => 400
            );
            if (isset($adminpages[$page]['button2'])) {
                $button2 = (!empty($adminpages[$page]['button2'])) ? $adminpages[$page]['button2'] : __('Next', 'textdomain');
            }
            if (isset($adminpages[$page]['function'])) {
                $function = $adminpages[$page]['function'];
            }
        }
        $this->users_print_scripts($id, $opt_arr, __("Close", 'textdomain'), $button2, $function);
    }

    /**
     * Prints the pointer script
     * @param string $selector The CSS selector the pointer is attached to.
     * @param array $options The options for the pointer.
     * @param string $button1 Text for button 1
     * @param string|bool $button2 Text for button 2 (or false to not show it, defaults to false)
     * @param string $button2_function The JavaScript function to attach to button 2
     * @param string $button1_function The JavaScript function to attach to button 1
     */
    function users_print_scripts($selector, $options, $button1, $button2 = false, $button2_function = '', $button1_function = '') {
        ?>
        <script type="text/javascript">
            //<![CDATA[
            (function ($) {
                var users_pointer_options = <?php echo json_encode( $options ); ?>, setup;
                users_pointer_options = $.extend(users_pointer_options, {
                    buttons: function (event, t) {
                        button = jQuery('<a id="pointer-close" style="margin-left:5px" class="button-secondary">' + '<?php echo $button1; ?>' + '</a>');
                        button.bind('click.pointer', function () {
                            t.element.pointer('close');
                        });
                        return button;
                    }
                });
                setup = function () {
                    $('<?php echo $selector; ?>').pointer(users_pointer_options).pointer('open');
                    <?php
                    if ( $button2 ) { ?>
                    jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">' + '<?php echo $button2; ?>' + '</a>');
                    <?php } ?>
                    jQuery('#pointer-primary').click(function () {
                        <?php echo $button2_function; ?>
                    });
                    jQuery('#pointer-close').click(function () {
                        <?php if ( $button1_function == '' ) { ?>
                        $.post(ajaxurl, {
                            pointer: '<?php echo $this->pointer_close_id_users; ?>', // Pointer ID
                            action: 'dismiss-wp-pointer'
                        });
                        <?php } else { ?>
                        <?php echo $button1_function; ?>
                        <?php } ?>
                    });
                };
                if (users_pointer_options.position && users_pointer_options.position.defer_loading) {
                    $(window).bind('load.wp-pointers', setup);
                } else {

                    $(document).ready(setup);
                }
            })(jQuery);
            //]]>
        </script>
    <?php
    }
}
$users_tour = new Users_Tour();

I have tried to find a solution to this for 5 hours now without making any progress. This is my last resort, and I understand that it might not be easy to help with this! But maybe there is a simple solution!

  • This seems kind of out of the scope of this site - it's a very localized question. As far as code I would suggest you create a parent class and then if you need to create either child classes or just individual objects from the class, instead of duplicating things. OOP is supposed to prevent the duplication. :) – WebElaine Jun 5 '18 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.