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_script
para pasar datos a javascript.
El plan:
- 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
- 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
...
- Escriba una clase que manejará la carga, el análisis y el filtrado de información de punteros
- 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.php
y 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 where
propiedad.
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.
add_action( 'admin_enqueue_scripts', function( $page ) {
simplemente regresar si el usuario no tiene el rol requerido.public function filter( $page ) {
en laPointersManager
clase e inmediatamente después de poner esa líneadie($page);
. Abra su navegador y pegue la URL, la página morirá con una cadena: eso es lo que debe usar como'where'
.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
admin_enqueue_scripts
.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:
De acuerdo ... echemos un vistazo a algunas cosas aquí.
Primero, nuestra
$tour
matriz. 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.
$tour
claves de la matriz deben ser únicas (quick_press, site_title, quick_press_last; como en los ejemplos anteriores).function
comando 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.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 function
elementos que los utilizados en nuestra$tour
matriz anterior. Recuerde, el segundo argumento de laget_admin_url()
función DEBE ser exactamente igual que la clave de matriz en la$tour
variable. 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.
Recuerde, hay dos argumentos; la página de administración que vamos a ... y la pestaña. La pestaña será la
$tour
clave 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.
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_pointers
opció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!! :)
fuente