Crea tutorial WP per utenti con puntatore amministratore utilizzando il pulsante successivo per la navigazione


9

Mi propongo di creare un tutorial sui miei utenti per l'area di amministrazione. Per raggiungere questo obiettivo, sto usando i puntatori di amministrazione disponibili in WP core. Il mio obiettivo:

inserisci qui la descrizione dell'immagine

Sono quasi li. Quello che ho ottenuto finora ...

Accoda gli script wp-pointer:

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

Funzioni di supporto, tra cui controllo condizionale e script piè di pagina:

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
}

Ora siamo pronti a mettere insieme l'array di puntatori:

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

}

Il codice si spiega da sé. Possiamo facilmente aggiungere più puntatori estendendo l'array. Tutto funziona bene in WP4.

Ora al problema: tutti i puntatori popup vengono visualizzati contemporaneamente, rendendola una cattiva interfaccia per un tutorial.

Il mio obiettivo è mostrare i puntatori uno per uno e consentire all'utente di fare clic su un pulsante Avanti per navigare attraverso il tutorial. Il pulsante successivo dovrebbe aprire il puntatore successivo e chiudere l'ultimo.

Come posso fare questo?

Risposte:


10

Stai chiamando la .pointer( 'open' );funzione javascript su tutti gli oggetti puntatori, quindi non è una sorpresa che tutti i puntatori vengano visualizzati contemporaneamente ...

Detto questo, non capisco perché restituisci tutti i puntatori (anche quelli non attivi) da custom_admin_pointers()e quindi aggiungi una funzione aggiuntiva per verificare se ci sono alcuni puntatori attivi e un controllo all'interno del ciclo di puntatori ( if ( $array['active'] ) {) per scegliere di aggiungere il puntatore javascript o no. Non è più semplice restituire solo i puntatori attivi?

Inoltre, stai aggiungendo che javascript su tutte le pagine di amministrazione, non è troppo? Considera anche che alcuni elementi come "# save-post" sono disponibili solo nella nuova pagina dei post, quindi non è meglio aggiungere i puntatori solo nella nuova pagina del piatto?

Infine, quanto è disordinato quel javascript confuso con PHP, penso che dovresti considerare di usare wp_localize_scriptper passare i dati a javascript.

Il piano:

  1. Sposta le definizioni dei puntatori in PHP in un file separato, in questo modo è facile modificarlo e anche rimuovere il markup dal codice PHP, tutto risulta più leggibile e manutenibile
  2. Nei puntatori configurazione aggiungere una proprietà "dove" che verrà utilizzato per impostare in cui pagina di amministrazione dovrebbe comparire un popup: post-new.php, index.php...
  3. Scrivi una classe che gestirà il caricamento, l'analisi e il filtraggio delle informazioni sui puntatori
  4. Scrivi qualche bontà js che ci aiuterà a cambiare il pulsante "Rimuovi" predefinito in "Avanti"

Il # 4 può (probabilmente) facilmente conoscere bene il plugin del puntatore, ma non è il mio caso. Quindi userò il codice jQuery generale per ottenere il risultato, se qualcuno può migliorare il mio codice lo apprezzerò.


modificare

Ho modificato il codice (principalmente js) perché ci sono diverse cose che non avevo preso in considerazione: alcuni puntatori possono essere aggiunti alla stessa ancora, oppure è possibile aggiungere gli stessi puntatori a ancore inesistenti o non visibili. In tutti questi casi, il codice precedente non funzionava, la nuova versione sembra risolvere bene questi problemi.

Ho anche installato un Gist con tutto il codice che ho usato per testare.


Cominciamo con i punti n. 1 e n. 2 : creare un file denominato pointers.phpe scrivere lì:

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

La configurazione di tutti i puntatori è qui. Quando devi cambiare qualcosa, basta aprire questo file e modificarlo.

Nota la proprietà "where" che è una matrice di pagine in cui dovrebbe essere disponibile il puntatore.

Se si desidera visualizzare i puntatori in una pagina generata da un plug-in, cercare questa riga descritta di seguito public function filter( $page ) {e aggiungere die($page);immediatamente al di sotto di essa. Quindi apri la rispettiva pagina del plugin e usa quella stringa nella whereproprietà.

Ok, ora il punto 3 .

Prima di scrivere la lezione voglio solo codificare un'interfaccia: lì inserirò dei commenti in modo che tu possa capire meglio quale classe farà.

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

}

Penso che dovrebbe essere abbastanza chiaro. Ora scriviamo la classe, conterrà i 2 metodi dall'interfaccia più il costruttore.

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

Il codice è molto semplice e fa esattamente ciò che l'interfaccia si aspetta.

Tuttavia, la classe non fa nulla da sola, abbiamo bisogno di un hook dove istanziare la classe e lanciare i 2 metodi passando argomenti appropriati.

Il 'admin_enqueue_scripts'è perfetto per il nostro campo: non avremo accesso alla pagina di amministrazione corrente e possiamo anche gli script di accodamento e stili necessario.

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

Niente di speciale: basta usare la classe per ottenere i dati dei puntatori e se alcuni puntatori passano i filtri accodano stili e script. Quindi passare i dati dei puntatori allo script insieme all'etichetta "Avanti" localizzata per il pulsante.

Ok, ora la parte "più difficile": la js. Ancora una volta voglio evidenziare che non conosco il plug-in del puntatore utilizzato da WordPress, quindi ciò che faccio nel mio codice può essere fatto meglio se qualcuno lo conosce, tuttavia il mio codice fa il suo lavoro e, parlando in termini generali, non è poi così male.

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

Con l'aiuto dei commenti il ​​codice dovrebbe essere abbastanza chiaro, almeno, lo spero.

Ok abbiamo finito. Il nostro PHP è più semplice e meglio organizzato, il nostro javascript è più leggibile, i puntatori sono più facili da modificare e, cosa più importante, tutto funziona.


1
@ChristineCooper certo. Ok, i problemi sono 2: 1 ° per come funziona ora lo script, puoi aggiungere 1 puntatore per 1 id di ancoraggio: l'uso dello stesso ancoraggio per più di un puntatore causerà il fallimento dello script. Il secondo problema è che alcuni puntatori usano l'ancoraggio agli ID che potrebbero non essere presenti nella pagina. Ad esempio un puntatore è per '# comment-55' in index.php e non viene trovato. Alcuni puntatori nei metabox di post.php mirano a essere nascosti ... e così via. Una volta nella versione corrente dei puntatori dello script vengono "concatenati" se non viene trovato, anche tutti i sottotitoli non funzioneranno. Vedrò se esiste un modo semplice per superare questi problemi.
gmazzap

1
@ChristineCooper Sono contento che abbia funzionato. Copierò tutto il codice da Gist qui. La condizione può essere inserita subito dopo il add_action( 'admin_enqueue_scripts', function( $page ) {semplice ritorno se l'utente non ha alcun ruolo richiesto.
gmazzap

Modifica il valore 30 in 120 on line: "scrollTop: $ pointer.offset (). Top - 30" - Il motivo è che la barra degli strumenti superiore copre occasionalmente la finestra del puntatore durante lo scorrimento.
Christine Cooper

Ho un problema minore. La pagina di cui ho bisogno per visualizzare alcuni puntatori è: "admin.php? Page = plugin-path / file.php" - cosa aggiungo esattamente all'array where ? Ho provato "admin.php", "plugin-path / file.php", "file.php" e qualsiasi variazione mi venisse in mente. C'è un motivo per cui non riesce a rilevare questa pagina o sto sbagliando?
Christine Cooper

1
@ChristineCooper apre la pagina di amministrazione del plug-in e copia l'URL dal browser . Successivamente, apri il file che contiene il mio codice sopra. Trova la linea public function filter( $page ) {in PointersManagerclasse e subito dopo la linea metti die($page);. Apri il tuo browser e incolla l'URL, la pagina morirà con una stringa: questo è quello che devi usare come 'where'.
gmazzap

7

Ahhh .. si. Puntatori di WordPress. Sai, ci sono molti sentimenti contrastanti quando si tratta di usare i puntatori;)

Eri sulla strada giusta con il tuo codice sopra. Ma ci sono un paio di problemi.

@GM ha ragione sul pointer('open')comando che apre tutti i puntatori contemporaneamente. Inoltre, non stai fornendo un metodo per avanzare attraverso i puntatori.

Ho combattuto questo stesso problema ... e ho avuto il mio approccio. Uso una variabile di query nell'URL, ricarico la pagina nella pagina di amministrazione in cui desidero visualizzare il puntatore successivo e lascio che jQuery gestisca il resto.

Classe di puntatori WP

Ho deciso di scrivere questo come classe. Ma inizialmente lo mostrerò con incrementi per aiutarti a capire meglio cosa sta succedendo.

Inizio della lezione

// 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. Abbiamo definito la classe.
  2. Abbiamo costruito la classe e aggiunto un'azione a admin_enqueue_scripts.
  3. Abbiamo stabilito se i nostri puntatori sono già stati ignorati.
  4. In caso contrario, continuiamo ad accodare gli script necessari.

NON è necessario modificare nulla in queste prime funzioni.

Impostazione della matrice di elementi puntatore

Il passaggio successivo consiste nella definizione di ciascuno dei puntatori. Ci sono cinque elementi che dobbiamo definire (escluso l'ultimo puntatore). Lo faremo usando array. Diamo un'occhiata alla funzione:

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

Ok .. diamo un'occhiata ad alcune cose qui.

Innanzitutto, il nostro $tourarray. Questo è l'array che contiene tutti i puntatori TRANNE il primo puntatore che viene visualizzato all'utente (ne parleremo più avanti). Quindi, ti consigliamo di iniziare con il secondo puntatore che intendi mostrare .. e continuare fino all'ultimo puntatore.

Successivamente, abbiamo alcuni articoli che sono molto importanti.

  1. Le $tourchiavi dell'array devono essere univoche (quick_press, site_title, quick_press_last; come esempi sopra).
  2. Il comando 'id' DEVE corrispondere all'ID dell'elemento html dell'elemento che si desidera collegare al puntatore.
  3. Il functioncomando ricaricherà / riposizionerà la finestra. Questo è ciò che viene utilizzato per mostrare il puntatore successivo. Dobbiamo ricaricare la finestra o spostarla nella pagina di amministrazione successiva in cui verrà visualizzato un puntatore.
  4. Eseguiamo la get_admin_url()funzione con due variabili; la prima è la pagina di amministrazione in cui vogliamo andare dopo; e la seconda è la chiave di matrice univoca del puntatore che desideriamo visualizzare.

Più in basso, vedrai il codice che inizia if (!array_key_exists($tab, $tour)) {. Qui è dove determiniamo se è stata impostata una variabile di query url. In caso contrario, è necessario definire il primo puntatore da visualizzare.

Questo puntatore usa gli stessi identici id, content, button2, and functionelementi usati nel nostro $tourarray sopra. Ricorda, il secondo argomento della get_admin_url()funzione DEVE essere esattamente lo stesso della chiave dell'array nella $tourvariabile. Questo è ciò che dice allo script di passare al puntatore successivo.

Il resto della funzione viene utilizzato se nell'URL è già impostata una variabile di query. Non è necessario regolare più la funzione.

Ottenere l'URL dell'amministratore La funzione successiva è in realtà una funzione di supporto ... utilizzata per ottenere l' URL dell'amministratore e far avanzare il puntatore.

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

Ricorda, ci sono due argomenti; la pagina di amministrazione che andremo a ... e la scheda. La scheda sarà la $tourchiave dell'array che vogliamo passare al prossimo. QUESTI DEVONO CORRISPONDERE .

Quindi, quando chiamiamo la funzione get_admin_url()e passiamo le due variabili; la prima variabile determina la pagina di amministrazione successiva .. e la seconda variabile determina quale puntatore visualizzare.

Infine ... possiamo finalmente stampare lo script admin sul piè di pagina.

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

Ancora una volta, non è necessario modificare nulla sopra. Questo script definirà e genererà i due pulsanti nella finestra di sovrapposizione del puntatore. Uno sarà sempre il pulsante "Chiudi"; e aggiornerà la meta dismissed_pointersopzione dell'utente corrente .

Il secondo pulsante (il pulsante di azione) eseguirà la funzione (il nostro metodo di riposizionamento della finestra).

E chiudiamo la lezione.

Ecco il codice nella sua interezza. Classe di puntatore WP

Puoi copiarlo / incollarlo nel tuo sito di sviluppo e visitare la pagina "Dashboard". Ti guiderà attraverso il tour.

Ricorda, è un po 'confuso che il primo puntatore sia definito per ultimo nel codice. Questo è il modo in cui dovrebbe funzionare. L'array conterrà tutti gli altri puntatori che si desidera utilizzare.

Ricordare che l'elemento dell'array "id" DEVE corrispondere al secondo argomento della get_admin_url()funzione dal comando "funzione" dell'elemento dell'array precedente. Questo è il modo in cui i puntatori "parlano" l'un l'altro e sanno come avanzare.

Godere!! :)


Questo è adorabile Josh, grazie mille! Lo proverò e vedrò come funziona. Dovrei sottolineare che il codice di GM è quello che probabilmente assegnerò questo premio perché ha alcune caratteristiche essenziali che ho richiesto e che ritengo sia importante creare una guida, in particolare per più pagine in wp-admin. Tuttavia, è bello vedere un altro approccio a questo e sarà utile per gli altri utenti che sono alla ricerca di una buona soluzione. Per curiosità, hai detto che ci sono un sacco di sentimenti contrastanti quando si tratta di usare i puntatori , ti interessa elaborare?
Christine Cooper

2
Nessun problema :) Bene, i puntatori possono "mettersi in mezzo" se usati in eccesso. Nessuno vuole visitare una pagina e visualizzare tre o quattro puntatori ... specialmente se non sono correlati. Supponiamo che altri due plugin mostrino puntatori, quindi aggiungiamo altri puntatori .. può diventare eccessivo. La maggior parte delle persone dice di usarli con parsimonia ... ma a ciascuno è il proprio :) Sono contento che tu l'abbia fatto funzionare correttamente.
josh,

1
Questo è anche fantastico Josh, vorrei dare 1 suggerimento, per renderlo più flessibile e averlo dove puoi semplicemente passare l'array in una funzione pubblica invece di archiviarlo all'interno del codice di classe stesso. In secondo luogo, il primo puntatore, come è separato, lo modifica in modo che possa essere la prima chiave / valore della matrice nella matrice del puntatore. Solo un paio di idee in modo che questa classe possa essere chiamata da un altro script e semplicemente passata nella matrice del puntatore. Mi piace ancora davvero, grazie per la condivisione lo userò!
JasonDavis,

Grazie @jasondavis. In realtà ho estratto quel codice da un altro plugin che ho sviluppato per qualcuno. Ero solo interessato a farlo funzionare correttamente. Ma sì, sono assolutamente d'accordo con te ... deve essere pulito. Forse mi fermerò più tardi oggi e lo incasinerò di nuovo :) Tu rock, fratello!
josh,

È bello, in realtà non ho mai avuto intenzione di usare i puntatori di amministrazione, principalmente perché sembravano un incubo e 2 ° perché non li uso davvero, ma la tua classe li rende così facili da usare ora che sento che devo usarli perché è così facile con quella classe! Adoro piccoli progetti / biblioteche del genere, roba buona
JasonDavis,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.