Создать WP учебник для пользователей с указателем администратора, используя следующую кнопку для навигации


9

Я стремлюсь создать учебник для моих пользователей для админки. Для этого я использую указатели администратора, доступные в ядре WP. Моя цель:

введите описание изображения здесь

Я почти у цели. Что я получил так далеко ...

Поставить в очередь сценарии wp-указателя:

add_action( 'admin_enqueue_scripts', 'custom_admin_pointers_header' );

function custom_admin_pointers_header() {
    if ( custom_admin_pointers_check() ) {
        add_action( 'admin_print_footer_scripts', 'custom_admin_pointers_footer' );

        wp_enqueue_script( 'wp-pointer' );
        wp_enqueue_style( 'wp-pointer' );
    }
}

Вспомогательные функции, включая условную проверку и скрипт нижнего колонтитула:

function custom_admin_pointers_check() {
    $admin_pointers = custom_admin_pointers();
    foreach ( $admin_pointers as $pointer => $array ) {
        if ( $array['active'] )
            return true;
    }
}

function custom_admin_pointers_footer() {
    $admin_pointers = custom_admin_pointers();
    ?>
    <script type="text/javascript">
        /* <![CDATA[ */
        ( function($) {
            <?php
            foreach ( $admin_pointers as $pointer => $array ) {
               if ( $array['active'] ) {
                  ?>
            $( '<?php echo $array['anchor_id']; ?>' ).pointer( {
                content: '<?php echo $array['content']; ?>',
                position: {
                    edge: '<?php echo $array['edge']; ?>',
                    align: '<?php echo $array['align']; ?>'
                },
                close: function() {
                    $.post( ajaxurl, {
                        pointer: '<?php echo $pointer; ?>',
                        action: 'dismiss-wp-pointer'
                    } );
                }
            } ).pointer( 'open' );
            <?php
         }
      }
      ?>
        } )(jQuery);
        /* ]]> */
    </script>
<?php
}

Теперь мы готовы собрать массив указателей:

function custom_admin_pointers() {
    $dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
    $version = '1_0'; // replace all periods in 1.0 with an underscore
    $prefix = 'custom_admin_pointers' . $version . '_';

    $new_pointer_content = '<h3>' . __( 'Add New Item' ) . '</h3>';
    $new_pointer_content .= '<p>' . __( 'Easily add a new post, media item, link, page or user by selecting from this drop down menu.' ) . '</p>';

    $story_pointer_content = '<h3>' . __( 'Another info' ) . '</h3>';
    $story_pointer_content .= '<p>' . __( 'Lorem ipsum...' ) . '</p>';


    return array(
        $prefix . 'new_items' => array(
            'content' => $new_pointer_content,
            'anchor_id' => '#wp-admin-bar-new-content',
            'edge' => 'top',
            'align' => 'left',
            'active' => ( ! in_array( $prefix . 'new_items', $dismissed ) )
        ),
        $prefix.'story_cover_help' => array(
            'content' => $story_pointer_content,
            'anchor_id' => '#save-post',
            'edge' => 'top',
            'align' => 'right',
            'active' => ( ! in_array( $prefix . 'story_cover_help', $dismissed ) )
        )
    );

}

Код не требует пояснений. Мы можем легко добавить больше указателей, расширяя массив. Все отлично работает в WP4.

Теперь к проблеме: все всплывающие указатели появляются одновременно, что делает этот интерфейс плохим для учебника.

Моя цель состоит в том, чтобы показывать указатели один за другим и позволить пользователю нажимать кнопку « Далее» для навигации по учебнику. Следующая кнопка должна открыть следующий указатель и закрыть последний.

Как я могу это сделать?

Ответы:


10

Вы вызываете .pointer( 'open' );функцию javascript для всех объектов указателей, поэтому неудивительно, что все указатели появляются одновременно ...

Тем не менее, я не понимаю, почему вы возвращаете все указатели (даже неактивные) из, custom_admin_pointers()а затем добавляете дополнительную функцию для проверки наличия каких-либо активных указателей и проверки внутри цикла указателей ( if ( $array['active'] ) {), чтобы выбрать добавление указателя javascript или нет. Не проще ли просто вернуть только активные указатели?

Более того, вы добавляете этот javascript на все страницы администратора, не слишком ли много? Также учтите, что некоторые элементы, такие как "# save-post", доступны только на новой странице поста, так что не лучше ли добавлять указатели только на новую страницу банка?

Наконец, насколько беспорядочно этот javascript перепутан с PHP, я думаю, вам стоит подумать об использовании wp_localize_scriptдля передачи данных в javascript.

План:

  1. Переместите определения указателей в PHP в отдельный файл, таким образом, его легко редактировать, а также удалять разметку из кода PHP, все становится более читабельным и понятным
  2. В указателях конфигурации добавить свойство «где» , который будет использоваться для набора , в котором администратор страницы должно появиться всплывающее окно: post-new.php, index.php...
  3. Напишите класс, который будет обрабатывать загрузку, разбор и фильтрацию информации указателей.
  4. Напишите некоторые js goodness, которые помогут нам изменить стандартную кнопку «Удалить» на «Далее»

# 4 может (вероятно) легко сделать , зная указатель плагин хорошо, но это не мой случай. Поэтому я буду использовать общий код jQuery для получения результата, если кто-то может улучшить мой код, я буду признателен.


редактировать

Я отредактировал код (в основном js), потому что есть разные вещи, которые я не учел: некоторые указатели могут быть добавлены к одной и той же привязке, или одинаковые указатели могут быть добавлены к несуществующим или невидимым привязкам. Во всем этом случае предыдущий код не работал, новая версия, кажется, хорошо решает эти проблемы.

Я также настроил Gist со всем кодом, который использовал для тестирования.


Давайте начнем с пунктов # 1 и # 2 : создайте файл с именем pointers.phpи напишите там:

<?php
$pointers = array();

$pointers['new-items'] = array(
  'title'     => sprintf( '<h3>%s</h3>', esc_html__( 'Add New Item' ) ),
  'content'   => sprintf( '<p>%s</p>', esc_html__( 'Easily add a new post..' ) ),
  'anchor_id' => '#wp-admin-bar-new-content',
  'edge'      => 'top',
  'align'     => 'left',
  'where'     => array( 'index.php', 'post-new.php' ) // <-- Please note this
);

$pointers['story_cover_help'] = array(
  'title'     => sprintf( '<h3>%s</h3>', esc_html__( 'Another info' ) ),
  'content'   => sprintf( '<p>%s</p>', esc_html__( 'Lore ipsum....' ) ),
  'anchor_id' => '#save-post',
  'edge'      => 'top',
  'align'     => 'right',
  'where'     => array( 'post-new.php' ) // <-- Please note this
);

// more pointers here...

return $pointers; 

Все настройки указателей здесь. Когда вам нужно что-то изменить, просто откройте этот файл и отредактируйте его.

Обратите внимание на свойство where, которое представляет собой массив страниц, где указатель должен быть доступен.

Если вы хотите отобразить указатели на странице, сгенерированной плагином, найдите эту строку, обрисованную в общих чертах ниже, public function filter( $page ) {и добавьте die($page);сразу под ней. Затем откройте соответствующую страницу плагина и используйте эту строку в whereсвойстве.

Хорошо, теперь точка № 3 .

Прежде чем писать класс, я просто хочу написать интерфейс: там я добавлю комментарии, чтобы вы могли лучше понять, что будет делать класс.

<?php
interface PointersManagerInterface {

  /**
  * Load pointers from file and setup id with prefix and version.
  * Cast pointers to objects.
  */
  public function parse();

  /**
  * Remove from parse pointers dismissed ones and pointers
  * that should not be shown on given page
  *
  * @param string $page Current admin page file
  */
  public function filter( $page );

}

Я думаю, должно быть довольно ясно. Теперь давайте напишем класс, он будет содержать 2 метода из интерфейса плюс конструктор.

<?php namespace GM;

class PointersManager implements PointersManagerInterface {

  private $pfile;
  private $version;
  private $prefix;
  private $pointers = array();

  public function __construct( $file, $version, $prefix ) {
    $this->pfile = file_exists( $file ) ? $file : FALSE;
    $this->version = str_replace( '.', '_', $version );
    $this->prefix = $prefix;
  }

  public function parse() {
    if ( empty( $this->pfile ) ) return;
    $pointers = (array) require_once $this->pfile;
    if ( empty($pointers) ) return;
    foreach ( $pointers as $i => $pointer ) {
      $pointer['id'] = "{$this->prefix}{$this->version}_{$i}";
      $this->pointers[$pointer['id']] = (object) $pointer;
    }
  }

  public function filter( $page ) {
    if ( empty( $this->pointers ) ) return array();
    $uid = get_current_user_id();
    $no = explode( ',', (string) get_user_meta( $uid, 'dismissed_wp_pointers', TRUE ) );
    $active_ids = array_diff( array_keys( $this->pointers ), $no );
    $good = array();
    foreach( $this->pointers as $i => $pointer ) {
      if (
        in_array( $i, $active_ids, TRUE ) // is active
        && isset( $pointer->where ) // has where
        && in_array( $page, (array) $pointer->where, TRUE ) // current page is in where
      ) {
       $good[] = $pointer;
      }
    }
    $count = count( $good );
    if ( $good === 0 ) return array();
    foreach( array_values( $good ) as $i => $pointer ) {
      $good[$i]->next = $i+1 < $count ? $good[$i+1]->id : '';
    }
    return $good;
  }
}

Код очень прост и выполняет именно то, что ожидает интерфейс.

Однако сам по себе класс ничего не делает, нам нужен хук, чтобы создать экземпляр класса и запустить 2 метода, передавая соответствующие аргументы.

'admin_enqueue_scripts'Идеально подходит для нашей области: там мы будем иметь доступ к текущей странице администратора , и мы можем также Епдиеие скрипты и стили необходимы.

add_action( 'admin_enqueue_scripts', function( $page ) {
  $file = plugin_dir_path( __FILE__ ) . 'pointers.php';
  // Arguments: pointers php file, version (dots will be replaced), prefix
  $manager = new PointersManager( $file, '5.0', 'custom_admin_pointers' );
  $manager->parse();
  $pointers = $manager->filter( $page );
  if ( empty( $pointers ) ) { // nothing to do if no pointers pass the filter
    return;
  }
  wp_enqueue_style( 'wp-pointer' );
  $js_url = plugins_url( 'pointers.js', __FILE__ );
  wp_enqueue_script( 'custom_admin_pointers', $js_url, array('wp-pointer'), NULL, TRUE );
  // data to pass to javascript
  $data = array(
    'next_label' => __( 'Next' ),
    'close_label' => __('Close'),
    'pointers' => $pointers
  );
  wp_localize_script( 'custom_admin_pointers', 'MyAdminPointers', $data );
} );

Ничего особенного: просто использование класса для получения данных указателей и, если некоторые указатели проходят фильтры, ставят в очередь стили и сценарии. Затем передайте данные указателей в скрипт вместе с локализованной меткой «Далее» для кнопки.

Хорошо, теперь самая сложная часть: JS. Опять же, я хочу подчеркнуть, что я не знаю, какой плагин-указатель использует WordPress, поэтому то, что я делаю в своем коде, можно сделать лучше, если кто-то это знает, однако мой код работает и, вообще говоря, это не так уж плохо.

( function($, MAP) {

  $(document).on( 'MyAdminPointers.setup_done', function( e, data ) {
    e.stopImmediatePropagation();
    MAP.setPlugin( data ); // open first popup
  } );

  $(document).on( 'MyAdminPointers.current_ready', function( e ) {
    e.stopImmediatePropagation();
    MAP.openPointer(); // open a popup
  } );

  MAP.js_pointers = {};        // contain js-parsed pointer objects
  MAP.first_pointer = false;   // contain first pointer anchor jQuery object
  MAP.current_pointer = false; // contain current pointer jQuery object
  MAP.last_pointer = false;    // contain last pointer jQuery object
  MAP.visible_pointers = [];   // contain ids of pointers whose anchors are visible

  MAP.hasNext = function( data ) { // check if a given pointer has valid next property
    return typeof data.next === 'string'
      && data.next !== ''
      && typeof MAP.js_pointers[data.next].data !== 'undefined'
      && typeof MAP.js_pointers[data.next].data.id === 'string';
  };

  MAP.isVisible = function( data ) { // check if anchor for given pointer is visible
    return $.inArray( data.id, MAP.visible_pointers ) !== -1;
  };

  // given a pointer object, return its the anchor jQuery object if available
  // otherwise return first available, lookin at next property of subsequent pointers
  MAP.getPointerData = function( data ) { 
    var $target = $( data.anchor_id );
    if ( $.inArray(data.id, MAP.visible_pointers) !== -1 ) {
      return { target: $target, data: data };
    }
    $target = false;
    while( MAP.hasNext( data ) && ! MAP.isVisible( data ) ) {
      data = MAP.js_pointers[data.next].data;
      if ( MAP.isVisible( data ) ) {
        $target = $(data.anchor_id);
      }
    }
    return MAP.isVisible( data )
      ? { target: $target, data: data }
      : { target: false, data: false };
  };

  // take pointer data and setup pointer plugin for anchor element
  MAP.setPlugin = function( data ) {
    if ( typeof MAP.last_pointer === 'object') {
      MAP.last_pointer.pointer('destroy');
      MAP.last_pointer = false;
    }
    MAP.current_pointer = false;
    var pointer_data = MAP.getPointerData( data );
      if ( ! pointer_data.target || ! pointer_data.data ) {
      return;
    }
    $target = pointer_data.target;
    data = pointer_data.data;
    $pointer = $target.pointer({
      content: data.title + data.content,
      position: { edge: data.edge, align: data.align },
      close: function() {
        // open next pointer if it exists
        if ( MAP.hasNext( data ) ) {
          MAP.setPlugin( MAP.js_pointers[data.next].data );
        }
        $.post( ajaxurl, { pointer: data.id, action: 'dismiss-wp-pointer' } );
      }
    });
    MAP.current_pointer = { pointer: $pointer, data: data };
    $(document).trigger( 'MyAdminPointers.current_ready' );
  };

  // scroll the page to current pointer then open it
  MAP.openPointer = function() {          
    var $pointer = MAP.current_pointer.pointer;
    if ( ! typeof $pointer === 'object' ) {
      return;
    }
    $('html, body').animate({ // scroll page to pointer
      scrollTop: $pointer.offset().top - 30
    }, 300, function() { // when scroll complete
      MAP.last_pointer = $pointer;
        var $widget = $pointer.pointer('widget');
        MAP.setNext( $widget, MAP.current_pointer.data );
        $pointer.pointer( 'open' ); // open
    });
  };

  // if there is a next pointer set button label to "Next", to "Close" otherwise
  MAP.setNext = function( $widget, data ) {
    if ( typeof $widget === 'object' ) {
      var $buttons = $widget.find('.wp-pointer-buttons').eq(0);        
      var $close = $buttons.find('a.close').eq(0);
      $button = $close.clone(true, true).removeClass('close');
      $buttons.find('a.close').remove();
      $button.addClass('button').addClass('button-primary');
      has_next = false;
      if ( MAP.hasNext( data ) ) {
        has_next_data = MAP.getPointerData(MAP.js_pointers[data.next].data);
        has_next = has_next_data.target && has_next_data.data;
      }
      var label = has_next ? MAP.next_label : MAP.close_label;
      $button.html(label).appendTo($buttons);
    }
  };

  $(MAP.pointers).each(function(index, pointer) { // loop pointers data
    if( ! $().pointer ) return;      // do nothing if pointer plugin isn't available
    MAP.js_pointers[pointer.id] = { data: pointer };
    var $target = $(pointer.anchor_id);
    if ( $target.length && $target.is(':visible') ) { // anchor exists and is visible?
      MAP.visible_pointers.push(pointer.id);
      if ( ! MAP.first_pointer ) {
        MAP.first_pointer = pointer;
      }
    }
    if ( index === ( MAP.pointers.length - 1 ) && MAP.first_pointer ) {
      $(document).trigger( 'MyAdminPointers.setup_done', MAP.first_pointer );
    }
  });

} )(jQuery, MyAdminPointers); // MyAdminPointers is passed by `wp_localize_script`

С помощью комментариев код должен быть довольно понятным, по крайней мере, я на это надеюсь.

Хорошо, мы закончили. Наш PHP проще и лучше организован, наш JavaScript более читабелен, указатели легче редактировать и, что более важно, все работает.


1
@ChristineCooper конечно. Итак, проблемы со сценарием 2: 1 в том, как теперь работает скрипт, вы можете добавить 1 указатель на 1 идентификатор привязки: использование одного и того же якоря для более чем одного указателя приведет к сбою сценария. Вторая проблема заключается в том, что некоторые указатели используют привязку к идентификаторам, которые могут отсутствовать на странице. Например, один указатель предназначен для '# comment-55' в index.php, и он не найден. Некоторые указатели в post.php нацелены на метабоксы, которые могут быть скрыты ... и так далее. Однажды в текущей версии скрипта указатели «сцепляются», если он не найден, все последующие операции тоже не будут работать. Я собираюсь посмотреть, есть ли простой способ преодолеть эти проблемы.
gmazzap

1
@ChristineCooper Рад, что это сработало. Я скопирую весь код из Gist сюда. Условие можно поставить сразу после add_action( 'admin_enqueue_scripts', function( $page ) {простого возврата, если у пользователя нет требуемой роли.
gmazzap

Пожалуйста, измените значение 30 на 120 в строке: "scrollTop: $ pointer.offset (). Top - 30" - причина в том, что верхняя панель инструментов иногда при прокрутке закрывает окно указателя.
Кристина Купер

У меня есть одна небольшая проблема. Страница, которая мне нужна, чтобы появилось несколько указателей: «admin.php? Page = plugin-path / file.php» - что именно мне добавить в массив where ? Я попытался "admin.php", "plugin-path / file.php", "file.php" и любые варианты, которые я мог придумать. Есть ли причина, по которой он не может обнаружить эту страницу или я делаю это неправильно?
Кристина Купер

1
@ChristineCooper откройте страницу администрирования плагина и скопируйте URL из браузера . После этого откройте файл, содержащий мой код выше. Найдите строку public function filter( $page ) {в PointersManagerклассе и сразу после этой строки поставьте die($page);. Откройте браузер и вставьте URL-адрес, страница умрет со строкой: это то, что вы должны использовать как 'where'.
gmazzap

7

Аааа .. да. Указатели WordPress. Вы знаете, когда дело доходит до использования указателей, существует довольно много смешанных чувств;)

Вы были на правильном пути с вашим кодом выше. Но есть пара вопросов.

@GM прав насчет pointer('open')команды, открывающей все ваши указатели одновременно. Кроме того, вы не предоставляете метод продвижения по указателям.

Я боролся с этой же проблемой .. и придумал свой собственный подход. Я использую переменную запроса в URL, перезагружаю страницу на страницу администратора, где я хочу отобразить следующий указатель, и позволяю jQuery обрабатывать все остальное.

WP Pointers Class

Я решил написать это как класс. Но сначала я собираюсь показать это постепенно, чтобы помочь вам лучше понять, что происходит.

Начало урока

// Create as a class
class testWPpointers {

    // Define pointer version
    const DISPLAY_VERSION = 'v1.0';

    // Initiate construct
    function __construct () {
        add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));  // Hook to admin_enqueue_scripts
    }

    function admin_enqueue_scripts () {

        // Check to see if user has already dismissed the pointer tour
        $dismissed = explode (',', get_user_meta (wp_get_current_user ()->ID, 'dismissed_wp_pointers', true));
        $do_tour = !in_array ('test_wp_pointer', $dismissed);

        // If not, we are good to continue
        if ($do_tour) {

            // Enqueue necessary WP scripts and styles
            wp_enqueue_style ('wp-pointer');
            wp_enqueue_script ('wp-pointer');

            // Finish hooking to WP admin areas
            add_action('admin_print_footer_scripts', array($this, 'admin_print_footer_scripts'));  // Hook to admin footer scripts
            add_action('admin_head', array($this, 'admin_head'));  // Hook to admin head
        }
    }

    // Used to add spacing between the two buttons in the pointer overlay window.
    function admin_head () {
        ?>
        <style type="text/css" media="screen">
            #pointer-primary {
                margin: 0 5px 0 0;
            }
        </style>
        <?php
    }
  1. Мы определили класс.
  2. Мы создали класс и добавили действие в admin_enqueue_scripts.
  3. Мы определили, были ли наши указатели уже отклонены.
  4. Если нет, мы продолжаем ставить в очередь необходимые скрипты.

Вам не нужно ничего менять в этих первых функциях.

Настройка массива элементов указателя

Следующим шагом является определение каждого из указателей. Нам нужно определить пять элементов (кроме последнего указателя). Мы сделаем это с помощью массивов. Давайте посмотрим на функцию:

// Define footer scripts
function admin_print_footer_scripts () {

    // Define global variables
    global $pagenow;
    global $current_user;

    //*****************************************************************************************************
    // This is our array of individual pointers.
    // -- The array key should be unique.  It is what will be used to 'advance' to the next pointer.
    // -- The 'id' should correspond to an html element id on the page.
    // -- The 'content' will be displayed inside the pointer overlay window.
    // -- The 'button2' is the text to show for the 'action' button in the pointer overlay window.
    // -- The 'function' is the method used to reload the window (or relocate to a new window).
    //    This also creates a query variable to add to the end of the url.
    //    The query variable is used to determine which pointer to display.
    //*****************************************************************************************************
    $tour = array (
        'quick_press' => array (
            'id' => '#dashboard_quick_press',
            'content' => '<h3>' . __('Congratulations!', 'test_lang') . '</h3>'
                . '<p><strong>' . __('WP Pointers is working properly.', 'test_lang') . '</strong></p>'
                . '<p>' . __('This pointer is attached to the "Quick Draft" admin widget.', 'test_lang') . '</p>'
                . '<p>' . __('Our next pointer will take us to the "Settings" admin menu.', 'test_lang') . '</p>',
            'button2' => __('Next', 'test_lang'),
            'function' => 'window.location="' . $this->get_admin_url('options-general.php', 'site_title') . '"'  // We are relocating to "Settings" page with the 'site_title' query var
            ),
        'site_title' => array (
            'id' => '#blogname',
            'content' => '<h3>' . __('Moving along to Site Title.', 'test_lang') . '</h3>'
            . '<p><strong>' . __('Another WP Pointer.', 'test_lang') . '</strong></p>'
            . '<p>' . __('This pointer is attached to the "Blog Title" input field.', 'test_lang') . '</p>',
            'button2' => __('Next', 'test_lang'),
            'function' => 'window.location="' . $this->get_admin_url('index.php', 'quick_press_last') . '"'  // We are relocating back to "Dashboard" with 'quick_press_last' query var
            ),
        'quick_press_last' => array (
            'id' => '#dashboard_quick_press',
            'content' => '<h3>' . __('This concludes our WP Pointers tour.', 'test_lang') . '</h3>'
            . '<p><strong>' . __('Last WP Pointer.', 'test_lang') . '</strong></p>'
            . '<p>' . __('When closing the pointer tour; it will be saved in the users custom meta.  The tour will NOT be shown to that user again.', 'test_lang') . '</p>'
            )
        );

    // Determine which tab is set in the query variable
    $tab = isset($_GET['tab']) ? $_GET['tab'] : '';
    // Define other variables
    $function = '';
    $button2 = '';
    $options = array ();
    $show_pointer = false;

    // *******************************************************************************************************
    // This will be the first pointer shown to the user.
    // If no query variable is set in the url.. then the 'tab' cannot be determined... and we start with this pointer.
    // *******************************************************************************************************
    if (!array_key_exists($tab, $tour)) {

        $show_pointer = true;
        $file_error = true;

        $id = '#dashboard_right_now';  // Define ID used on page html element where we want to display pointer
        $content = '<h3>' . sprintf (__('Test WP Pointers %s', 'test_lang'), self::DISPLAY_VERSION) . '</h3>';
        $content .= __('<p>Welcome to Test WP Pointers admin tour!</p>', 'test_lang');
        $content .= __('<p>This pointer is attached to the "At a Glance" dashboard widget.</p>', 'test_lang');
        $content .= '<p>' . __('Click the <em>Begin Tour</em> button to get started.', 'test_lang' ) . '</p>';

        $options = array (
            'content' => $content,
            'position' => array ('edge' => 'top', 'align' => 'left')
            );
        $button2 = __('Begin Tour', 'test_lang' );
        $function = 'document.location="' . $this->get_admin_url('index.php', 'quick_press') . '";';
    }
    // Else if the 'tab' is set in the query variable.. then we can determine which pointer to display
    else {

        if ($tab != '' && in_array ($tab, array_keys ($tour))) {

            $show_pointer = true;

            if (isset ($tour[$tab]['id'])) {
                $id = $tour[$tab]['id'];
            }

            $options = array (
                'content' => $tour[$tab]['content'],
                'position' => array ('edge' => 'top', 'align' => 'left')
            );

            $button2 = false;
            $function = '';

            if (isset ($tour[$tab]['button2'])) {
                $button2 = $tour[$tab]['button2'];
            }
            if (isset ($tour[$tab]['function'])) {
                $function = $tour[$tab]['function'];
            }
        }
    }

    // If we are showing a pointer... let's load the jQuery.
    if ($show_pointer) {
        $this->make_pointer_script ($id, $options, __('Close', 'test_lang'), $button2, $function);
    }
}

Хорошо ... давайте посмотрим на несколько вещей здесь.

Во-первых, наш $tourмассив. Это массив, который содержит все указатели, КРОМЕ первого указателя, который отображается пользователю (подробнее об этом позже). Итак, вы хотите начать со второго указателя, который вы намереваетесь показать ... и продолжить до последнего указателя.

Далее у нас есть несколько пунктов, которые очень важны.

  1. Эти $tourключи массива должны быть уникальными (quick_press, SITE_TITLE, quick_press_last; в качестве примеров выше).
  2. Команда 'id' ДОЛЖНА совпадать с идентификатором элемента html элемента, который вы хотите прикрепить к указателю.
  3. Команда functionперезагрузит / переместит окно. Это то, что используется для отображения следующего указателя. Мы должны либо перезагрузить окно, либо переместить его на следующую страницу администратора, где будет отображаться указатель.
  4. Мы запускаем get_admin_url()функцию с двумя переменными; первая страница администратора, куда мы хотим перейти; а второй - это уникальный ключ массива указателя, который мы хотим отобразить.

Далее вы увидите код, который начинается if (!array_key_exists($tab, $tour)) {. Здесь мы определяем, была ли установлена ​​переменная URL-запроса. Если он НЕ, то нам нужно определить первый указатель для отображения.

Этот указатель использует те же id, content, button2, and functionэлементы, что и в нашем $tourмассиве выше. Помните, что второй аргумент get_admin_url()функции ДОЛЖЕН быть точно таким же, как ключ массива в $tourпеременной. Это то, что говорит сценарию перейти к следующему указателю.

Остальная часть функции используется, если в URL уже установлена ​​переменная запроса. Больше нет необходимости настраивать функцию.

Получение адреса администратора Следующая функция на самом деле является вспомогательной функцией ... используется для получения адреса администратора и перемещения указателя.

// This function is used to reload the admin page.
// -- $page = the admin page we are passing (index.php or options-general.php)
// -- $tab = the NEXT pointer array key we want to display
function get_admin_url($page, $tab) {

    $url = admin_url();
    $url .= $page.'?tab='.$tab;

    return $url;
}

Помните, что есть два аргумента; страницу администратора мы собираемся .. и вкладку. Вкладка будет $tourключом массива, к которому мы хотим перейти далее. ЭТО ДОЛЖНО СООТВЕТСТВОВАТЬ .

Итак, когда мы вызываем функцию get_admin_url()и передаем две переменные; первая переменная определяет следующую страницу администратора .. а вторая переменная определяет, какой указатель отображать.

Наконец ... мы можем наконец напечатать скрипт администратора в нижний колонтитул.

// Print footer scripts
function make_pointer_script ($id, $options, $button1, $button2=false, $function='') {

    ?>
    <script type="text/javascript">

        (function ($) {

            // Define pointer options
            var wp_pointers_tour_opts = <?php echo json_encode ($options); ?>, setup;

            wp_pointers_tour_opts = $.extend (wp_pointers_tour_opts, {

                // Add 'Close' button
                buttons: function (event, t) {

                    button = jQuery ('<a id="pointer-close" class="button-secondary">' + '<?php echo $button1; ?>' + '</a>');
                    button.bind ('click.pointer', function () {
                        t.element.pointer ('close');
                    });
                    return button;
                },
                close: function () {

                    // Post to admin ajax to disable pointers when user clicks "Close"
                    $.post (ajaxurl, {
                        pointer: 'test_wp_pointer',
                        action: 'dismiss-wp-pointer'
                    });
                }
            });

            // This is used for our "button2" value above (advances the pointers)
            setup = function () {

                $('<?php echo $id; ?>').pointer(wp_pointers_tour_opts).pointer('open');

                <?php if ($button2) { ?>

                    jQuery ('#pointer-close').after ('<a id="pointer-primary" class="button-primary">' + '<?php echo $button2; ?>' + '</a>');
                    jQuery ('#pointer-primary').click (function () {
                        <?php echo $function; ?>  // Execute button2 function
                    });
                    jQuery ('#pointer-close').click (function () {

                        // Post to admin ajax to disable pointers when user clicks "Close"
                        $.post (ajaxurl, {
                            pointer: 'test_wp_pointer',
                            action: 'dismiss-wp-pointer'
                        });
                    })
                <?php } ?>
            };

            if (wp_pointers_tour_opts.position && wp_pointers_tour_opts.position.defer_loading) {

                $(window).bind('load.wp-pointers', setup);
            }
            else {
                setup ();
            }
        }) (jQuery);
    </script>
    <?php
}
} 
$testWPpointers = new testWPpointers();

Опять же, нет необходимости что-либо менять выше. Этот скрипт определит и выведет две кнопки в окне наложения указателя. Всегда будет кнопка «Закрыть»; и обновит мета- dismissed_pointersопцию текущего пользователя .

Вторая кнопка (кнопка действия) выполнит функцию (наш метод перемещения окна).

И мы закрываем класс.

Вот код целиком. WP Pointer Class

Вы можете скопировать / вставить это на свой сайт разработчика и посетить страницу «Панель инструментов». Он проведет вас через тур.

Помните, это немного сбивает с толку, что первый указатель определяется последним в коде. Вот как это должно работать. Массив будет содержать все остальные указатели, которые вы хотите использовать.

Помните, что элемент массива 'id' ДОЛЖЕН совпадать со вторым аргументом get_admin_url()функции из предыдущей команды 'function' элемента массива. Именно так указатели «общаются» друг с другом и знают, как продвигаться.

Наслаждаться!! :)


Это мило, Джош, большое спасибо! Я попробую это и посмотрю, насколько хорошо это работает. Я должен подчеркнуть, что код GM - это тот, который я, скорее всего, получу за эту награду, потому что он имеет несколько важных функций, которые я запросил и которые, как я считаю, важны для создания руководства, особенно для нескольких страниц в wp-admin. Тем не менее, замечательно видеть другой подход в этом, и он пригодится другим пользователям, которые ищут хорошее решение. Из любопытства вы сказали, что довольно много смешанных чувств, когда дело доходит до использования указателей , заботы о разработке?
Кристина Купер

2
Не беспокойтесь :) Ну, указатели могут «мешать» при использовании в избытке. Никто не хочет посещать страницу и отображать три или четыре указателя ... особенно, если они не связаны. Скажем, два других плагина показывают указатели, затем мы добавляем больше указателей .. это может стать излишним. Большинство людей говорят, чтобы использовать их экономно ... но для каждого свое :) Рад, что у вас все работает правильно.
Джош

1
Это также замечательно, Джош, я бы сделал 1 предложение, чтобы сделать это более гибким и иметь его, где вы можете просто передать массив в публичную функцию вместо того, чтобы хранить это внутри самого кода класса. Во-вторых, первый указатель, как он разделен, измените его так, чтобы он мог быть первым ключом / значением массива в массиве указателей. Всего пара идей, чтобы этот класс мог быть вызван из другого скрипта и просто передан в массив указателей. Мне все еще очень нравится, спасибо, что поделился, я буду использовать это!
Джейсон Дейвис

Спасибо @jasondavis. Я на самом деле вытащил этот код из другого плагина, который я разработал для кого-то. Я был заинтересован только в том, чтобы заставить его работать должным образом. Но да, я абсолютно согласен с вами ... это нужно почистить. Возможно, я зайду сегодня попозже и еще раз поиграюсь с этим :) Ты молодец, братан!
Джош

Это круто, у меня фактически никогда не было никакого намерения использовать указатели администратора, главным образом потому, что они выглядели как кошмар и второе, потому что я не пользуюсь ими, но ваш класс делает их так легко использовать сейчас, что я чувствую, что использовать их так легко с этим классом! Мне нравятся такие маленькие проекты / библиотеки, хорошие вещи
JasonDavis
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.