Anda memanggil .pointer( 'open' );
fungsi javascript pada semua objek pointer, jadi tidak mengherankan bahwa semua pointer muncul pada waktu yang sama ...
Yang mengatakan, saya tidak mengerti mengapa Anda mengembalikan semua pointer (bahkan yang tidak aktif) dari custom_admin_pointers()
dan kemudian menambahkan fungsi tambahan untuk memeriksa apakah ada beberapa pointer aktif dan cek di dalam pointer pointer ( if ( $array['active'] ) {
) untuk memilih untuk menambahkan pointer javascript atau tidak. Bukankah lebih sederhana hanya mengembalikan pointer aktif saja?
Apalagi Anda menambahkan javascript itu di semua halaman admin, tidak terlalu banyak? Juga pertimbangkan bahwa beberapa elemen seperti "# save-post" hanya tersedia di halaman posting baru, jadi bukankah lebih baik menambahkan pointer hanya di halaman pot baru?
Akhirnya, betapa berantakannya javascript yang dicampur dengan PHP, saya pikir Anda harus mempertimbangkan untuk menggunakan wp_localize_script
untuk meneruskan data ke javascript.
Rencana:
- Pindahkan definisi pointer dalam PHP ke file terpisah, dengan cara ini mudah diedit dan juga menghapus markup dari kode PHP, semuanya menghasilkan lebih mudah dibaca dan dikelola
- Dalam pointer konfigurasi menambahkan properti "di mana" yang akan digunakan untuk set di mana halaman admin popup akan muncul:
post-new.php
, index.php
...
- Tulis kelas yang akan menangani pemuatan, penguraian dan pemfilteran info pointer
- Tulis beberapa kebaikan yang akan membantu kita mengubah tombol "Hapus" menjadi "Selanjutnya"
The # 4 kaleng (mungkin) dilakukan dengan mudah mengetahui pointer Plugin baik, tapi itu bukan kasus saya. Jadi saya akan menggunakan kode jQuery umum untuk mendapatkan hasilnya, jika seseorang dapat meningkatkan kode saya, saya akan menghargai.
Edit
Saya mengedit kode (terutama js) karena ada beberapa hal yang tidak saya pertimbangkan: beberapa pointer dapat ditambahkan ke anchor yang sama, atau pointer yang sama dapat ditambahkan ke anchor yang tidak ada atau tidak terlihat. Dalam semua kasus kode sebelumnya tidak berfungsi, versi baru tampaknya mengatasi masalah itu dengan baik.
Saya juga menyiapkan Gist dengan semua kode yang saya uji.
Mari kita mulai dengan poin # 1 dan # 2 : buat file bernama pointers.php
dan tulis di sana:
<?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;
Semua konfigurasi pointer ada di sini. Ketika Anda perlu mengubah sesuatu, cukup buka file ini dan edit.
Perhatikan properti "di mana" yang merupakan array halaman tempat penunjuk harus tersedia.
Jika Anda ingin menampilkan pointer di halaman yang dihasilkan oleh plugin, cari baris yang diuraikan di bawah ini public function filter( $page ) {
dan tambahkan die($page);
segera di bawahnya. Kemudian buka halaman plugin masing-masing dan gunakan string itu di where
properti.
Ok, sekarang poin # 3 .
Sebelum menulis kelas saya hanya ingin kode antarmuka: di sana saya akan memberikan komentar sehingga Anda dapat lebih memahami apa yang akan dilakukan kelas.
<?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 );
}
Saya pikir harus cukup jelas. Sekarang mari kita menulis kelas, itu akan berisi 2 metode dari antarmuka plus 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;
}
}
Kode sangat sederhana, dan melakukan apa yang diharapkan antarmuka.
Namun, kelas tidak melakukan apa-apa dengan sendirinya, kita memerlukan sebuah kait di mana untuk instantiate kelas dan meluncurkan 2 metode yang melewati argumen yang tepat.
Ini 'admin_enqueue_scripts'
sempurna untuk ruang lingkup kami: di sana kami akan memiliki akses ke halaman admin saat ini dan kami juga dapat membuat skrip dan gaya yang diperlukan.
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 );
} );
Tidak ada yang istimewa: hanya menggunakan kelas untuk mendapatkan data petunjuk dan jika beberapa petunjuk lulus filter gaya enqueue dan skrip. Lalu, lewati data pointer ke skrip ke label "Next" yang dilokalkan untuk tombol.
Ok, sekarang bagian "paling sulit": js. Sekali lagi saya ingin menyoroti bahwa saya tidak tahu menggunakan plugin pointer WordPress, jadi apa yang saya lakukan dalam kode saya dapat dilakukan lebih baik jika seseorang mengetahuinya, namun kode saya melakukan pekerjaannya dan - secara umum - itu tidak terlalu buruk.
( 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`
Dengan bantuan komentar kode harus cukup jelas, setidaknya, saya harap begitu.
Ok kita sudah selesai. PHP kami lebih sederhana dan lebih terorganisir, javascript kami lebih mudah dibaca, pointer lebih mudah diedit dan, yang lebih penting, semuanya berfungsi.