Utwórz samouczek WP dla użytkowników ze wskaźnikiem administratora, używając następnego przycisku do nawigacji

9

Chcę utworzyć samouczek dla moich użytkowników dla obszaru administracyjnego. Aby to osiągnąć, używam wskaźników administracyjnych dostępnych w WP core. Mój cel:

wprowadź opis zdjęcia tutaj

Jestem prawie na miejscu. Co do tej pory mam ...

Kolejkuj skrypty wskaźnika 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' );
    }
}

Funkcje pomocnicze, w tym kontrola warunkowa i skrypt stopki:

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
}

Teraz jesteśmy gotowi zebrać zestaw wskaźników:

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 ) )
        )
    );

}

Kod jest zrozumiały. Możemy łatwo dodać więcej wskaźników, rozszerzając tablicę. Wszystko działa dobrze w WP4.

Teraz problem: wszystkie wskaźniki wyskakujące pojawiają się w tym samym czasie, co czyni z tego kiepski interfejs do samouczka.

Moim celem jest pokazanie wskaźników jeden po drugim i umożliwienie użytkownikowi kliknięcia przycisku Dalej , aby poruszać się po samouczku. Następny przycisk powinien otworzyć następny wskaźnik i zamknąć ostatni.

W jaki sposób mogę to zrobić?

Christine Cooper
źródło

Odpowiedzi:

10

Dzwonisz .pointer( 'open' );funkcji JavaScript na wszystkich obiektów wskazówek, więc nie jest zaskoczeniem, że wszystkie wskaźniki wyświetlane w tym samym czasie ...

To powiedziawszy, nie rozumiem, dlaczego zwracasz wszystkie wskaźniki (nawet nieaktywne), custom_admin_pointers()a następnie dodajesz dodatkową funkcję, aby sprawdzić, czy są jakieś aktywne wskaźniki i sprawdź wewnątrz pętli wskaźników ( if ( $array['active'] ) {), aby wybrać dodanie wskaźnika javascript albo nie. Czy nie jest prostsze tylko zwracanie tylko aktywnych wskaźników?

Co więcej, dodajesz, że javascript na wszystkich stronach administracyjnych, nie jest za dużo? Weź również pod uwagę, że niektóre elementy, takie jak „# save-post” są dostępne tylko na nowej stronie postu, więc czy nie lepiej dodawać wskaźniki tylko na nowej stronie puli?

Wreszcie, jak niechlujny jest ten javascript pomieszany z PHP, myślę, że powinieneś rozważyć przesłanie wp_localize_scriptdanych do javascript.

Plan:

  1. Przenieś definicje wskaźników w PHP do osobnego pliku, w ten sposób można łatwo edytować, a także usuwać znaczniki z kodu PHP, dzięki czemu wszystko jest bardziej czytelne i łatwe do utrzymania
  2. W wskaźników konfiguracyjnych dodać obiekt „gdzie”, który będzie używany do zestawu, w którym administrator strony powinien pojawić się okienko: post-new.php, index.php...
  3. Napisz klasę, która zajmie się ładowaniem, analizowaniem i filtrowaniem informacji o wskaźnikach
  4. Napisz js dobroć, która pomoże nam zmienić domyślny przycisk „Usuń” na „Dalej”

# 4 puszki (prawdopodobnie) łatwo zrobić znając wskaźnik wtyczki dobrze, ale to nie moja sprawa. Więc użyję ogólnego kodu jQuery, aby uzyskać wynik, jeśli ktoś może ulepszyć mój kod, docenię.


Edytować

Edytowałem kod (głównie js), ponieważ istnieją różne rzeczy, których nie wziąłem pod uwagę: niektóre wskaźniki można dodać do tej samej kotwicy lub takie same wskaźniki można dodać do nieistniejących lub niewidocznych kotwic. We wszystkich tych przypadkach poprzedni kod nie działał, wydaje się, że nowa wersja ładnie rozwiązuje te problemy.

Skonfigurowałem także Gist z całym kodem, którego użyłem do testowania.


Zacznijmy od punktów 1 i 2 : utwórz plik o nazwie pointers.phpi napisz tam:

<?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; 

Konfiguracja wszystkich wskaźników jest tutaj. Gdy musisz coś zmienić, po prostu otwórz ten plik i edytuj go.

Zwróć uwagę na właściwość „where”, która jest tablicą stron, na których wskaźnik powinien być dostępny.

Jeśli chcesz wyświetlić wskaźniki na stronie generowanej przez wtyczkę, poszukaj tej linii opisanej poniżej public function filter( $page ) {i dodaj die($page);bezpośrednio pod nią. Następnie otwórz odpowiednią stronę wtyczki i użyj tego ciągu we wherewłaściwości.

Ok, teraz punkt # 3 .

Przed napisaniem zajęć chcę po prostu napisać interfejs: tam dodam komentarze, abyście mogli lepiej zrozumieć, co zrobi klasa.

<?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 );

}

Myślę, że powinno być całkiem jasne. Teraz napiszmy klasę, która będzie zawierać 2 metody z interfejsu oraz konstruktora.

<?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;
  }
}

Kod jest bardzo prosty i robi dokładnie to, czego oczekuje interfejs.

Jednak klasa sama z siebie nic nie robi, potrzebujemy haka, w którym należy utworzyć instancję klasy i uruchomić 2 metody, przekazując odpowiednie argumenty.

'admin_enqueue_scripts'Jest idealny dla naszego zakresu: nie będziemy mieli dostępu do bieżącej strony administratora i możemy również enqueue skrypty i style potrzebne.

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 );
} );

Nic specjalnego: użycie klasy do pobrania danych wskaźników i jeśli niektóre wskaźniki przejdą przez filtry, zamieniają style i skrypty. Następnie przekaż dane wskaźników do skryptu wraz ze zlokalizowaną etykietą „Dalej” dla przycisku.

Ok, teraz „najtrudniejsza” część: js. Ponownie chcę podkreślić, że nie znam wtyczki wskaźnika, której używa WordPress, więc to, co robię w kodzie, można zrobić lepiej, jeśli ktoś to wie, jednak mój kod działa i - mówiąc ogólnie - nie jest tak źle.

( 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`

Przy pomocy komentarzy kod powinien być dość wyraźny, przynajmniej mam taką nadzieję.

Ok, skończyliśmy. Nasz PHP jest prostszy i lepiej zorganizowany, nasz javascript jest bardziej czytelny, wskaźniki są łatwiejsze do edycji i, co ważniejsze, wszystko działa.

gmazzap
źródło
1
@ChristineCooper na pewno. Ok, problemy są 2: 1. dla tego, jak teraz działa skrypt, możesz dodać 1 wskaźnik dla 1 identyfikatora kotwicy: użycie tej samej kotwicy dla więcej niż jednego wskaźnika spowoduje błąd skryptu. Drugi problem polega na tym, że niektóre wskaźniki używają kotwicy do identyfikatorów, które mogą nie znajdować się na stronie. Np. Jeden wskaźnik oznacza „# comment-55” w index.php i nie został znaleziony. Niektóre wskaźniki w post.php atakują metaboksy, które mogą być ukryte ... i tak dalej. Raz w obecnej wersji skryptu wskaźniki są „powiązane”, jeśli nie zostanie znalezione, wszystkie podsekwencje również nie będą działać. Zobaczę, czy istnieje prosty sposób na rozwiązanie tych problemów.
gmazzap
1
@ChristineCooper Cieszę się, że to działało. Skopiuję cały kod z Gist z powrotem tutaj. Warunek można ustawić tuż po add_action( 'admin_enqueue_scripts', function( $page ) {zwykłym powrocie, jeśli użytkownik nie ma wymaganej roli.
gmazzap
Zmień wartość 30 na 120 w wierszu: „scrollTop: $ pointer.offset (). Top - 30” - Powodem jest to, że górny pasek narzędzi czasami zakrywa okno wskaźnika podczas przewijania.
Christine Cooper
Mam jeden drobny problem. Strona, do której wyświetlenia potrzebuję wskaźników, to: „admin.php? Page = plugin-path / file.php” - co dokładnie mam dodać do tablicy where ? Próbowałem „admin.php”, „plugin-path / file.php”, „file.php” i dowolnej odmiany, o której mogłem pomyśleć. Czy istnieje powód, dla którego nie może wykryć tej strony lub robię to źle?
Christine Cooper
1
@ChristineCooper otwórz stronę administratora wtyczki i skopiuj adres URL z przeglądarki . Następnie otwórz plik zawierający mój kod powyżej. Znajdź linię public function filter( $page ) {w PointersManagerklasie i natychmiast po jej umieszczeniu die($page);. Otwórz przeglądarkę i wklej adres URL, strona umrze z ciągiem: właśnie tego musisz użyć 'where'.
gmazzap
7

Ahhh .. tak. Wskaźniki WordPress. Wiesz, istnieje wiele mieszanych uczuć, jeśli chodzi o używanie wskaźników;)

Twój kod był na dobrej drodze. Ale jest kilka problemów.

@GM ma rację co do pointer('open')polecenia otwierającego wszystkie wskaźniki na raz. Ponadto nie zapewniasz metody przechodzenia przez wskaźniki.

Walczyłem z tym samym problemem ... i wpadłem na własne podejście. Używam zmiennej zapytania w adresie URL, ponownie ładuję stronę do strony administratora, na której chcę wyświetlić następny wskaźnik, i pozwalam jQuery zająć się resztą.

Klasa wskaźników WP

Postanowiłem napisać to jako lekcję. Ale najpierw pokażę to stopniowo, aby lepiej zrozumieć, co się dzieje.

Rozpoczęcie zajęć

// 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. Zdefiniowaliśmy klasę.
  2. Zbudowaliśmy klasę i dodaliśmy akcję do admin_enqueue_scripts.
  3. Ustaliliśmy, czy nasze wskaźniki zostały już odrzucone.
  4. Jeśli nie, kontynuujemy kolejkowanie niezbędnych skryptów.

NIE musisz nic zmieniać w tych pierwszych funkcjach.

Konfigurowanie tablicy pozycji wskaźnika

Następnym krokiem jest zdefiniowanie każdego ze wskaźników. Jest pięć elementów, które musimy zdefiniować (z wyjątkiem ostatniego wskaźnika). Zrobimy to za pomocą tablic. Rzućmy okiem na funkcję:

// 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);
    }
}

Okej. Rzućmy okiem na kilka rzeczy tutaj.

Po pierwsze, nasza $tourtablica. Jest to tablica zawierająca wszystkie wskaźniki Z WYJĄTKIEM pierwszego wskaźnika wyświetlanego użytkownikowi (więcej na ten temat później). Więc zacznij od drugiego wskaźnika, który zamierzasz pokazać ... i przejdź do ostatniego wskaźnika.

Następnie mamy kilka bardzo ważnych przedmiotów.

  1. W $tourkluczami musi być niepowtarzalny (quick_press, SITE_TITLE, quick_press_last; jako przykłady powyżej).
  2. Polecenie „id” MUSI być zgodne z identyfikatorem elementu HTML elementu, który chcesz dołączyć do wskaźnika.
  3. functionPolecenie reload / przenieść okno. To jest używane do wyświetlenia następnego wskaźnika. Musimy albo ponownie załadować okno, albo przenieść je na następną stronę administratora, na której wyświetli się wskaźnik.
  4. Uruchamiamy get_admin_url()funkcję z dwiema zmiennymi; pierwsza to strona administratora, do której chcemy przejść dalej; a drugi to unikalny klucz tablicy wskaźnika, który chcemy wyświetlić.

W dalszej części zobaczysz kod, który się zaczyna if (!array_key_exists($tab, $tour)) {. Tutaj określamy, czy ustawiono zmienną zapytania adresu URL. Jeśli NIE, to musimy zdefiniować pierwszy wskaźnik do wyświetlenia.

Ten wskaźnik używa dokładnie tych samych id, content, button2, and functionelementów, które zostały użyte w $tourpowyższej tablicy. Pamiętaj, że drugi argument get_admin_url()funkcji MUSI być dokładnie taki sam jak klucz tablicy w $tourzmiennej. To mówi skryptowi, aby przejść do następnego wskaźnika.

Reszta funkcji jest używana, jeśli zmienna zapytania jest już ustawiona w adresie URL. Nie trzeba już dostosowywać tej funkcji.

Pobieranie adresu URL następnej funkcji Następna funkcja jest w rzeczywistości funkcją pomocnika ... używaną do uzyskania adresu URL administratora i przesunięcia wskaźnika.

// 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;
}

Pamiętaj, że istnieją dwa argumenty; stronę administratora, do której jedziemy .. i zakładkę. Zakładka będzie $tourkluczem tablicy, do którego chcemy przejść dalej. TE MUSZĄ DOPASOWAĆ .

Kiedy wywołujemy funkcję get_admin_url()i przekazujemy dwie zmienne; pierwsza zmienna określa następną stronę administratora .. a druga zmienna określa wskaźnik do wyświetlenia.

Wreszcie ... możemy wreszcie wydrukować skrypt administratora w stopce.

// 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();

Ponownie nie ma potrzeby zmieniać niczego powyżej. Ten skrypt zdefiniuje i wyświetli dwa przyciski w oknie nakładki wskaźnika. Zawsze będzie przycisk „Zamknij”; i zaktualizuje bieżącą dismissed_pointersopcję meta użytkownika .

Drugi przycisk (przycisk akcji) wykona funkcję (nasza metoda relokacji okna).

I zamykamy klasę.

Oto kod w całości. Klasa wskaźnika WP

Możesz skopiować / wkleić to na swojej stronie deweloperskiej i odwiedzić stronę „Dashboard”. Poprowadzi Cię przez wycieczkę.

Pamiętaj, że trochę mylące jest to, że pierwszy wskaźnik jest zdefiniowany jako ostatni w kodzie. Tak ma to działać. Tablica pomieści wszystkie pozostałe wskaźniki, których chcesz użyć.

Pamiętaj, że element tablicy „id” MUSI pasować do drugiego argumentu get_admin_url()funkcji z polecenia „funkcja” poprzedniego elementu tablicy. W ten sposób wskaźniki „rozmawiają” ze sobą i wiedzą, jak się rozwijać.

Cieszyć się!! :)

josh
źródło
To jest kochany Josh, dziękuję bardzo! Wypróbuję to i zobaczę, jak dobrze to działa. Powinienem podkreślić, że kod GM jest tym, który prawdopodobnie nagrodzę tę nagrodę, ponieważ ma kilka istotnych funkcji, o które prosiłem i które uważam za ważne, aby stworzyć przewodnik, szczególnie dla wielu stron w wp-admin. Niemniej jednak wspaniale jest zobaczyć inne podejście i przyda się innym użytkownikom, którzy szukają dobrego rozwiązania. Z ciekawości powiedziałeś, że istnieje wiele mieszanych uczuć, jeśli chodzi o używanie wskaźników , chcesz rozwinąć?
Christine Cooper
2
Bez obaw :) Cóż, wskaźniki mogą „przeszkadzać”, gdy są używane w nadmiarze. Nikt nie chce odwiedzać strony i wyświetlać trzy lub cztery wskaźniki ... zwłaszcza jeśli nie są ze sobą powiązane. Powiedzmy, że dwie inne wtyczki pokazują wskaźniki, a następnie dodajemy więcej wskaźników .. może to stać się nadmierne. Większość ludzi mówi, aby używać ich oszczędnie ... ale dla każdego jest ona własna :) Cieszę się, że działa poprawnie.
josh
1
To także niesamowite Josh, proponuję 1 sugestię, aby uczynić to bardziej elastycznym i mieć to, gdzie można po prostu przekazać tablicę do funkcji publicznej zamiast przechowywać ją w samym kodzie klasy. Po drugie, pierwszy wskaźnik, jak jest oddzielny, zmodyfikuj go, aby mógł być pierwszym kluczem / wartością tablicy w tablicy wskaźników. Tylko kilka pomysłów, aby tę klasę można było wywołać z innego skryptu i po prostu przekazać do tablicy wskaźnika. Nadal bardzo to lubię, dziękuję za udostępnienie. Będę tego używać!
JasonDavis
Dzięki @jasondavis. Wyciągnąłem ten kod z innej wtyczki, którą opracowałem dla kogoś. Byłem zainteresowany tylko tym, aby działał poprawnie. Ale tak, absolutnie się z tobą zgadzam ... trzeba to wyczyścić. Być może przyjadę dzisiaj później i znów z tym popsuję :) Ty rock, bracie!
josh
To fajne, tak naprawdę nigdy nie miałem zamiaru używać wskaźników administracyjnych, głównie dlatego, że wyglądały jak koszmar i drugie, ponieważ nie mam dla nich prawdziwego zastosowania, ale twoja klasa sprawia, że ​​wyglądają na tak łatwe w użyciu teraz, kiedy czuję, że muszę ich używać, ponieważ jest to takie proste dzięki tej klasie! Uwielbiam takie małe projekty / biblioteki, dobre rzeczy
JasonDavis