如何使我的插件适应Multisite?

Obm*_*nen 27 php wordpress

我为WordPress编写了很多插件,现在我想让它们适应MU.为了"升级"我的插件以支持多站点安装,我必须遵循/避免/适应
哪些考虑/最佳实践/工作流/功能/陷阱

例如,但不限于:

  • 排队脚本/注册
  • 传入文件(php,图像)
  • 自定义文件上传的路径
  • $wpdb
  • 激活,卸载,停用
  • 处理管理员特定页面

在Codex中,有时在单一功能描述中有关于Multisite的评论,但我找不到任何一站式页面来解决这个问题.

bra*_*ilo 68

至于入队和包括,事情就像平常一样.插件路径和URL是相同的.

我从未处理过与Multisite上传路径有关的任何事情,我想通常WP负责这一点.


$wpdb

有一个常用的代码片段可以遍历所有博客:

global $wpdb;
$blogs = $wpdb->get_results("
    SELECT blog_id
    FROM {$wpdb->blogs}
    WHERE site_id = '{$wpdb->siteid}'
    AND spam = '0'
    AND deleted = '0'
    AND archived = '0'
");
$original_blog_id = get_current_blog_id();   
foreach ( $blogs as $blog_id ) 
{
    switch_to_blog( $blog_id->blog_id );
    // do something in the blog, like:
    // update_option()
}   
switch_to_blog( $original_blog_id );
Run Code Online (Sandbox Code Playgroud)

您可以找到使用的示例restore_current_blog()代替switch_to_blog( $original_blog_id ).但这就是为什么switch更可靠:restore_current_blog()vs switch_to_blog().


$blog_id

根据博客ID执行一些功能或挂钩:

global $blog_id;
if( $blog_id != 3 )
    add_image_size( 'category-thumb', 300, 9999 ); //300 pixels wide (and unlimited height)
Run Code Online (Sandbox Code Playgroud)

或者可能:

if( 
    'child.multisite.com' === $_SERVER['SERVER_NAME'] 
    || 
    'domain-mapped-child.com' === $_SERVER['SERVER_NAME']
    )
{
    // do_something();
}
Run Code Online (Sandbox Code Playgroud)

安装 - 仅限网络激活

使用插件标题Network: true (请参阅:示例插件)将仅显示页面中的插件/wp-admin/network/plugins.php.使用此标头,我们可以使用以下内容阻止在插件仅为网络时发生的某些操作.

function my_plugin_block_something()
{
    $plugin = plugin_basename( __FILE__ );
    if( !is_network_only_plugin( $plugin ) )
        wp_die(
            'Sorry, this action is meant for Network only', 
            'Network only',  
            array( 
                'response' => 500, 
                'back_link' => true 
            )
        );    
}
Run Code Online (Sandbox Code Playgroud)

卸载

对于(De)激活,它取决于每个插件.但是,对于卸载,这是我在文件中使用的代码uninstall.php:

<?php
/**
 * Uninstall plugin - Single and Multisite
 * Source: https://wordpress.stackexchange.com/q/80350/12615
 */

// Make sure that we are uninstalling
if ( !defined( 'WP_UNINSTALL_PLUGIN' ) ) 
    exit();

// Leave no trail
$option_name = 'HardCodedOptionName';

if ( !is_multisite() ) 
{
    delete_option( $option_name );
} 
else 
{
    global $wpdb;
    $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
    $original_blog_id = get_current_blog_id();

    foreach ( $blog_ids as $blog_id ) 
    {
        switch_to_blog( $blog_id );
        delete_option( $option_name );    
    }
    switch_to_blog( $original_blog_id );
}
Run Code Online (Sandbox Code Playgroud)

管理页面

1)添加管理页面

要添加管理菜单,我们检查是否is_multisite()并相应地修改了挂钩:

$hook = is_multisite() ? 'network_' : '';
add_action( "{$hook}admin_menu", 'unique_prefix_function_callback' );
Run Code Online (Sandbox Code Playgroud)

2)检查多站点仪表板并修改管理URL:

// Check for MS dashboard
if( is_network_admin() )
    $url = network_admin_url( 'plugins.php' );
else
    $url = admin_url( 'plugins.php' );
Run Code Online (Sandbox Code Playgroud)

3)解决方法仅在主站点中显示界面元素

如果不创建网络管理员菜单(动作挂钩network_admin_menu),则可以仅在主站点中显示插件的某些部分.

我开始在我最大的插件中包含一些Multisite功能,并执行以下操作将插件选项的一部分限制到主站点.这意味着,如果在子站点中激活插件,则该选项将不会显示.

$this->multisite = is_multisite() 
        ? ( is_super_admin() && is_main_site() ) // must meet this 2 conditions to be "our multisite"
        : false;
Run Code Online (Sandbox Code Playgroud)

再看一遍,也许它可以简单地说:is_multisite() && is_super_admin() && is_main_site().请注意,最后两个返回true单个站点.

然后:

if( $this->multisite )
    echo "Something only for the main site, i.e.: Super Admin!";
Run Code Online (Sandbox Code Playgroud)

4)有用的钩子和函数的集合.

:network_admin_menu,wpmu_new_blog,signup_blogform,wpmu_blogs_columns,manage_sites_custom_column,manage_blogs_custom_column,wp_dashboard_setup,network_admin_notices,site_option_active_sitewide_plugins,{$hook}admin_menu

功能:is_multisite,,,,,,is_super_admin is_main_siteget_blogs_of_userupdate_blog_optionis_network_adminnetwork_admin_urlis_network_only_plugin

PS:我宁愿链接到WordPress Answers而不是Codex,因为会有更多的工作代码示例.


示例插件

我刚刚推出了一个Multisite插件,Network Deactivated但Active Elsewhere,并在下面制作了一个非工作的恢复注释版本(请参阅GitHub以获得完整的完整工作版本).完成的插件纯粹是功能性的,没有设置界面.

请注意,插件标题有Network: true.它可以防止插件在子站点中显示.

<?php
/**
 * Plugin Name: Network Deactivated but Active Elsewhere
 * Network: true
 */ 

/**
 * Start the plugin only if in Admin side and if site is Multisite
 */
if( is_admin() && is_multisite() )
{
    add_action(
        'plugins_loaded',
        array ( B5F_Blog_Active_Plugins_Multisite::get_instance(), 'plugin_setup' )
    );
}    

/**
 * Based on Plugin Class Demo - https://gist.github.com/toscho/3804204 
 */
class B5F_Blog_Active_Plugins_Multisite
{
    protected static $instance = NULL;
    public $blogs = array();
    public $plugin_url = '';
    public $plugin_path = '';

    public static function get_instance()
    {
        NULL === self::$instance and self::$instance = new self;
        return self::$instance;
    }

    /**
     * Plugin URL and Path work as normal
     */
    public function plugin_setup()
    {
        $this->plugin_url    = plugins_url( '/', __FILE__ );
        $this->plugin_path   = plugin_dir_path( __FILE__ );
        add_action( 
            'load-plugins.php', 
            array( $this, 'load_blogs' ) 
        );
    }

    public function __construct() {}

    public function load_blogs()
    { 
        /**
         * Using "is_network" property from $current_screen global variable.
         * Run only in /wp-admin/network/plugins.php
         */
        global $current_screen;
        if( !$current_screen->is_network )
            return;

        /**
         * A couple of Multisite-only filter hooks and a regular one.
         */
        add_action( 
                'network_admin_plugin_action_links', 
                array( $this, 'list_plugins' ), 
                10, 4 
        );
        add_filter( 
                'views_plugins-network', // 'views_{$current_screen->id}'
                array( $this, 'inactive_views' ), 
                10, 1 
        );
        add_action(
                'admin_print_scripts',
                array( $this, 'enqueue')
        );

        /**
         * This query is quite frequent to retrieve all blog IDs.
         */
        global $wpdb;
        $this->blogs = $wpdb->get_results(
                " SELECT blog_id, domain 
                FROM {$wpdb->blogs}
                WHERE site_id = '{$wpdb->siteid}'
                AND spam = '0'
                AND deleted = '0'
                AND archived = '0' "
        );  
    }

    /**
     * Enqueue script and style normally.
     */
    public function enqueue()
    {
        wp_enqueue_script( 
                'ndbae-js', 
                $this->plugin_url . '/ndbae.js', 
                array(), 
                false, 
                true 
        );
        wp_enqueue_style( 
                'ndbae-css', 
                $this->plugin_url . '/ndbae.css'
        );
    }

    /**
     * Check if plugin is active in any blog
     * Using Multisite function get_blog_option
     */
    private function get_network_plugins_active( $plug )
    {
        $active_in_blogs = array();
        foreach( $this->blogs as $blog )
        {
            $the_plugs = get_blog_option( $blog['blog_id'], 'active_plugins' );
            foreach( $the_plugs as $value )
            {
                if( $value == $plug )
                    $active_in_blogs[] = $blog['domain'];
            }
        }
        return $active_in_blogs;
    }
}
Run Code Online (Sandbox Code Playgroud)

其他资源 - 电子书

与插件开发没有直接关系,但对多站点管理至关重要.
这些电子书由不少于两个巨人阵容:Mika Epstein(又名Ipstenu)和Andrea Rennick撰写.

  • 这里有一些很棒的信息..如果可以的话,我不会给你+1而是+100..谢谢。都有用。由于 wp-mu 是一个有点“混蛋”的孩子,没有人真正知道如何处理它(只需查看网络选项管理 UI)。无论如何,关于 docblock 中的 `Network: true` 的一个问题,是否有可能以某种方式也为第三方插件触发它?(它不在原始文档块中?) (2认同)