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_script
Daten an Javascript zu übergeben.
Der Plan:
- 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
- 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
...
- Schreiben Sie eine Klasse, die das Laden, Parsen und Filtern von Zeigerinformationen übernimmt
- 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.php
und 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 where
Eigenschaft.
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.
add_action( 'admin_enqueue_scripts', function( $page ) {
einfachen Rückgabe gestellt werden, wenn der Benutzer keine erforderliche Rolle hat.public function filter( $page ) {
in derPointersManager
Klasse und setzen Sie sie unmittelbar nach dieser Zeile eindie($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'
.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
admin_enqueue_scripts
.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:
Okay ... schauen wir uns hier ein paar Dinge an.
Erstens unser
$tour
Array. 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.
$tour
Array-Schlüssel müssen eindeutig sein (quick_press, site_title, quick_press_last; wie oben beschrieben).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.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 function
Elemente wie in unserem$tour
obigen Array. Denken Sie daran, dass das zweite Argument derget_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.
Denken Sie daran, es gibt zwei Argumente; die Admin-Seite, die wir besuchen werden .. und die Registerkarte. Die Registerkarte ist der
$tour
Array-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.
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_pointers
Option.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!! :) :)
quelle