Cree un tutorial de WP para usuarios con puntero de administrador usando el botón Siguiente para la navegación

9

Mi objetivo es crear un tutorial sobre mis usuarios para el área de administración. Para lograr esto, estoy usando los punteros de administrador disponibles en WP core. Mi meta:

ingrese la descripción de la imagen aquí

Ya casi estoy allí. Lo que llegué hasta ahora ...

Poner en cola los scripts 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' );
    }
}

Funciones de ayuda, incluida la verificación condicional y el script de pie de página:

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
}

Ahora estamos listos para armar la matriz de punteros:

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

}

El código se explica por sí mismo. Podemos agregar fácilmente más punteros extendiendo la matriz. Todo funciona bien en WP4.

Ahora al problema: todos los punteros emergentes aparecen al mismo tiempo, lo que hace que esta sea una interfaz deficiente para un tutorial.

Mi objetivo es mostrar los punteros uno por uno y permitir que el usuario haga clic en el botón Siguiente para navegar por el tutorial. El siguiente botón debe abrir el siguiente puntero y cerrar el último.

¿Cómo puedo hacer esto?

Christine Cooper
fuente

Respuestas:

10

Está llamando a la .pointer( 'open' );función javascript en todos los objetos de punteros, por lo que no es sorprendente que todos los punteros aparezcan al mismo tiempo ...

Dicho esto, no entiendo por qué devuelve todos los punteros (incluso los no activos) custom_admin_pointers()y luego agrega una función adicional para verificar si hay algunos punteros activos y una marca dentro del bucle de punteros ( if ( $array['active'] ) {) para elegir agregar un puntero javascript o no. ¿No es más simple devolver solo punteros activos?

Además, está agregando que javascript en todas las páginas de administración, ¿no es demasiado? También considere que algunos elementos como "# save-post" están disponibles solo en la nueva página de publicación, por lo que no es mejor agregar los punteros solo en la nueva página de bote.

Finalmente, cuán desordenado es ese javascript mezclado con PHP, creo que debería considerar usarlo wp_localize_scriptpara pasar datos a javascript.

El plan:

  1. Mueva las definiciones de punteros en PHP a un archivo separado, de esta manera es fácil de editar y también elimina el marcado del código PHP, todo resulta más legible y sostenible
  2. En los punteros de configuración añadir una propiedad "donde" que se utiliza para establecer en la que la página de administración debería aparecer una ventana emergente: post-new.php, index.php...
  3. Escriba una clase que manejará la carga, el análisis y el filtrado de información de punteros
  4. Escriba algunas bondades de js que nos ayudarán a cambiar el botón predeterminado "Eliminar" a "Siguiente"

El # 4 puede (probablemente) hacerse fácilmente conociendo bien el complemento de puntero, pero no es mi caso. Así que usaré el código general de jQuery para obtener el resultado, si alguien puede mejorar mi código, lo agradeceré.


Editar

Edité el código (principalmente js) porque hay cosas diferentes que no había considerado: algunos punteros pueden agregarse al mismo anclaje, o los mismos punteros pueden agregarse a anclajes no existentes o no visibles. En todo ese caso, el código anterior no funcionó, la nueva versión parece abordar muy bien esos problemas.

También configuré un Gist con todo el código que solía probar.


Comencemos con los puntos 1 y 2 : cree un archivo llamado pointers.phpy escriba allí:

<?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 configuración de todos los punteros está aquí. Cuando necesite cambiar algo, simplemente abra este archivo y edítelo.

Tenga en cuenta la propiedad "donde" que es una matriz de páginas donde el puntero debería estar disponible.

Si desea mostrar punteros en una página generada por un complemento, busque esta línea que se describe a continuación public function filter( $page ) {y agregue die($page);inmediatamente debajo de ella. Luego abra la página del complemento respectivo y use esa cadena en la wherepropiedad.

Ok, ahora el punto # 3 .

Antes de escribir la clase, solo quiero codificar una interfaz: allí pondré comentarios para que pueda comprender mejor qué hará la clase.

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

}

Creo que debería estar bastante claro. Ahora escribamos la clase, contendrá los 2 métodos de la interfaz más el constructor.

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

El código es muy simple y hace exactamente lo que la interfaz espera.

Sin embargo, la clase no hace nada por sí misma, necesitamos un gancho donde instanciar la clase y lanzar los 2 métodos pasando los argumentos adecuados.

El 'admin_enqueue_scripts'es perfecto para nuestro alcance: allí tendremos acceso a la página de administración actual y también podemos poner en cola los scripts y los estilos necesarios.

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

Nada especial: solo usar la clase para obtener datos de punteros y si algunos punteros pasan los filtros, ponen en cola estilos y scripts. Luego, pase los datos de los punteros al script a la etiqueta "Siguiente" localizada para el botón.

Ok, ahora la parte "más difícil": el js. Una vez más, quiero resaltar que no conozco el plugin de puntero que usa WordPress, por lo que lo que hago en mi código se puede hacer mejor si alguien lo sabe, sin embargo, mi código hace su trabajo y, en términos generales, no es tan malo.

( 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 la ayuda de los comentarios, el código debería ser bastante claro, al menos, eso espero.

Ok ya hemos terminado. Nuestro PHP es más simple y está mejor organizado, nuestro javascript es más legible, los punteros son más fáciles de editar y, lo que es más importante, todo funciona.

gmazzap
fuente
1
@ChristineCooper seguro. Ok, los problemas son 2: primero para el funcionamiento del script ahora, puede agregar 1 puntero para 1 identificación de ancla: usar el mismo ancla para más de un puntero hará que el script falle. El segundo problema es que algunos punteros usan el ancla para los identificadores que pueden no estar en la página. Por ejemplo, un puntero es para '# comment-55' en index.php, y no se encuentra. Algunos punteros en meta.cajas de destino post.php que pueden estar ocultos ... y así sucesivamente. Una vez en la versión actual de la secuencia de comandos, los punteros se "encadenan" si no se encuentra uno, todos los subsecuentes no funcionarán también. Veré si hay una manera simple de superar esos problemas.
gmazzap
1
@ChristineCooper Me alegro de que haya funcionado. Copiaré todo el código de Gist aquí. La condición se puede poner justo después de add_action( 'admin_enqueue_scripts', function( $page ) {simplemente regresar si el usuario no tiene el rol requerido.
gmazzap
Cambie el valor 30 a 120 en línea: "scrollTop: $ pointer.offset (). Top - 30" - La razón es porque la barra de herramientas superior cubre la ventana del puntero ocasionalmente cuando se desplaza.
Christine Cooper
Tengo un problema menor La página que necesito para que aparezcan algunos indicadores es: "admin.php? Page = plugin-path / file.php": ¿qué agrego exactamente a la matriz where ? Intenté "admin.php", "plugin-path / file.php", "file.php" y cualquier variación que se me ocurriera. ¿Hay alguna razón por la que no puede detectar esta página o estoy haciendo esto mal?
Christine Cooper
1
@ChristineCooper abre la página de administración del complemento y copia la url del navegador . Después de eso, abra el archivo que contiene mi código anterior. Encuentra la línea public function filter( $page ) {en la PointersManagerclase e inmediatamente después de poner esa línea die($page);. Abra su navegador y pegue la URL, la página morirá con una cadena: eso es lo que debe usar como 'where'.
gmazzap
7

Ahhh .. si. Punteros de WordPress. Ya sabes, hay bastantes sentimientos encontrados cuando se trata de usar punteros;)

Estabas en el camino correcto con tu código de arriba. Pero hay un par de problemas.

@GM tiene razón acerca del pointer('open')comando que abre todos sus punteros a la vez. Además, no está proporcionando un método para avanzar a través de punteros.

Luché contra este mismo problema ... y se me ocurrió mi propio enfoque. Utilizo una variable de consulta en la url, vuelvo a cargar la página en la página de administración donde quiero mostrar el siguiente puntero y dejo que jQuery se encargue del resto.

Clase de punteros WP

Decidí escribir esto como una clase. Pero al principio lo mostraré en incrementos para ayudarlo a comprender mejor lo que está sucediendo.

Comenzando la clase

// 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. Hemos definido la clase.
  2. Construimos la clase y agregamos una acción a admin_enqueue_scripts.
  3. Determinamos si nuestros punteros ya han sido despedidos.
  4. Si no, continuamos poniendo en cola los scripts necesarios.

NO necesita cambiar nada en estas primeras funciones.

Configurar la matriz de elementos de puntero

El siguiente paso es definir cada uno de los punteros. Hay cinco elementos que debemos definir (excepto el último puntero). Haremos esto usando matrices. Echemos un vistazo a la función:

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

De acuerdo ... echemos un vistazo a algunas cosas aquí.

Primero, nuestra $tourmatriz. Esta es la matriz que contiene todos los punteros, EXCEPTO el primer puntero que se muestra al usuario (más sobre esto más adelante). Por lo tanto, querrá comenzar con el segundo puntero que desea mostrar ... y continuar hasta el último puntero.

A continuación, tenemos algunos artículos que son muy importantes.

  1. Las $tourclaves de la matriz deben ser únicas (quick_press, site_title, quick_press_last; como en los ejemplos anteriores).
  2. El comando 'id' DEBE coincidir con el id del elemento html del elemento que desea adjuntar al puntero.
  3. El functioncomando recargará / reubicará la ventana. Esto es lo que se usa para mostrar el siguiente puntero. Tenemos que volver a cargar la ventana o reubicarla en la siguiente página de administración donde se mostrará un puntero.
  4. Ejecutamos la get_admin_url()función con dos variables; la primera es la página de administración donde queremos ir a continuación; y la segunda es la clave de matriz única del puntero que deseamos mostrar.

Más abajo, verá el código que comienza if (!array_key_exists($tab, $tour)) {. Aquí es donde determinamos si se ha establecido una variable de consulta de URL. Si NO tiene, entonces necesitamos definir el primer puntero para mostrar.

Este puntero usa exactamente los mismos id, content, button2, and functionelementos que los utilizados en nuestra $tourmatriz anterior. Recuerde, el segundo argumento de la get_admin_url()función DEBE ser exactamente igual que la clave de matriz en la $tourvariable. Esto es lo que le dice al script que vaya al siguiente puntero.

El resto de la función se usa si una variable de consulta ya está establecida en la url. No hay necesidad de ajustar más la función.

Obteniendo la URL del administrador La siguiente función es en realidad una función auxiliar ... utilizada para obtener la URL del administrador y avanzar el puntero.

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

Recuerde, hay dos argumentos; la página de administración que vamos a ... y la pestaña. La pestaña será la $tourclave de matriz a la que queremos ir a continuación. Estos deben coincidir .

Entonces, cuando llamamos a la función get_admin_url()y pasamos las dos variables; la primera variable determina la siguiente página de administración ... y la segunda variable determina qué puntero mostrar.

Por último ... finalmente podemos imprimir el script de administración al pie de página.

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

Nuevamente, no hay necesidad de cambiar nada de lo anterior. Este script definirá y mostrará los dos botones en la ventana de superposición de puntero. Uno siempre será el botón "Cerrar"; y actualizará la meta dismissed_pointersopción de usuario actual .

El segundo botón (el botón de acción) ejecutará la función (nuestro método de reubicación de ventanas).

Y cerramos la clase.

Aquí está el código en su totalidad. Clase de puntero WP

Puede copiar / pegar eso en su sitio de desarrollo y visitar la página "Panel de control". Te guiará a través del recorrido.

Recuerde, es un poco confuso que el primer puntero se defina en último lugar en el código. Esa es la forma en que se supone que funciona. La matriz contendrá el resto de los punteros que desea usar.

Recuerde, el elemento de matriz 'id' DEBE coincidir con el segundo argumento de la get_admin_url()función del comando anterior 'función' del elemento de matriz. Así es como los punteros 'hablan' entre sí y saben cómo avanzar.

¡¡Disfrutar!! :)

josh
fuente
Este es el encantador Josh, muchas gracias! Probaré esto y veré qué tan bien funciona. Debo resaltar que el código de GM es el que probablemente otorgaré esta recompensa porque tiene algunas características esenciales que solicité y que creo que es importante para crear una guía, particularmente para múltiples páginas en wp-admin. Sin embargo, es genial ver otro enfoque en esto y será útil para otros usuarios que buscan una buena solución. Por curiosidad, dijiste que hay muchos sentimientos encontrados cuando se trata de usar punteros , ¿te gustaría elaborar?
Christine Cooper
2
No se preocupe :) Bueno, los punteros pueden 'interferir' cuando se usan en exceso. Nadie quiere visitar una página y mostrar tres o cuatro punteros ... especialmente si no están relacionados. Digamos que otros dos complementos muestran punteros, luego agregamos más punteros ... puede volverse excesivo. La mayoría de la gente dice que los use con moderación ... pero cada uno es suyo :) Me alegro de que haya funcionado correctamente.
josh
1
Esto también es asombroso Josh, haría una sugerencia, para hacer esto más flexible y tenerlo donde simplemente pueda pasar la matriz a una función pública en lugar de almacenarla dentro del código de la clase. Segundo, el primer puntero, cómo está separado, modifíquelo para que pueda ser la primera clave / valor de la matriz en la matriz del puntero. Solo un par de ideas para poder llamar a esta clase desde otro script y simplemente pasarla en la matriz del puntero. Todavía me gusta mucho, gracias por compartir, ¡voy a usar esto!
JasonDavis
Gracias @jasondavis. De hecho, saqué ese código de otro complemento que desarrollé para alguien. Solo estaba interesado en que funcionara correctamente. Pero sí, estoy absolutamente de acuerdo contigo ... necesita ser limpiado. Tal vez pase por aquí más tarde hoy y me meta con eso otra vez :) ¡Eres genial, hermano!
josh
Es genial, en realidad nunca tuve la intención de usar los punteros de administrador, principalmente porque parecían una pesadilla y segundo porque no los uso realmente, pero tu clase hace que se vean tan fáciles de usar ahora que siento que ¡tengo que usarlos ya que es tan fácil con esa clase! Me encantan los pequeños proyectos / bibliotecas como esa, cosas buenas
JasonDavis