Vous appelez la .pointer( 'open' );
fonction javascript sur tous les objets pointeurs, il n'est donc pas surprenant que tous les pointeurs apparaissent en même temps ...
Cela dit, je ne comprends pas pourquoi renvoyez tous les pointeurs (même non actifs) custom_admin_pointers()
, puis ajoutez une fonction supplémentaire pour vérifier s'il existe des pointeurs actifs et une vérification à l'intérieur de la boucle de pointeurs ( if ( $array['active'] ) {
) pour choisir d'ajouter un pointeur javascript ou pas. N'est-ce pas plus simple de ne renvoyer que des pointeurs actifs?
De plus, vous ajoutez ce javascript sur toutes les pages d'administration, ce n'est pas trop? Considérez également que certains éléments comme "# save-post" ne sont disponibles que sur la nouvelle page de publication, il n'est donc pas préférable d'ajouter les pointeurs uniquement dans la nouvelle page de pot?
Enfin, à quel point ce javascript est mélangé avec PHP, je pense que vous devriez envisager d'utiliser wp_localize_script
pour transmettre des données à javascript.
Le plan:
- Déplacez les définitions de pointeurs en PHP dans un fichier séparé, de cette façon, il est facile de modifier et également de supprimer le balisage du code PHP, tout est plus lisible et maintenable
- Dans les pointeurs de configuration ajouter une propriété « où » qui sera utilisé pour définir dans quelle page admin une fenêtre devrait apparaître:
post-new.php
, index.php
...
- Écrire une classe qui gérera le chargement, l'analyse et le filtrage des pointeurs info
- Écrivez quelques bonnes choses qui nous aideront à changer le bouton "Supprimer" par défaut en "Suivant"
Le # 4 peut (probablement) se faire facilement en connaissant bien le plugin pointeur, mais ce n'est pas mon cas. Je vais donc utiliser le code général jQuery pour obtenir le résultat, si quelqu'un peut améliorer mon code, j'apprécierai.
Éditer
J'ai édité le code (principalement js) car il y avait différentes choses que je n'avais pas considérées: certains pointeurs peuvent être ajoutés à la même ancre, ou les mêmes pointeurs peuvent être ajoutés à des ancres inexistantes ou non visibles. Dans tous les cas, le code précédent ne fonctionnait pas, la nouvelle version semble bien résoudre ce problème.
J'ai également configuré un Gist avec tout le code que j'ai utilisé pour tester.
Commençons par les points # 1 et # 2 : créez un fichier nommé pointers.php
et écrivez-y:
<?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 configuration de tous les pointeurs est ici. Lorsque vous devez modifier quelque chose, ouvrez simplement ce fichier et modifiez-le.
Notez la propriété "where" qui est un tableau de pages où le pointeur doit être disponible.
Si vous souhaitez afficher des pointeurs dans une page générée par un plugin, recherchez cette ligne décrite ci public function filter( $page ) {
- dessous et ajoutez-la die($page);
immédiatement en dessous. Ouvrez ensuite la page de plug-in correspondante et utilisez cette chaîne dans la where
propriété.
Ok, maintenant le point # 3 .
Avant d'écrire la classe, je veux juste coder une interface: j'y mettrai des commentaires pour que vous puissiez mieux comprendre ce que fera la classe.
<?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 );
}
Je pense que cela devrait être assez clair. Écrivons maintenant la classe, elle contiendra les 2 méthodes de l'interface plus le constructeur.
<?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;
}
}
Le code est très simple et fait exactement ce que l'interface attend.
Cependant, la classe ne fait rien par elle-même, nous avons besoin d'un crochet où instancier la classe et lancer les 2 méthodes en passant les arguments appropriés.
Le 'admin_enqueue_scripts'
est parfait pour notre portée: là, nous aurons accès à la page d'administration actuelle et nous pouvons également mettre en file d'attente les scripts et les styles nécessaires.
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 );
} );
Rien de spécial: il suffit d'utiliser la classe pour obtenir des données de pointeurs et si certains pointeurs passent les filtres, mettre en file d'attente les styles et les scripts. Ensuite, transmettez les données des pointeurs au script jusqu'à l'étiquette "Suivant" localisée pour le bouton.
Ok, maintenant la partie "la plus difficile": les js. Encore une fois, je tiens à souligner que je ne connais pas le plugin de pointeur utilisé par WordPress, donc ce que je fais dans mon code peut être mieux fait si quelqu'un le sait, mais mon code fait son travail et, en général, ce n'est pas si mal.
( 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`
Avec l'aide des commentaires, le code devrait être assez clair, du moins, je l'espère.
Ok, nous avons terminé. Notre PHP est plus simple et mieux organisé, notre javascript est plus lisible, les pointeurs sont plus faciles à éditer et, plus important encore, tout fonctionne.
add_action( 'admin_enqueue_scripts', function( $page ) {
simple retour si l'utilisateur n'a pas de rôle requis.public function filter( $page ) {
enPointersManager
classe, et immédiatement après cette ligne, mettezdie($page);
. Ouvrez votre navigateur et collez l'URL, la page mourra avec une chaîne: c'est ce que vous devez utiliser'where'
.Ahhh .. oui. Pointeurs WordPress. Vous savez, il y a beaucoup de sentiments mitigés quand il s'agit d'utiliser des pointeurs;)
Vous étiez sur la bonne voie avec votre code ci-dessus. Mais il y a quelques problèmes.
@GM a raison sur la
pointer('open')
commande ouvrant tous vos pointeurs à la fois. En outre, vous ne fournissez pas de méthode pour avancer dans les pointeurs.J'ai combattu ce même problème .. et j'ai trouvé ma propre approche. J'utilise une variable de requête dans l'URL, recharge la page sur la page d'administration où je veux afficher le pointeur suivant et laisse jQuery gérer le reste.
Classe WP Pointers
J'ai décidé d'écrire ceci en classe. Mais je vais d'abord le montrer par incréments pour vous aider à mieux comprendre ce qui se passe.
Début de la classe
admin_enqueue_scripts
.Vous n'avez PAS besoin de changer quoi que ce soit dans ces premières fonctions.
Configuration du tableau d'éléments de pointeur
L'étape suivante consiste à définir chacun des pointeurs. Il y a cinq éléments que nous devons définir (extrait pour le dernier pointeur). Nous le ferons en utilisant des tableaux. Jetons un coup d'œil à la fonction:
D'accord .. jetons un oeil à quelques choses ici.
Tout d'abord, notre
$tour
tableau. Il s'agit du tableau qui contient tous les pointeurs SAUF le premier pointeur qui est affiché pour l'utilisateur (plus d'informations à ce sujet plus tard). Donc, vous voudrez commencer par le deuxième pointeur que vous avez l'intention d'afficher .. et continuer jusqu'au dernier pointeur.Ensuite, nous avons quelques éléments qui sont très importants.
$tour
clés du tableau doivent être uniques (quick_press, site_title, quick_press_last; comme exemples ci-dessus).function
commande rechargera / relocalisera la fenêtre. C'est ce qui est utilisé pour afficher le pointeur suivant. Nous devons soit recharger la fenêtre, soit la déplacer vers la page d'administration suivante où un pointeur sera affiché.get_admin_url()
fonction avec deux variables; la première est la page d'administration où nous voulons aller ensuite; et le second est la clé de tableau unique du pointeur que nous souhaitons afficher.Plus bas, vous verrez le code qui commence
if (!array_key_exists($tab, $tour)) {
. C'est là que nous déterminons si une variable de requête URL a été définie. Si ce n'est PAS le cas, nous devons définir le premier pointeur à afficher.Ce pointeur utilise exactement les mêmes
id, content, button2, and function
éléments que ceux utilisés dans notre$tour
tableau ci-dessus. N'oubliez pas que le deuxième argument de laget_admin_url()
fonction DOIT être exactement le même que la clé du tableau dans la$tour
variable. C'est ce qui indique au script d'aller au pointeur suivant.Le reste de la fonction est utilisé si une variable de requête est déjà définie dans l'url. Il n'est plus nécessaire de régler la fonction.
Obtention de l'URL d'administration La fonction suivante est en fait une fonction d'aide ... utilisée pour obtenir l'URL d'administration et faire avancer le pointeur.
N'oubliez pas qu'il y a deux arguments; la page d'administration, nous allons .. et l'onglet. L'onglet sera la
$tour
clé du tableau dans laquelle nous voulons aller ensuite. CEUX-CI DOIVENT CORRESPONDRE .Ainsi, lorsque nous appelons la fonction
get_admin_url()
et passons les deux variables; la première variable détermine la page d'administration suivante .. et la deuxième variable détermine le pointeur à afficher.Enfin ... nous pouvons enfin imprimer le script admin dans le pied de page.
Encore une fois, il n'est pas nécessaire de modifier quoi que ce soit ci-dessus. Ce script définira et affichera les deux boutons dans la fenêtre de superposition du pointeur. L'un sera toujours le bouton "Fermer"; et mettra à jour la méta-
dismissed_pointers
option utilisateur actuelle .Le deuxième bouton (le bouton d'action) exécutera la fonction (notre méthode de relocalisation de fenêtre).
Et nous fermons la classe.
Voici le code dans son intégralité. Classe WP Pointer
Vous pouvez copier / coller cela dans votre site de développement et visiter la page "Tableau de bord". Il vous guidera tout au long de la visite.
Rappelez-vous, c'est un peu déroutant que le premier pointeur soit défini en dernier dans le code. C'est ainsi que cela est censé fonctionner. Le tableau contiendra tous les autres pointeurs que vous souhaitez utiliser.
N'oubliez pas que l'élément de tableau «id» DOIT correspondre au deuxième argument de la
get_admin_url()
fonction de la commande précédente de «fonction» de l'élément de tableau. C'est ainsi que les pointeurs se «parlent» les uns aux autres et savent comment avancer.Prendre plaisir!! :)
la source