โอเคฉันจะแทงนี่สิ ข้อ จำกัด บางประการที่ฉันพบระหว่างทาง:
ไม่มีตัวกรองจำนวนมากในคลาสย่อยของ WP_List_Table อย่างน้อยก็ไม่มีที่ที่เราต้องการให้เป็น
เนื่องจากขาดตัวกรองเราจึงไม่สามารถรักษารายการประเภทปลั๊กอินที่ถูกต้องที่ด้านบน
นอกจากนี้เรายังต้องใช้จาวาสคริปต์ที่ยอดเยี่ยม (อ่าน: สกปรก) เพื่อแสดงปลั๊กอินว่าใช้งานได้
ฉันห่อรหัสพื้นที่ผู้ดูแลของฉันไว้ในชั้นเรียนดังนั้นชื่อฟังก์ชั่นของฉันจึงไม่ได้ขึ้นหน้า คุณสามารถดูทั้งหมดของรหัสนี้ที่นี่ กรุณาช่วย!
API กลาง
ฟังก์ชั่นง่ายๆที่ตั้งค่าตัวแปรทั่วโลกซึ่งจะมีไดเรกทอรีปลั๊กอินของเราในอาเรย์แบบเชื่อมโยง $key
เป็นไปได้บางสิ่งบางอย่างใช้ภายในเพื่อดึงข้อมูลปลั๊กอิน ฯลฯ$dir
เป็นทั้งเส้นทางหรือบางสิ่งบางอย่างเต็มรูปแบบเมื่อเทียบกับwp-content
ไดเรกทอรี $label
จะเป็นสำหรับการแสดงผลของเราในพื้นที่ผู้ดูแลระบบ (เช่นสตริงที่แปลได้)
<?php
function register_plugin_directory( $key, $dir, $label )
{
global $wp_plugin_directories;
if( empty( $wp_plugin_directories ) ) $wp_plugin_directories = array();
if( ! file_exists( $dir ) && file_exists( trailingslashit( WP_CONTENT_DIR ) . $dir ) )
{
$dir = trailingslashit( WP_CONTENT_DIR ) . $dir;
}
$wp_plugin_directories[$key] = array(
'label' => $label,
'dir' => $dir
);
}
แน่นอนว่าเราต้องโหลดปลั๊กอิน ขอความช่วยเหลือจากplugins_loaded
สายและผ่านปลั๊กอินที่ใช้งานอยู่โหลดแต่ละครั้ง
เขตการปกครอง
มาตั้งค่าฟังก์ชั่นของเราในชั้นเรียนกัน
<?php
class CD_APD_Admin
{
/**
* The container for all of our custom plugins
*/
protected $plugins = array();
/**
* What custom actions are we allowed to handle here?
*/
protected $actions = array();
/**
* The original count of the plugins
*/
protected $all_count = 0;
/**
* constructor
*
* @since 0.1
*/
function __construct()
{
add_action( 'load-plugins.php', array( &$this, 'init' ) );
add_action( 'plugins_loaded', array( &$this, 'setup_actions' ), 1 );
}
} // end class
เรากำลังจะเข้าหาplugins_loaded
แต่เนิ่นๆและตั้งค่า "การกระทำ" ที่เราอนุญาตให้ใช้ สิ่งเหล่านี้จะจัดการกับการเปิดใช้งานปลั๊กอินและการปิดการใช้งานเนื่องจากฟังก์ชั่นในตัวไม่สามารถทำได้กับไดเรกทอรีที่กำหนดเอง
function setup_actions()
{
$tmp = array(
'custom_activate',
'custom_deactivate'
);
$this->actions = apply_filters( 'custom_plugin_actions', $tmp );
}
load-plugins.php
จากนั้นก็มีฟังก์ชั่นลงในติดยาเสพติด มันทำเรื่องสนุกได้ทุกประเภท
function init()
{
global $wp_plugin_directories;
$screen = get_current_screen();
$this->get_plugins();
$this->handle_actions();
add_filter( 'views_' . $screen->id, array( &$this, 'views' ) );
// check to see if we're using one of our custom directories
if( $this->get_plugin_status() )
{
add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
add_filter( 'all_plugins', array( &$this, 'filter_plugins' ) );
// TODO: support bulk actions
add_filter( 'bulk_actions-' . $screen->id, '__return_empty_array' );
add_filter( 'plugin_action_links', array( &$this, 'action_links' ), 10, 2 );
add_action( 'admin_enqueue_scripts', array( &$this, 'scripts' ) );
}
}
มาดูทีละอย่างกัน get_plugins
วิธีการเป็นห่อหุ้มรอบฟังก์ชันอื่น มันเติมคุณลักษณะที่plugins
มีข้อมูล
function get_plugins()
{
global $wp_plugin_directories;
foreach( array_keys( $wp_plugin_directories ) as $key )
{
$this->plugins[$key] = cd_apd_get_plugins( $key );
}
}
cd_apd_get_plugins
เป็นของget_plugins
ฟังก์ชั่นในตัวที่ไม่มีฮาร์ดโค้ดWP_CONTENT_DIR
และplugins
ธุรกิจ โดยทั่วไป: รับไดเรกทอรีจาก$wp_plugin_directories
ทั่วโลกเปิดค้นหาไฟล์ปลั๊กอินทั้งหมด เก็บไว้ในแคชไว้ใช้ภายหลัง
<?php
function cd_apd_get_plugins( $dir_key )
{
global $wp_plugin_directories;
// invalid dir key? bail
if( ! isset( $wp_plugin_directories[$dir_key] ) )
{
return array();
}
else
{
$plugin_root = $wp_plugin_directories[$dir_key]['dir'];
}
if ( ! $cache_plugins = wp_cache_get( 'plugins', 'plugins') )
$cache_plugins = array();
if ( isset( $cache_plugins[$dir_key] ) )
return $cache_plugins[$dir_key];
$wp_plugins = array();
$plugins_dir = @ opendir( $plugin_root );
$plugin_files = array();
if ( $plugins_dir ) {
while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
if ( substr($file, 0, 1) == '.' )
continue;
if ( is_dir( $plugin_root.'/'.$file ) ) {
$plugins_subdir = @ opendir( $plugin_root.'/'.$file );
if ( $plugins_subdir ) {
while (($subfile = readdir( $plugins_subdir ) ) !== false ) {
if ( substr($subfile, 0, 1) == '.' )
continue;
if ( substr($subfile, -4) == '.php' )
$plugin_files[] = "$file/$subfile";
}
closedir( $plugins_subdir );
}
} else {
if ( substr($file, -4) == '.php' )
$plugin_files[] = $file;
}
}
closedir( $plugins_dir );
}
if ( empty($plugin_files) )
return $wp_plugins;
foreach ( $plugin_files as $plugin_file ) {
if ( !is_readable( "$plugin_root/$plugin_file" ) )
continue;
$plugin_data = get_plugin_data( "$plugin_root/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached.
if ( empty ( $plugin_data['Name'] ) )
continue;
$wp_plugins[trim( $plugin_file )] = $plugin_data;
}
uasort( $wp_plugins, '_sort_uname_callback' );
$cache_plugins[$dir_key] = $wp_plugins;
wp_cache_set('plugins', $cache_plugins, 'plugins');
return $wp_plugins;
}
ถัดไปเป็นธุรกิจที่น่ารำคาญของการเปิดใช้งานและปิดการใช้งานปลั๊กอิน ในการทำเช่นนี้เราใช้handle_actions
วิธีการ นี่คืออีกครั้ง ripped ออกมาโจ๋งครึ่มจากด้านบนของwp-admin/plugins.php
ไฟล์หลัก
function handle_actions()
{
$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
// not allowed to handle this action? bail.
if( ! in_array( $action, $this->actions ) ) return;
// Get the plugin we're going to activate
$plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : false;
if( ! $plugin ) return;
$context = $this->get_plugin_status();
switch( $action )
{
case 'custom_activate':
if( ! current_user_can('activate_plugins') )
wp_die( __('You do not have sufficient permissions to manage plugins for this site.') );
check_admin_referer( 'custom_activate-' . $plugin );
$result = cd_apd_activate_plugin( $plugin, $context );
if ( is_wp_error( $result ) )
{
if ( 'unexpected_output' == $result->get_error_code() )
{
$redirect = add_query_arg( 'plugin_status', $context, self_admin_url( 'plugins.php' ) );
wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) ) ;
exit();
}
else
{
wp_die( $result );
}
}
wp_redirect( add_query_arg( array( 'plugin_status' => $context, 'activate' => 'true' ), self_admin_url( 'plugins.php' ) ) );
exit();
break;
case 'custom_deactivate':
if ( ! current_user_can( 'activate_plugins' ) )
wp_die( __('You do not have sufficient permissions to deactivate plugins for this site.') );
check_admin_referer('custom_deactivate-' . $plugin);
cd_apd_deactivate_plugins( $plugin, $context );
if ( headers_sent() )
echo "<meta http-equiv='refresh' content='" . esc_attr( "0;url=plugins.php?deactivate=true&plugin_status=$status&paged=$page&s=$s" ) . "' />";
else
wp_redirect( self_admin_url("plugins.php?deactivate=true&plugin_status=$context") );
exit();
break;
default:
do_action( 'custom_plugin_dir_' . $action );
break;
}
}
ฟังก์ชั่นที่กำหนดเองสองสามที่นี่อีกครั้ง cd_apd_activate_plugin
(คัดลอกมาจากactivate_plugin
) และcd_apd_deactivate_plugins
(ฉีกออกจากdeactivate_plugins
) ทั้งสองอย่างนั้นเหมือนกับฟังก์ชั่น "พาเรนต์" ตามลำดับโดยไม่มีไดเรกทอรีฮาร์ดโค้ด
function cd_apd_activate_plugin( $plugin, $context, $silent = false )
{
$plugin = trim( $plugin );
$redirect = add_query_arg( 'plugin_status', $context, admin_url( 'plugins.php' ) );
$redirect = apply_filters( 'custom_plugin_redirect', $redirect );
$current = get_option( 'active_plugins_' . $context, array() );
$valid = cd_apd_validate_plugin( $plugin, $context );
if ( is_wp_error( $valid ) )
return $valid;
if ( !in_array($plugin, $current) ) {
if ( !empty($redirect) )
wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect)); // we'll override this later if the plugin can be included without fatal error
ob_start();
include_once( $valid );
if ( ! $silent ) {
do_action( 'custom_activate_plugin', $plugin, $context );
do_action( 'custom_activate_' . $plugin, $context );
}
$current[] = $plugin;
sort( $current );
update_option( 'active_plugins_' . $context, $current );
if ( ! $silent ) {
do_action( 'custom_activated_plugin', $plugin, $context );
}
if ( ob_get_length() > 0 ) {
$output = ob_get_clean();
return new WP_Error('unexpected_output', __('The plugin generated unexpected output.'), $output);
}
ob_end_clean();
}
return true;
}
และฟังก์ชั่นปิดการใช้งาน
function cd_apd_deactivate_plugins( $plugins, $context, $silent = false ) {
$current = get_option( 'active_plugins_' . $context, array() );
foreach ( (array) $plugins as $plugin )
{
$plugin = trim( $plugin );
if ( ! in_array( $plugin, $current ) ) continue;
if ( ! $silent )
do_action( 'custom_deactivate_plugin', $plugin, $context );
$key = array_search( $plugin, $current );
if ( false !== $key ) {
array_splice( $current, $key, 1 );
}
if ( ! $silent ) {
do_action( 'custom_deactivate_' . $plugin, $context );
do_action( 'custom_deactivated_plugin', $plugin, $context );
}
}
update_option( 'active_plugins_' . $context, $current );
}
นอกจากนี้ยังมีcd_apd_validate_plugin
ฟังก์ชั่นที่validate_plugin
ไม่ได้ใช้งานโดยไม่มีขยะที่เข้ารหัสยาก
<?php
function cd_apd_validate_plugin( $plugin, $context )
{
$rv = true;
if ( validate_file( $plugin ) )
{
$rv = new WP_Error('plugin_invalid', __('Invalid plugin path.'));
}
global $wp_plugin_directories;
if( ! isset( $wp_plugin_directories[$context] ) )
{
$rv = new WP_Error( 'invalid_context', __( 'The context for this plugin does not exist' ) );
}
$dir = $wp_plugin_directories[$context]['dir'];
if( ! file_exists( $dir . '/' . $plugin) )
{
$rv = new WP_Error( 'plugin_not_found', __( 'Plugin file does not exist.' ) );
}
$installed_plugins = cd_apd_get_plugins( $context );
if ( ! isset($installed_plugins[$plugin]) )
{
$rv = new WP_Error( 'no_plugin_header', __('The plugin does not have a valid header.') );
}
$rv = $dir . '/' . $plugin;
return $rv;
}
เอาล่ะออกไปให้พ้น เราสามารถเริ่มพูดคุยเกี่ยวกับการแสดงตารางรายการ
ขั้นตอนที่ 1: เพิ่มมุมมองของเราไปยังรายการที่ด้านบนของตาราง สิ่งนี้ทำได้โดยการกรองviews_{$screen->id}
ภายในinit
ฟังก์ชั่นของเรา
add_filter( 'views_' . $screen->id, array( &$this, 'views' ) );
จากนั้นฟังก์ชั่น hooked ที่แท้จริงจะวน$wp_plugin_directories
ซ้ำผ่าน หากหนึ่งในไดเรกทอรีที่ลงทะเบียนใหม่มีปลั๊กอินเราจะรวมไว้ในจอแสดงผล
function views( $views )
{
global $wp_plugin_directories;
// bail if we don't have any extra dirs
if( empty( $wp_plugin_directories ) ) return $views;
// Add our directories to the action links
foreach( $wp_plugin_directories as $key => $info )
{
if( ! count( $this->plugins[$key] ) ) continue;
$class = $this->get_plugin_status() == $key ? ' class="current" ' : '';
$views[$key] = sprintf(
'<a href="%s"' . $class . '>%s <span class="count">(%d)</span></a>',
add_query_arg( 'plugin_status', $key, 'plugins.php' ),
esc_html( $info['label'] ),
count( $this->plugins[$key] )
);
}
return $views;
}
สิ่งแรกที่เราต้องทำถ้าเรากำลังดูหน้าไดเรกทอรีปลั๊กอินที่กำหนดเองคือการกรองมุมมองอีกครั้ง เราต้องกำจัดinactive
จำนวนเพราะมันจะไม่แม่นยำ ผลที่ตามมาของการไม่มีตัวกรองที่เราต้องการให้เป็น ขออีกครั้ง ...
if( $this->get_plugin_status() )
{
add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
}
และไม่มีการตั้งค่าอย่างรวดเร็ว ...
function views_again( $views )
{
if( isset( $views['inactive'] ) ) unset( $views['inactive'] );
return $views;
}
ถัดไปลองกำจัดปลั๊กอินที่คุณจะเห็นเป็นอย่างอื่นในตารางรายการและแทนที่ด้วยปลั๊กอินที่กำหนดเองของเรา all_plugins
ขอเข้าสู่
if( $this->get_plugin_status() )
{
add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
add_filter( 'all_plugins', array( &$this, 'filter_plugins' ) );
}
เนื่องจากเราได้ตั้งค่าปลั๊กอินและข้อมูลของเราแล้ว (ดูsetup_plugins
ด้านบน) filter_plugins
วิธีการเพียง (1) จะบันทึกจำนวนในปลั๊กอินทั้งหมดในภายหลังและ (2) แทนที่ปลั๊กอินในตารางรายการ
function filter_plugins( $plugins )
{
if( $key = $this->get_plugin_status() )
{
$this->all_count = count( $plugins );
$plugins = $this->plugins[$key];
}
return $plugins;
}
และตอนนี้เราจะฆ่าการกระทำเป็นกลุ่ม ฉันสามารถรองรับสิ่งเหล่านี้ได้อย่างง่ายดายใช่ไหม?
if( $this->get_plugin_status() )
{
add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
add_filter( 'all_plugins', array( &$this, 'filter_plugins' ) );
// TODO: support bulk actions
add_filter( 'bulk_actions-' . $screen->id, '__return_empty_array' );
}
ลิงก์การกระทำของปลั๊กอินเริ่มต้นจะไม่ทำงานสำหรับเรา ดังนั้นเราต้องตั้งค่าของเราเอง (ด้วยการกระทำที่กำหนดเอง ฯลฯ ) ในinit
ฟังก์ชั่น
if( $this->get_plugin_status() )
{
add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
add_filter( 'all_plugins', array( &$this, 'filter_plugins' ) );
// TODO: support bulk actions
add_filter( 'bulk_actions-' . $screen->id, '__return_empty_array' );
add_filter( 'plugin_action_links', array( &$this, 'action_links' ), 10, 2 );
}
สิ่งเดียวที่ได้รับการเปลี่ยนแปลงที่นี่คือ (1) เรากำลังเปลี่ยนการกระทำ (2) การรักษาสถานะปลั๊กอินในและ (3) การเปลี่ยนชื่อ nonce เล็กน้อย
function action_links( $links, $plugin_file )
{
$context = $this->get_plugin_status();
// let's just start over
$links = array();
$links['activate'] = sprintf(
'<a href="%s" title="Activate this plugin">%s</a>',
wp_nonce_url( 'plugins.php?action=custom_activate&plugin=' . $plugin_file . '&plugin_status=' . esc_attr( $context ), 'custom_activate-' . $plugin_file ),
__( 'Activate' )
);
$active = get_option( 'active_plugins_' . $context, array() );
if( in_array( $plugin_file, $active ) )
{
$links['deactivate'] = sprintf(
'<a href="%s" title="Deactivate this plugin" class="cd-apd-deactivate">%s</a>',
wp_nonce_url( 'plugins.php?action=custom_deactivate&plugin=' . $plugin_file . '&plugin_status=' . esc_attr( $context ), 'custom_deactivate-' . $plugin_file ),
__( 'Deactivate' )
);
}
return $links;
}
และในที่สุดเราก็ต้องจัดคิว JavaScript เพื่อปิดมัน ในinit
ฟังก์ชั่นอีกครั้ง (พร้อมกันในเวลานี้)
if( $this->get_plugin_status() )
{
add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
add_filter( 'all_plugins', array( &$this, 'filter_plugins' ) );
// TODO: support bulk actions
add_filter( 'bulk_actions-' . $screen->id, '__return_empty_array' );
add_filter( 'plugin_action_links', array( &$this, 'action_links' ), 10, 2 );
add_action( 'admin_enqueue_scripts', array( &$this, 'scripts' ) );
}
ในขณะที่จัดคิว JS ของเราเราจะใช้wp_localize_script
เพื่อรับค่าการนับ "ปลั๊กอินทั้งหมด" ทั้งหมด
function scripts()
{
wp_enqueue_script(
'cd-apd-js',
CD_APD_URL . 'js/apd.js',
array( 'jquery' ),
null
);
wp_localize_script(
'cd-apd-js',
'cd_apd',
array(
'count' => esc_js( $this->all_count )
)
);
}
และแน่นอนว่า JS เป็นเพียงแฮ็คที่ดีในการทำให้ปลั๊กอินรายการใช้งาน / ไม่ใช้งานเพื่อแสดงตารางอย่างถูกต้อง นอกจากนี้เราจะติดจำนวนที่ถูกต้องของปลั๊กอินทั้งหมดกลับเข้าไปในAll
ลิงค์
jQuery(document).ready(function(){
jQuery('li.all a').removeClass('current').find('span.count').html('(' + cd_apd.count + ')');
jQuery('.wp-list-table.plugins tr').each(function(){
var is_active = jQuery(this).find('a.cd-apd-deactivate');
if(is_active.length) {
jQuery(this).removeClass('inactive').addClass('active');
jQuery(this).find('div.plugin-version-author-uri').removeClass('inactive').addClass('active');
}
});
});
สรุป
การโหลดไดเรกทอรีปลั๊กอินเพิ่มเติมที่เกิดขึ้นจริงนั้นค่อนข้างน่าตื่นเต้น รับตารางรายการเพื่อแสดงอย่างถูกต้องเป็นส่วนที่ยากขึ้น ฉันยังคงไม่พอใจอย่างสมบูรณ์กับวิธีการที่ปรากฏออกมา แต่บางทีบางคนสามารถปรับปรุงรหัสได้