Thêm nhiều thư mục plugin


39

Nhiệm vụ

Bạn có thể đăng ký thêm các thư mục Chủ đề bổ sung bằng cách sử dụng register_theme_directory()cho cài đặt WP của mình. Đáng buồn là lõi không cung cấp cùng chức năng cho các plugin. Chúng tôi đã có MU-Plugin, Drop-Ins, Plugins và Themes. Nhưng chúng tôi cần nhiều hơn cho một tổ chức tập tin tốt hơn.

Đây là danh sách các nhiệm vụ cần đạt được:

  • Thêm một thư mục plugin bổ sung
  • Đối với mỗi thư mục plugin, cần có một "tab" mới như được hiển thị ở đây [1]
  • Thư mục bổ sung sẽ có chức năng tương tự như thư mục plugin mặc định có

Có gì trong đó cho bạn?

Câu trả lời tốt nhất và đầy đủ nhất sẽ được trao một tiền thưởng.


[1] Tab bổ sung cho thư mục / thư mục plugin mới


3
Vì cấu trúc thư mục khá gắn với các hằng thư mục, tôi nghi ngờ rằng việc thực hiện điều này ở cấp hệ thống tệp là thực tế (không có sự chấp nhận cốt lõi). Lớp tổ chức ảo trong quản trị viên có thể dễ dàng đạt được hơn ở cấp độ mở rộng.
Hết

@Rarst Không nên kìm hãm bạn thêm suy nghĩ của bạn :)
kaiser

Đây sẽ là một tính năng tuyệt vời.
ltfishie

Tính năng âm thanh tốt. Chỉ cần đảo ngược lõi kỹ sư, tìm ra cách thực hiện (cách WP) và sau đó gửi bản vá cho Devs ... bạn muốn xem register_theme_directory () - search_theme_directories () - get_raw_theme_root () - get_theme_root () () - get_theme () - get_theme ()
Sterling Hamilton

2
Các bạn: Gửi những gì ? Đây là một câu hỏi, không phải là một câu trả lời với mã đầy đủ :) FYI: Một vé mới trên trac để viết lạiget_themes() cho một lớp.
kaiser

Câu trả lời:


28

Được rồi, tôi sẽ đâm sau này. Một số hạn chế tôi gặp phải trên đường đi:

  1. Không có nhiều bộ lọc trong các lớp con của WP_List_Table, ít nhất là không có nơi nào chúng ta cần chúng ở đó.

  2. Do thiếu bộ lọc, chúng tôi thực sự không thể duy trì một danh sách chính xác các loại plugin ở đầu.

  3. Chúng tôi cũng phải sử dụng một số hack JavaScript tuyệt vời (đọc: bẩn) để hiển thị các plugin khi hoạt động.

Tôi đã bọc mã vùng quản trị của mình bên trong một lớp, vì vậy tên hàm của tôi không có tiền tố. Bạn có thể xem tất cả các mã này ở đây . Hãy đóng góp!

API trung tâm

Chỉ cần một chức năng đơn giản thiết lập một biến toàn cục sẽ chứa các thư mục plugin của chúng tôi trong một mảng kết hợp. Đây $keysẽ là một cái gì đó được sử dụng nội bộ để tìm nạp các plugin, v.v. $dirhoặc là một đường dẫn đầy đủ hoặc một cái gì đó liên quan đến wp-contentthư mục. $labelsẽ được hiển thị cho khu vực quản trị của chúng tôi (ví dụ: chuỗi có thể dịch).

<?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
    );
}

Sau đó, tất nhiên, chúng ta cần tải các plugin. Đi vào plugins_loadedmuộn và đi qua các plugin đang hoạt động, tải từng plugin.

Khu vực quản trị

Hãy thiết lập chức năng của chúng tôi trong một lớp.

<?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

Chúng tôi sẽ kết nối plugins_loadedsớm và thiết lập các "hành động" được phép mà chúng tôi sẽ sử dụng. Chúng sẽ xử lý kích hoạt và hủy kích hoạt plugin vì các hàm tích hợp không thể làm điều đó với các thư mục tùy chỉnh.

function setup_actions()
{
    $tmp = array(
        'custom_activate',
        'custom_deactivate'
    );
    $this->actions = apply_filters( 'custom_plugin_actions', $tmp );
}

Sau đó, có chức năng móc vào load-plugins.php. Điều này làm tất cả các loại công cụ thú vị.

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' ) );
    }
}

Chúng ta hãy đi qua một điều tại một thời điểm. các get_pluginsphương pháp, là một wrapper quanh chức năng khác. Nó điền thuộc tính pluginsvới dữ liệu.

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_pluginslà sự lột xác của hàm dựng sẵn get_pluginsmà không cần mã hóa WP_CONTENT_DIRpluginskinh doanh. Về cơ bản: lấy thư mục từ $wp_plugin_directoriestoàn cầu, mở nó, tìm tất cả các tệp plugin. Lưu trữ chúng trong bộ nhớ cache để sau.

<?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;
}

Tiếp theo là công việc phiền phức khi thực sự kích hoạt và hủy kích hoạt các plugin. Để làm điều này, chúng tôi sử dụng handle_actionsphương pháp. Đây là, một lần nữa, bị gạt một cách trắng trợn từ đầu wp-admin/plugins.phptập tin cốt lõi .

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;
    }

}

Một vài chức năng tùy chỉnh ở đây một lần nữa. cd_apd_activate_plugin(tách ra từ activate_plugin) và cd_apd_deactivate_plugins(tách ra từ deactivate_plugins). Cả hai đều giống như các hàm "cha" tương ứng của chúng mà không có các thư mục được mã hóa cứng.

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;
}

Và chức năng hủy kích hoạt

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 );
}

Ngoài ra còn có cd_apd_validate_pluginchức năng, tất nhiên, là một sự lột xác validate_pluginmà không có rác được mã hóa cứng.

<?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;
}

Được rồi, với điều đó ra khỏi đường đi. Chúng ta thực sự có thể bắt đầu nói về việc hiển thị bảng danh sách

Bước 1: thêm lượt xem của chúng tôi vào danh sách ở đầu bảng. Điều này được thực hiện bằng cách lọc views_{$screen->id}bên trong initchức năng của chúng tôi .

add_filter( 'views_' . $screen->id, array( &$this, 'views' ) );

Sau đó, hàm hooked thực tế chỉ cần vòng qua $wp_plugin_directories. Nếu một trong những thư mục mới được đăng ký có plugin, chúng tôi sẽ đưa nó vào màn hình.

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;
}

Điều đầu tiên chúng ta cần làm nếu tình cờ xem trang thư mục plugin tùy chỉnh là lọc lại lượt xem. Chúng ta cần loại bỏ inactivesố đếm vì nó sẽ không chính xác. Hậu quả của việc không có bộ lọc mà chúng ta cần chúng là. Kết nối lại ...

if( $this->get_plugin_status() )
{
    add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
}

Và nhanh chóng bỏ qua ...

function views_again( $views )
{
    if( isset( $views['inactive'] ) ) unset( $views['inactive'] );
    return $views;
}

Tiếp theo, hãy loại bỏ các plugin mà bạn có thể thấy trong bảng danh sách và thay thế chúng bằng các plugin tùy chỉnh của chúng tôi. Móc vào all_plugins.

if( $this->get_plugin_status() )
{
    add_filter( 'views_' . $screen->id, array( &$this, 'views_again' ) );
    add_filter( 'all_plugins', array( &$this, 'filter_plugins' ) );
}

Vì chúng tôi đã thiết lập các plugin và dữ liệu của mình (xem setup_pluginsbên trên), filter_pluginsphương thức chỉ (1) lưu số đếm trên tất cả các plugin cho sau này và (2) thay thế các plugin trong bảng danh sách.

function filter_plugins( $plugins )
{
    if( $key = $this->get_plugin_status() )
    {
        $this->all_count = count( $plugins );
        $plugins = $this->plugins[$key];
    }
    return $plugins;
}

Và bây giờ chúng ta sẽ giết các hành động số lượng lớn. Chúng có thể dễ dàng được hỗ trợ, tôi cho rằng?

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' );
}

Các liên kết hành động plugin mặc định sẽ không hoạt động đối với chúng tôi. Vì vậy, thay vào đó, chúng ta cần thiết lập riêng của mình (với các hành động tùy chỉnh, v.v.). Trong initchức năng.

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 );
}

Điều duy nhất được thay đổi ở đây là (1) chúng tôi đang thay đổi hành động, (2) giữ trạng thái plugin và (3) thay đổi tên nonce một chút.

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&amp;plugin=' . $plugin_file . '&amp;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&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . esc_attr( $context ), 'custom_deactivate-' . $plugin_file ),
            __( 'Deactivate' )
        );
    }
    return $links;
}

Và cuối cùng, chúng ta chỉ cần ghi lại một số JavaScript để hoàn thành nó. Trong initchức năng một lần nữa (tất cả cùng nhau lần này).

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' ) );
}

Trong khi chinh phụcJJ của chúng tôi, chúng tôi cũng sẽ sử dụng wp_localize_scriptđể có được giá trị của tổng số "tất cả các plugin".

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 )
        )
    );
}

Và tất nhiên, JS chỉ là một số hack đẹp để bảng danh sách các plugin hoạt động / không hoạt động hiển thị đúng. Chúng tôi cũng sẽ gắn số đếm chính xác của tất cả các plugin vào Allliên kết.

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');
        }
    });
});

Gói lại

Việc tải thực tế của các thư mục plugin bổ sung là khá khó chịu. Lấy bảng danh sách để hiển thị chính xác là phần khó khăn hơn. Tôi vẫn chưa hoàn toàn hài lòng với cách nó bật ra, nhưng có lẽ ai đó có thể cải thiện mã


1
Ấn tượng! Làm việc rất tốt Tôi sẽ dành chút thời gian vào cuối tuần để nghiên cứu mã của bạn. Lưu ý: Có một chức năng __return_empty_array().
fuxia

Cảm ơn! Phản hồi luôn được chào đón. Kết hợp __return_empty_arraychức năng!
chrisguitarguy

1
Bạn nên thu thập danh sách tất cả các vị trí mà bộ lọc lõi đơn giản sẽ lưu cho bạn một chức năng riêng biệt. Và sau đó, nộp một vé Trac.
fuxia

Điều này thực sự tuyệt vời. Nó sẽ càng lạnh hơn nếu chúng ta có thể đây là một thư viện bên trong một Theme (xem nhận xét của tôi trên Github: github.com/chrisguitarguy/WP-Plugin-Directories/issues/4 )
julien_c

1
+1 Không thể tin rằng tôi đã bỏ lỡ câu trả lời này - công việc tuyệt vời! Tôi sẽ xem xét mã của bạn chi tiết hơn vào cuối tuần :). @Julien_c - tại sao bạn sẽ sử dụng điều này trong một chủ đề?
Stephen Harris

2

Cá nhân tôi không có hứng thú với việc sửa đổi giao diện người dùng, nhưng tôi thích cách bố trí hệ thống tệp có tổ chức hơn, vì nhiều lý do.

Cuối cùng, một cách tiếp cận khác là sử dụng các liên kết tượng trưng.

wp-content
    |-- plugins
        |-- acme-widgets               -> ../plugins-custom/acme-widgets
        |-- acme-custom-post-types     -> ../plugins-custom/acme-custom-post-types
        |-- acme-business-logic        -> ../plugins-custom/acme-business-logic
        |-- google-authenticator       -> ../plugins-external/google-authenticator
        |-- rest-api                   -> ../plugins-external/rest-api
        |-- quick-navigation-interface -> ../plugins-external/quick-navigation-interface
    |-- plugins-custom
        |-- acme-widgets
        |-- acme-custom-post-types
        |-- acme-business-logic
    |-- plugins-external
        |-- google-authenticator
        |-- rest-api
        |-- quick-navigation-interface

Bạn có thể thiết lập các plugin tùy chỉnh của mình plugins-custom, đây có thể là một phần của kho điều khiển phiên bản dự án của bạn.

Sau đó, bạn có thể cài đặt các phụ thuộc của bên thứ 3 vào plugins-external(thông qua các trình con của Trình soạn thảo hoặc Git hoặc bất cứ điều gì bạn thích).

Sau đó, bạn có thể có một tập lệnh Bash đơn giản hoặc lệnh WP-CLI quét các thư mục bổ sung và tạo một liên kết tượng trưng pluginscho mỗi thư mục con mà nó tìm thấy.

pluginssẽ vẫn lộn xộn, nhưng nó không thành vấn đề vì bạn chỉ cần tương tác với plugins-customplugins-external.

Chia tỷ lệ sang ncác thư mục bổ sung sẽ theo cùng một quy trình như hai thư mục đầu tiên.


-3

Hoặc bạn cũng có thể sử dụng COMPOSER với đường dẫn thư mục tùy chỉnh được xử lý để trỏ đến thư mục nội dung wp. Nếu nó không phải là một câu trả lời trực tiếp cho câu hỏi của bạn là một cách suy nghĩ mới về wordpress, hãy chuyển sang nhà soạn nhạc trước khi nó ăn bạn.


Đã chuyển sang Nhà soạn nhạc từ lâu. Vui lòng tra cứu ngày của câu hỏi này. Bên cạnh đó: Đây không thực sự là một câu trả lời. Có lẽ cho thấy làm thế nào để thực sự thiết lập này?
kaiser
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.