Bạn đang gọi .pointer( 'open' );
hàm javascript trên tất cả các đối tượng con trỏ, vì vậy không có gì ngạc nhiên khi tất cả các con trỏ xuất hiện cùng một lúc ...
Điều đó nói rằng, tôi không hiểu tại sao bạn trả lại tất cả các con trỏ (ngay cả những con trỏ không hoạt động) custom_admin_pointers()
và sau đó thêm một chức năng bổ sung để kiểm tra xem có một số con trỏ hoạt động và kiểm tra bên trong vòng lặp con trỏ ( if ( $array['active'] ) {
) để chọn thêm con trỏ javascript hay không. Không đơn giản hơn chỉ trả về con trỏ hoạt động?
Hơn nữa, bạn đang thêm javascript đó trên tất cả các trang quản trị, có quá nhiều không? Cũng xem xét rằng một số yếu tố như "# save-post" chỉ khả dụng trên trang bài đăng mới, vì vậy không tốt hơn chỉ thêm các con trỏ trong trang pot mới?
Cuối cùng, làm thế nào lộn xộn mà javascript trộn lẫn với PHP, tôi nghĩ bạn nên xem xét sử dụng wp_localize_script
để truyền dữ liệu sang javascript.
Kế hoạch:
- Di chuyển các định nghĩa con trỏ trong PHP sang một tệp riêng biệt, theo cách này dễ dàng chỉnh sửa và cũng loại bỏ đánh dấu khỏi mã PHP, mọi thứ đều dễ đọc và dễ bảo trì hơn
- Trong cấu hình con trỏ, thêm một thuộc tính "trong đó" sẽ được sử dụng để đặt trong đó trang quản trị sẽ xuất hiện một cửa sổ bật lên :
post-new.php
, index.php
...
- Viết một lớp sẽ xử lý việc tải, phân tích cú pháp và lọc thông tin con trỏ
- Viết một số tính tốt của js sẽ giúp chúng ta thay đổi nút "Xóa" mặc định thành "Tiếp theo"
Các # 4 lon (có lẽ) thực hiện một cách dễ dàng biết con trỏ cắm tốt, nhưng nó không phải là trường hợp của tôi. Vì vậy, tôi sẽ sử dụng mã jQuery chung để thu được kết quả, nếu ai đó có thể cải thiện mã của tôi, tôi sẽ đánh giá cao.
Biên tập
Tôi đã chỉnh sửa mã (chủ yếu là js) vì có những điều khác nhau mà tôi chưa xem xét: một số con trỏ có thể được thêm vào cùng một neo hoặc có thể thêm cùng một con trỏ vào các neo không tồn tại hoặc không nhìn thấy được. Trong tất cả trường hợp mã trước đó không hoạt động, phiên bản mới dường như giải quyết vấn đề đó một cách độc đáo.
Tôi cũng đã thiết lập Gist với tất cả mã tôi đã sử dụng để kiểm tra.
Hãy bắt đầu với các điểm # 1 và # 2 : tạo một tệp có tên pointers.php
và viết ở đó:
<?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;
Tất cả các cấu hình con trỏ ở đây. Khi bạn cần thay đổi một cái gì đó, chỉ cần mở tệp này và chỉnh sửa nó.
Lưu ý thuộc tính "where" là một mảng các trang nơi con trỏ sẽ có sẵn.
Nếu bạn muốn hiển thị các con trỏ trong một trang được tạo bởi một plugin, hãy tìm dòng này được nêu bên dưới public function filter( $page ) {
và thêm die($page);
ngay bên dưới nó. Sau đó mở trang plugin tương ứng và sử dụng chuỗi đó trong thuộc where
tính.
Ok, bây giờ là điểm số 3 .
Trước khi viết lớp tôi chỉ muốn viết mã một giao diện: ở đó tôi sẽ đưa ý kiến để bạn có thể hiểu rõ hơn về những gì lớp sẽ làm.
<?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 );
}
Tôi nghĩ nên khá rõ ràng. Bây giờ hãy viết lớp, nó sẽ chứa 2 phương thức từ giao diện cộng với hàm tạo.
<?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;
}
}
Mã rất đơn giản và thực hiện chính xác những gì giao diện mong đợi.
Tuy nhiên, lớp không làm gì cả, chúng ta cần một cái móc để khởi tạo lớp nad khởi chạy 2 phương thức truyền các đối số thích hợp.
Điều 'admin_enqueue_scripts'
này là hoàn hảo cho phạm vi của chúng tôi: ở đó chúng tôi sẽ có quyền truy cập vào trang quản trị hiện tại và chúng tôi cũng có thể liệt kê các tập lệnh và kiểu cần thiết.
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 );
} );
Không có gì đặc biệt: chỉ sử dụng lớp để lấy dữ liệu con trỏ và nếu một số con trỏ vượt qua các bộ lọc và các kiểu script. Sau đó chuyển dữ liệu con trỏ tới tập lệnh cùng với nhãn "Tiếp theo" được bản địa hóa cho nút.
Ok, bây giờ là phần "khó nhất": js. Một lần nữa tôi muốn nhấn mạnh rằng tôi không biết plugin con trỏ mà WordPress sử dụng, vì vậy những gì tôi làm trong mã của mình có thể được thực hiện tốt hơn nếu ai đó biết, tuy nhiên mã của tôi hoạt động tốt và nói chung - nó không quá tệ.
( 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`
Với sự giúp đỡ của các bình luận, mã này sẽ khá rõ ràng, ít nhất, tôi hy vọng vậy.
Ok chúng ta đã xong. PHP của chúng tôi đơn giản hơn và được tổ chức tốt hơn, javascript của chúng tôi dễ đọc hơn, các con trỏ dễ chỉnh sửa hơn và quan trọng hơn, mọi thứ đều hoạt động.