Erstellen Sie ein WP-Tutorial für Benutzer mit Admin-Zeiger, indem Sie die nächste Schaltfläche für die Navigation verwenden


9

Ich möchte ein Tutorial für meine Benutzer für den Admin-Bereich erstellen. Um dies zu erreichen, verwende ich die im WP Core verfügbaren Admin-Zeiger. Mein Ziel:

Geben Sie hier die Bildbeschreibung ein

Ich bin fast da. Was ich bisher bekommen habe ...

Wp-Zeiger-Skripte in die Warteschlange stellen:

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

Hilfsfunktionen, einschließlich bedingter Prüfung und Fußzeilenskript:

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
}

Jetzt können wir das Array von Zeigern zusammenstellen:

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

}

Der Code ist selbsterklärend. Wir können leicht weitere Zeiger hinzufügen, indem wir das Array erweitern. In WP4 funktioniert alles einwandfrei.

Nun zum Problem: Alle Popup-Zeiger werden gleichzeitig angezeigt, was dies zu einer schlechten Oberfläche für ein Tutorial macht.

Mein Ziel ist es, die Zeiger einzeln anzuzeigen und dem Benutzer zu ermöglichen, auf die Schaltfläche Weiter zu klicken , um durch das Lernprogramm zu navigieren. Die nächste Schaltfläche sollte den nächsten Zeiger öffnen und den letzten schließen.

Wie kann ich das machen?

Antworten:


10

Sie rufen die .pointer( 'open' );Javascript-Funktion für alle Zeigerobjekte auf, daher ist es nicht verwunderlich, dass alle Zeiger gleichzeitig angezeigt werden ...

Ich verstehe jedoch nicht, warum Sie alle Zeiger (auch nicht aktive) von zurückgeben custom_admin_pointers()und dann eine zusätzliche Funktion hinzufügen, um zu überprüfen, ob einige aktive Zeiger vorhanden sind, und eine Überprüfung innerhalb der Zeigerschleife ( if ( $array['active'] ) {), um den Javascript-Zeiger hinzuzufügen oder nicht. Ist es nicht einfacher, nur aktive Zeiger zurückzugeben?

Darüber hinaus fügen Sie das Javascript auf allen Admin-Seiten hinzu, ist nicht zu viel? Bedenken Sie auch, dass einige Elemente wie "# save-post" nur auf einer neuen Post-Seite verfügbar sind. Ist es also nicht besser, die Zeiger nur auf einer neuen Pot-Seite hinzuzufügen?

Schließlich, wie chaotisch dieses mit PHP vermischte Javascript ist, sollten Sie in Betracht ziehen, wp_localize_scriptDaten an Javascript zu übergeben.

Der Plan:

  1. Verschieben Sie die Zeigerdefinitionen in PHP in eine separate Datei. Auf diese Weise ist es einfach, Markups aus dem PHP-Code zu bearbeiten und zu entfernen. Alles führt zu einer besseren Lesbarkeit und Wartung
  2. Fügen Sie in der Zeigerkonfiguration eine Eigenschaft "where" hinzu, mit der festgelegt wird, auf welcher Administrationsseite ein Popup angezeigt werden soll : post-new.php, index.php...
  3. Schreiben Sie eine Klasse, die das Laden, Parsen und Filtern von Zeigerinformationen übernimmt
  4. Schreiben Sie einige js Güte, die uns helfen, die Standardschaltfläche "Entfernen" in "Weiter" zu ändern.

Die # 4 kann (wahrscheinlich) leicht das Zeiger-Plugin gut kennen, aber es ist nicht mein Fall. Also werde ich allgemeinen jQuery-Code verwenden, um das Ergebnis zu erhalten. Wenn jemand meinen Code verbessern kann, werde ich es zu schätzen wissen.


Bearbeiten

Ich habe den Code (hauptsächlich js) bearbeitet, weil ich verschiedene Dinge nicht berücksichtigt habe: Einige Zeiger können demselben Anker hinzugefügt werden, oder dieselben Zeiger können nicht vorhandenen oder nicht sichtbaren Ankern hinzugefügt werden. In all dem Fall, in dem der vorherige Code nicht funktioniert hat, scheint die neue Version diese Probleme gut zu lösen.

Ich habe auch einen Gist mit dem gesamten Code eingerichtet, den ich zum Testen verwendet habe.


Beginnen wir mit den Punkten 1 und 2 : Erstellen Sie eine Datei mit dem Namen pointers.phpund schreiben Sie dort:

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

Die Konfiguration aller Zeiger finden Sie hier. Wenn Sie etwas ändern müssen, öffnen Sie einfach diese Datei und bearbeiten Sie sie.

Beachten Sie die Eigenschaft "where", bei der es sich um ein Array von Seiten handelt, auf denen der Zeiger verfügbar sein soll.

Wenn Sie Zeiger auf einer von einem Plugin generierten Seite anzeigen möchten, suchen Sie nach dieser unten beschriebenen Zeile public function filter( $page ) {und fügen Sie sie die($page);unmittelbar darunter hinzu. Öffnen Sie dann die entsprechende Plugin-Seite und verwenden Sie diese Zeichenfolge in der whereEigenschaft.

Ok, jetzt der Punkt # 3 .

Bevor ich die Klasse schreibe, möchte ich nur eine Schnittstelle codieren: Dort werde ich Kommentare einfügen, damit Sie besser verstehen, was die Klasse tun wird.

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

}

Ich denke sollte ziemlich klar sein. Schreiben wir nun die Klasse, sie enthält die 2 Methoden von interface plus den Konstruktor.

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

Code ist sehr einfach und macht genau das, was die Schnittstelle erwartet.

Die Klasse macht jedoch nichts für sich. Wir benötigen einen Hook, um die Klasse zu instanziieren und die beiden Methoden zu starten, die die richtigen Argumente übergeben.

Das 'admin_enqueue_scripts'ist perfekt für unseren Bereich: Dort haben wir Zugriff auf die aktuelle Administrationsseite und können die benötigten Skripte und Stile in die Warteschlange stellen.

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

Nichts Besonderes: Verwenden Sie einfach die Klasse, um Zeigerdaten abzurufen, und wenn einige Zeiger die Filter übergeben, werden Stile und Skripte in die Warteschlange gestellt. Übergeben Sie dann Zeigerdaten an das Skript zusammen mit der lokalisierten Bezeichnung "Weiter" für die Schaltfläche.

Ok, jetzt der "schwierigste" Teil: der js. Ich möchte noch einmal hervorheben, dass ich das Zeiger-Plugin, das WordPress verwendet, nicht kenne. Was ich also in meinem Code mache, kann besser gemacht werden, wenn jemand es weiß, aber mein Code macht seine Arbeit und - im Allgemeinen - ist es nicht so schlecht.

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

Mit Hilfe von Kommentaren sollte der Code zumindest ziemlich klar sein, ich hoffe es.

Ok wir sind fertig. Unser PHP ist einfacher und besser organisiert, unser Javascript besser lesbar, Zeiger sind einfacher zu bearbeiten und, was noch wichtiger ist, alles funktioniert.


1
@ChristineCooper sicher. Ok, Probleme sind 2: 1 für die Funktionsweise des Skripts. Sie können 1 Zeiger für 1 Anker-ID hinzufügen. Wenn Sie denselben Anker für mehr als einen Zeiger verwenden, schlägt das Skript fehl. Das zweite Problem ist, dass einige Zeiger Anker für IDs verwenden, die sich möglicherweise nicht auf der Seite befinden. Ein Zeiger steht beispielsweise für '# comment-55' in index.php und wird nicht gefunden. Einige Zeiger in post.php zielen auf Metaboxen ab, die möglicherweise ausgeblendet sind ... und so weiter. Sobald in der aktuellen Version des Skripts Zeiger "verkettet" sind, wenn einer nicht gefunden wird, funktionieren auch alle Teilsequenzen nicht. Ich werde sehen, ob es einen einfachen Weg gibt, diese Probleme zu überwinden.
gmazzap

1
@ChristineCooper Ich bin froh, dass es funktioniert hat. Ich werde den gesamten Code von Gist hierher zurück kopieren. Die Bedingung kann unmittelbar nach der add_action( 'admin_enqueue_scripts', function( $page ) {einfachen Rückgabe gestellt werden, wenn der Benutzer keine erforderliche Rolle hat.
gmazzap

Bitte ändern Sie den Wert 30 online in 120: "scrollTop: $ pointer.offset (). Top - 30" - Der Grund dafür ist, dass die obere Symbolleiste beim Scrollen gelegentlich das Zeigerfenster abdeckt.
Christine Cooper

Ich habe ein kleines Problem. Die Seite, auf der einige Zeiger angezeigt werden sollen, lautet: "admin.php? Page = plugin-path / file.php" - was genau füge ich dem where- Array hinzu? Ich habe "admin.php", "plugin-path / file.php", "file.php" und jede erdenkliche Variation ausprobiert. Gibt es einen Grund, warum diese Seite nicht erkannt werden kann oder mache ich das falsch?
Christine Cooper

1
@ChristineCooper öffne die Plugin-Administrationsseite und kopiere die URL aus dem Browser . Öffnen Sie danach die Datei, die meinen obigen Code enthält. Suchen Sie die Zeile public function filter( $page ) {in der PointersManagerKlasse und setzen Sie sie unmittelbar nach dieser Zeile ein die($page);. Öffnen Sie Ihren Browser und fügen Sie die URL wieder ein. Die Seite stirbt mit einer Zeichenfolge: Das ist das, als was Sie verwenden müssen 'where'.
gmazzap

7

Ahhh .. ja. WordPress-Zeiger. Weißt du, es gibt ziemlich viele gemischte Gefühle, wenn es darum geht, Zeiger zu verwenden;)

Sie waren mit Ihrem obigen Code auf dem richtigen Weg. Es gibt jedoch einige Probleme.

@ GM ist richtig über die pointer('open') Befehl alle Zeiger gleichzeitig öffnet. Darüber hinaus stellen Sie keine Methode zum Durchlaufen von Zeigern bereit.

Ich habe das gleiche Problem bekämpft und mir meinen eigenen Ansatz ausgedacht. Ich verwende eine Abfragevariable in der URL, lade die Seite neu auf die Administrationsseite, auf der ich den nächsten Zeiger anzeigen möchte, und lasse jQuery den Rest erledigen.

WP Zeiger Klasse

Ich beschloss, dies als Klasse zu schreiben. Aber ich werde es zunächst schrittweise zeigen, damit Sie besser verstehen, was passiert.

Beginn des Unterrichts

// 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. Wir haben die Klasse definiert.
  2. Wir haben die Klasse erstellt und eine Aktion hinzugefügt admin_enqueue_scripts.
  3. Wir haben festgestellt, ob unsere Zeiger bereits verworfen wurden.
  4. Wenn nicht, stellen wir die erforderlichen Skripte weiterhin in die Warteschlange.

In diesen ersten Funktionen müssen Sie nichts ändern.

Einrichten des Arrays von Zeigerelementen

Der nächste Schritt besteht darin, jeden der Zeiger zu definieren. Es gibt fünf Elemente, die wir definieren müssen (außer für den letzten Zeiger). Wir werden dies mit Arrays tun. Werfen wir einen Blick auf die Funktion:

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

Okay ... schauen wir uns hier ein paar Dinge an.

Erstens unser $tourArray. Dies ist das Array, das alle Zeiger enthält, AUSSER den ersten Zeiger, der dem Benutzer angezeigt wird (dazu später mehr). Beginnen Sie also mit dem zweiten Zeiger, den Sie anzeigen möchten, und fahren Sie mit dem letzten Zeiger fort.

Als nächstes haben wir einige Punkte, die sehr wichtig sind.

  1. Die $tourArray-Schlüssel müssen eindeutig sein (quick_press, site_title, quick_press_last; wie oben beschrieben).
  2. Der Befehl 'id' MUSS mit der HTML-Element-ID des Elements übereinstimmen, das Sie an den Zeiger anhängen möchten.
  3. Das function Befehl lädt / verschiebt das Fenster neu. Dies wird verwendet, um den nächsten Zeiger anzuzeigen. Wir müssen entweder das Fenster neu laden oder es auf die nächste Administrationsseite verschieben, auf der ein Zeiger angezeigt wird.
  4. Wir führen die get_admin_url()Funktion mit zwei Variablen aus; Die erste ist die Administrationsseite, auf die wir als nächstes gehen möchten. und der zweite ist der eindeutige Array-Schlüssel des Zeigers, den wir anzeigen möchten.

Weiter unten sehen Sie den Code, der beginnt if (!array_key_exists($tab, $tour)) {. Hier bestimmen wir, ob eine URL-Abfragevariable festgelegt wurde. Wenn dies NICHT der Fall ist, müssen wir den ersten anzuzeigenden Zeiger definieren.

Dieser Zeiger verwendet genau die gleichen id, content, button2, and functionElemente wie in unserem $tourobigen Array. Denken Sie daran, dass das zweite Argument der get_admin_url()Funktion genau mit dem Array-Schlüssel in übereinstimmen muss$tour Variablen entsprechen muss. Dies weist das Skript an, zum nächsten Zeiger zu wechseln.

Der Rest der Funktion wird verwendet, wenn in der URL bereits eine Abfragevariable festgelegt ist. Die Funktion muss nicht mehr angepasst werden.

Admin URL bekommen die nächste Funktion ist eigentlich eine Hilfsfunktion , ... verwendet , um die Admin - URL zu erhalten und den Zeiger vorzurücken.

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

Denken Sie daran, es gibt zwei Argumente; die Admin-Seite, die wir besuchen werden .. und die Registerkarte. Die Registerkarte ist der $tourArray-Schlüssel, zu dem wir als Nächstes wechseln möchten. DAS MUSS PASSEN .

Also, wenn wir die Funktion aufrufen get_admin_url() und die beiden Variablen übergeben; Die erste Variable bestimmt die nächste Administrationsseite. Die zweite Variable bestimmt, welcher Zeiger angezeigt werden soll.

Zuletzt ... können wir endlich das Admin-Skript in die Fußzeile drucken.

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

Auch hier besteht keine Notwendigkeit, etwas oben zu ändern. Dieses Skript definiert und gibt die beiden Schaltflächen im Zeiger-Overlay-Fenster aus. Einer wird immer der "Schließen" -Button sein; und aktualisiert die aktuelle Benutzer-Meta- dismissed_pointersOption.

Die zweite Schaltfläche (die Aktionstaste) führt die Funktion aus (unsere Fensterverschiebungsmethode).

Und wir schließen die Klasse.

Hier ist der Code in seiner Gesamtheit. WP Zeigerklasse

Sie können das kopieren / in Ihre Entwickler-Site einfügen und die Seite "Dashboard" besuchen. Es wird Sie durch die Tour führen.

Denken Sie daran, es ist etwas verwirrend, dass der erste Zeiger zuletzt im Code definiert ist. So soll es funktionieren. Das Array enthält alle übrigen Zeiger, die Sie verwenden möchten.

Denken Sie daran, dass das Array-Element 'id' mit dem zweiten Argument der get_admin_url()Funktion aus dem vorherigen Befehl 'function' des Array-Elements übereinstimmen muss . Auf diese Weise „sprechen“ die Zeiger miteinander und wissen, wie sie vorankommen.

Genießen!! :) :)


Das ist schön, Josh, vielen Dank! Ich werde das ausprobieren und sehen, wie gut es funktioniert. Ich möchte hervorheben, dass der Code von GM derjenige ist, den ich wahrscheinlich vergeben werde, da er einige wesentliche Funktionen enthält, die ich angefordert habe und die meiner Meinung nach wichtig sind, um einen Leitfaden zu erstellen, insbesondere für mehrere Seiten in wp-admin. Trotzdem ist es großartig, einen anderen Ansatz zu sehen, der sich für andere Benutzer als nützlich erweisen wird, die nach einer guten Lösung suchen. Aus Neugier sagten Sie, dass es ziemlich viele gemischte Gefühle gibt, wenn es darum geht, Zeiger zu verwenden.
Christine Cooper

2
Keine Sorge :) Nun, Zeiger können im Weg stehen, wenn sie übermäßig verwendet werden. Niemand möchte eine Seite besuchen und drei oder vier Zeiger anzeigen lassen ... besonders wenn sie nichts miteinander zu tun haben. Angenommen, zwei andere Plugins zeigen Zeiger an, dann fügen wir weitere Zeiger hinzu. Dies kann zu einem Overkill werden. Die meisten Leute sagen, sie sparsam zu benutzen ... aber jeder hat seine eigene :) Ich bin froh, dass du es richtig zum Laufen gebracht hast.
Josh

1
Das ist auch großartig, Josh. Ich würde einen Vorschlag machen, um dies flexibler zu gestalten und es dort zu haben, wo Sie das Array einfach an eine öffentliche Funktion übergeben können, anstatt es im Klassencode selbst zu speichern. Zweitens ändert der erste Zeiger, wie er getrennt ist, ihn so, dass er der erste Array-Schlüssel / Wert im Zeiger-Array sein kann. Nur ein paar Ideen, damit diese Klasse aus einem anderen Skript aufgerufen und einfach im Zeigerarray übergeben werden kann. Ich mag es immer noch sehr, danke fürs Teilen, ich werde es benutzen!
JasonDavis

Danke @jasondavis. Ich habe diesen Code tatsächlich aus einem anderen Plugin gezogen, das ich für jemanden entwickelt habe. Ich war nur daran interessiert, dass es richtig funktioniert. Aber ja, ich stimme dir absolut zu ... es muss gereinigt werden. Vielleicht schaue ich heute später vorbei und lege mich wieder damit an :) Du rockst, Bruder!
Josh

Es ist cool, ich hatte eigentlich nie die Absicht, die Admin-Zeiger zu verwenden, hauptsächlich, weil sie wie ein Albtraum aussahen, und zweitens, weil ich sie nicht wirklich brauche, aber deine Klasse lässt sie jetzt so einfach aussehen, dass ich mich fühle Ich muss sie benutzen, damit es mit dieser Klasse so einfach ist! Ich liebe
solche
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.