問題描述

我想以編程方式向我的兩個側邊欄添加小工具。我找不到任何正式的做法嗎?

我開始查看數據庫。我發現這是’sidebars_widgets’ 選項,它將小工具放在邊欄上。當查看選項時,窗口小工具名稱的末尾添加如下:widget_name-6 。那個號碼來自哪裏?

關於如何解決這個問題的任何想法?

最佳解決方案

當我開始這個答案時,應該只是一個小筆記。那麼我失敗了抱歉! 留在我身邊,有一個隱藏在深處的好東西…

如何存儲 WordPress 小工具

窗口小工具列表存儲在名為'sidebars_widgets'的選項中。 var_export()可能會給出以下內容:

array (
  'wp_inactive_widgets' =>
  array (
  ),
  'top-widget' =>
  array (
  ),
  'bottom-widget' =>
  array (
  ),
  'array_version' => 3,
)

忽略'wp_inactive_widgets''array_version'。我們不必關心那些。其他鍵是註冊的側邊欄的標識符。在這種情況下,側邊欄可能已經註冊了此代碼:

// Register two sidebars.
$sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
foreach ( $sidebars as $sidebar )
{
    register_sidebar(
        array (
            'name'          => $sidebar,
            'id'            => $sidebar,
            'before_widget' => '',
            'after_widget'  => ''
        )
    );
}

默認情況下,側邊欄註冊後為空。當然。

對於每個註冊的窗口小工具類,都會創建一個單獨的選項,其中包含所有必該選項以字符串 widget_為前綴。要獲取所有活動的 RSS 小工具的選項,我們必須研究…

get_option( 'widget_rss' );

可能輸出:

array (
  2 =>
  array (
    'title' => 'WordPress Stack Exchange',
    'url' => 'http://wordpress.stackexchange.com/feeds',
    'link' => 'http://wordpress.stackexchange.com/questions',
    'items' => 5,
    'show_summary' => 1,
    'show_author' => 0,
    'show_date' => 0,
  ),
)

注意數字 2. 多個實例的參數都存儲在按數字排序的這一個選項中。

要查看哪些小工具類已經被 WordPress 知道,請轉到 wp-admin/options.php 並向下滾動,直到看到如下所示:

是的,序列化的數據。不,你不能在這裏閲讀。別擔心,你不必。

演示小工具

為了更好地説明內部工作,我寫了一個非常簡單的演示小工具:

/**
 * Super simple widget.
 */
class T5_Demo_Widget extends WP_Widget
{
    public function __construct()
    {                      // id_base        ,  visible name
        parent::__construct( 't5_demo_widget', 'T5 Demo Widget' );
    }

    public function widget( $args, $instance )
    {
        echo $args['before_widget'], wpautop( $instance['text'] ), $args['after_widget'];
    }

    public function form( $instance )
    {
        $text = isset ( $instance['text'] )
            ? esc_textarea( $instance['text'] ) : '';
        printf(
            '<textarea class="widefat" rows="7" cols="20" id="%1$s" name="%2$s">%3$s</textarea>',
            $this->get_field_id( 'text' ),
            $this->get_field_name( 'text' ),
            $text
        );
    }
}

注意構造函數:'t5_demo_widget'$id_base,這個小工具的標識符。如您在屏幕截圖中所看到的,其參數存儲在選項 widget_t5_demo_widget 中。所有您的自定義小工具將被視為這樣。你不必猜名字。而且,由於您已經編寫了您的小工具 (可能),您可以知道類 $instance 參數中的所有參數。

主題基礎

首先你必須註冊一些側邊欄和自定義小工具。對此的正確操作很容易記住:'widgets_init'。將所有內容放入容器 – 類或功能。為了簡單起見,我將使用一個名為 t5_default_widget_demo()的函數。

所有以下代碼都進入 functions.phpT5_Demo_Widget 類應該已經加載了。我只是把它放入同一個文件…

add_action( 'widgets_init', 't5_default_widget_demo' );

function t5_default_widget_demo()
{
    // Register our own widget.
    register_widget( 'T5_Demo_Widget' );

    // Register two sidebars.
    $sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
    foreach ( $sidebars as $sidebar )
    {
        register_sidebar(
            array (
                'name'          => $sidebar,
                'id'            => $sidebar,
                'before_widget' => '',
                'after_widget'  => ''
            )
        );
    }

到目前為止,這麼簡單。我們的主題現在是小工具就緒,演示小工具是已知的。現在的樂趣。

$active_widgets = get_option( 'sidebars_widgets' );

if ( ! empty ( $active_widgets[ $sidebars['a'] ] )
    or ! empty ( $active_widgets[ $sidebars['b'] ] )
)
{   // Okay, no fun anymore. There is already some content.
    return;
}

你真的不想破壞用户設置。如果側邊欄中已經有一些內容,那麼您的代碼不應該運行它。這就是為什麼我們在這種情況下停止。

好吧,假設邊欄是空的… 我們需要一個櫃枱:

$counter = 1;

小工具編號。這些數字是 WordPress 的第二個標識符。

我們讓數組改變它:

$active_widgets = get_option( 'sidebars_widgets' );

我們還需要一個櫃枱 (稍後再説):

$counter = 1;

這裏是我們如何使用計數器,側邊欄名稱和小工具參數 (我們只有一個參數:text) 。

// Add a 'demo' widget to the top sidebar …
$active_widgets[ $sidebars['a'] ][0] = 't5_demo_widget-' . $counter;
// … and write some text into it:
$demo_widget_content[ $counter ] = array ( 'text' => "This works!nnAmazing!" );

$counter++;

請注意如何創建窗口小工具標識符:id_base,減號-和計數器。小工具的內容存儲在另一個變量 $demo_widget_content 中。這是計數器,鍵和數組參數存儲在數組中。

當我們完成避免碰撞時,我們增加一個計數器。

那很簡單。現在是一個 RSS 小工具。更多的領域,更有趣!

$active_widgets[ $sidebars['a'] ][] = 'rss-' . $counter;
// The latest 15 questions from WordPress Stack Exchange.
$rss_content[ $counter ] = array (
    'title'        => 'WordPress Stack Exchange',
    'url'          => 'http://wordpress.stackexchange.com/feeds',
    'link'         => 'http://wordpress.stackexchange.com/questions',
    'items'        => 15,
    'show_summary' => 0,
    'show_author'  => 1,
    'show_date'    => 1,
);
update_option( 'widget_rss', $rss_content );

$counter++;

這裏有一些新的東西:update_option()這將存儲 RSS 窗口參數在一個單獨的選項。 WordPress 會在以後自動找到。我們沒有保存演示小工具參數,因為現在我們將第二個實例添加到第二個側邊欄…

// Okay, now to our second sidebar. We make it short.
$active_widgets[ $sidebars['b'] ][] = 't5_demo_widget-' . $counter;
#$demo_widget_content = get_option( 'widget_t5_demo_widget', array() );
$demo_widget_content[ $counter ] = array ( 'text' => 'The second instance of our amazing demo widget.' );
update_option( 'widget_t5_demo_widget', $demo_widget_content );

… 並立即保存 t5_demo_widget 的所有參數。不需要更新相同的選項兩次。

那麼現在有足夠的小工具呢,我們也來保存 sidebars_widgets

update_option( 'sidebars_widgets', $active_widgets );

現在 WordPress 將知道有一些註冊的小工具,每個小工具的參數都存儲在哪裏。 sidebar_widgets 上的 var_export()將如下所示:

array (
  'wp_inactive_widgets' =>
  array (
  ),
  'top-widget' =>
  array (
    0 => 't5_demo_widget-1',
    1 => 'rss-2',
  ),
  'bottom-widget' =>
  array (
    0 => 't5_demo_widget-3',
  ),
  'array_version' => 3,
)

complete code 再次:

add_action( 'widgets_init', 't5_default_widget_demo' );

function t5_default_widget_demo()
{
    // Register our own widget.
    register_widget( 'T5_Demo_Widget' );

    // Register two sidebars.
    $sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
    foreach ( $sidebars as $sidebar )
    {
        register_sidebar(
            array (
                'name'          => $sidebar,
                'id'            => $sidebar,
                'before_widget' => '',
                'after_widget'  => ''
            )
        );
    }

    // Okay, now the funny part.

    // We don't want to undo user changes, so we look for changes first.
    $active_widgets = get_option( 'sidebars_widgets' );

    if ( ! empty ( $active_widgets[ $sidebars['a'] ] )
        or ! empty ( $active_widgets[ $sidebars['b'] ] )
    )
    {   // Okay, no fun anymore. There is already some content.
        return;
    }

    // The sidebars are empty, let's put something into them.
    // How about a RSS widget and two instances of our demo widget?

    // Note that widgets are numbered. We need a counter:
    $counter = 1;

    // Add a 'demo' widget to the top sidebar …
    $active_widgets[ $sidebars['a'] ][0] = 't5_demo_widget-' . $counter;
    // … and write some text into it:
    $demo_widget_content[ $counter ] = array ( 'text' => "This works!nnAmazing!" );
    #update_option( 'widget_t5_demo_widget', $demo_widget_content );

    $counter++;

    // That was easy. Now a RSS widget. More fields, more fun!
    $active_widgets[ $sidebars['a'] ][] = 'rss-' . $counter;
    // The latest 15 questions from WordPress Stack Exchange.
    $rss_content[ $counter ] = array (
        'title'        => 'WordPress Stack Exchange',
        'url'          => 'http://wordpress.stackexchange.com/feeds',
        'link'         => 'http://wordpress.stackexchange.com/questions',
        'items'        => 15,
        'show_summary' => 0,
        'show_author'  => 1,
        'show_date'    => 1,
    );
    update_option( 'widget_rss', $rss_content );

    $counter++;

    // Okay, now to our second sidebar. We make it short.
    $active_widgets[ $sidebars['b'] ][] = 't5_demo_widget-' . $counter;
    #$demo_widget_content = get_option( 'widget_t5_demo_widget', array() );
    $demo_widget_content[ $counter ] = array ( 'text' => 'The second instance of our amazing demo widget.' );
    update_option( 'widget_t5_demo_widget', $demo_widget_content );

    // Now save the $active_widgets array.
    update_option( 'sidebars_widgets', $active_widgets );
}

如果你現在去 wp-admin/widgets.php,你會看到三個 pre-set 小工具:

就是這樣使用 …

dynamic_sidebar( 'top-widget' );
dynamic_sidebar( 'bottom-widget' );

… 打印小工具。

有一個小故障:您必須先加載 front-end 兩次才能進行初始註冊。如果有人能在這裏幫忙,我將非常感激。

次佳解決方案

感謝您分享您的解決方案。我使用了這個問題中描述的內容來創建一個可以很容易地初始化邊欄的代碼。它非常靈活,您可以創建儘可能多的小工具,而無需修改代碼。只需使用過濾器鈎子並傳遞數組中的參數。以下是已註釋的代碼:

function initialize_sidebars(){

  $sidebars = array();
  // Supply the sidebars you want to initialize in a filter
  $sidebars = apply_filters( 'alter_initialization_sidebars', $sidebars );

  $active_widgets = get_option('sidebars_widgets');

  $args = array(
    'sidebars' => $sidebars,
    'active_widgets' => $active_widgets,
    'update_widget_content' => array(),
  );

  foreach ( $sidebars as $current_sidebar_short_name => $current_sidebar_id ) {

    $args['current_sidebar_short_name'] = $current_sidebar_short_name;
    // we are passing our arguments as a reference, so we can modify their contents
    do_action( 'your_plugin_sidebar_init', array( &$args ) );

  }
  // we only need to update sidebars, if the sidebars are not initialized yet
  // and we also have data to initialize the sidebars with
  if ( ! empty( $args['update_widget_content'] ) ) {

    foreach ( $args['update_widget_content'] as $widget => $widget_occurence ) {

      // the update_widget_content array stores all widget instances of each widget
      update_option( 'widget_' . $widget, $args['update_widget_content'][ $widget ] );

    }
    // after we have updated all the widgets, we update the active_widgets array
    update_option( 'sidebars_widgets', $args['active_widgets'] );

  }

}

這是一個幫助函數,它檢查邊欄中是否已經有內容:

function check_sidebar_content( $active_widgets, $sidebars, $sidebar_name ) {

  $sidebar_contents = $active_widgets[ $sidebars[ $sidebar_name ] ];

  if ( ! empty( $sidebar_contents ) ) {

    return $sidebar_contents;

  }

  return false;

}

現在我們需要創建一個掛鈎到’sidebar_init’ 操作的函數。

add_action( 'your_plugin_sidebar_init', 'add_widgets_to_sidebar' );

function add_widgets_to_sidebar( $args ) {

  extract( $args[0] );

  // We check if the current sidebar already has content and if it does we exit
  $sidebar_element = check_sidebar_content( $active_widgets, $sidebars, $current_sidebar_short_name );

  if ( $sidebar_element !== false  ) {

    return;

  }

  do_action( 'your_plugin_widget_init', array( &$args ) );

}

而現在的 widget 初始化:

add_action( 'your_plugin_widget_init', 'your_plugin_initialize_widgets' );

function your_plugin_initialize_widgets( $args ) {

  extract( $args[0][0] );

  $widgets = array();

  // Here the widgets previously defined in filter functions are initialized,
  // but only those corresponding to the current sidebar
  $widgets = apply_filters( 'alter_initialization_widgets_' . $current_sidebar_short_name, $widgets );

  if ( ! empty( $widgets ) ) {

    do_action( 'create_widgets_for_sidebar', array( &$args ), $widgets );

  }

}

最後一個操作是在每個側邊欄中創建小工具:

add_action( 'create_widgets_for_sidebar', 'your_plugin_create_widgets', 10, 2 );

function your_plugin_create_widgets( $args, $widgets ) {

  extract( $args[0][0][0] );

  foreach ( $widgets as $widget => $widget_content ) {

    // The counter is increased on a widget basis. For instance, if you had three widgets,
    // two of them being the archives widget and one of the being a custom widget, then the
    // correct counter appended to each one of them would be archive-1, archive-2 and custom-1.
    // So the widget counter is not a global counter but one which counts the instances (the
    // widget_occurrence as I have called it) of each widget.
    $counter = count_widget_occurence( $widget, $args[0][0][0]['update_widget_content'] );

    // We add each instance to the active widgets...
    $args[0][0][0]['active_widgets'][ $sidebars[ $current_sidebar_short_name ] ][] = $widget . '-' . $counter;

    // ...and also save the content in another associative array.
    $args[0][0][0]['update_widget_content'][ $widget ][ $counter ] = $widget_content;

  }

}

此功能用於跟蹤已定義特定小工具的實例數量:

function count_widget_occurence( $widget, $update_widget_content ) {

  $widget_occurrence = 0;

  // We look at the update_widget_content array which stores each
  // instance of the current widget with the current counter in an
  // associative array. The key of this array is the name of the
  // current widget.
      // Having three archives widgets for instance would look like this:
      // 'update_widget_content'['archives'] => [1][2][3]
  if ( array_key_exists( $widget, $update_widget_content ) ) {

    $widget_counters = array_keys( $update_widget_content[ $widget ] );

    $widget_occurrence = end( $widget_counters );

  }

  $widget_occurrence++;

  return $widget_occurrence;

}

我們最後需要做的是實際分配值。利用這些過濾功能:

add_filter( 'alter_initialization_sidebars', 'current_initialization_sidebars' ) ;
// Use this filter hook to specify which sidebars you want to initialize
function current_initialization_sidebars( $sidebars ) {

  // The sidebars are assigned in this manner.
  // The array key is very important because it is used as a suffix in the initialization function
  // for each sidebar. The value is what is used in the html attributes.
  $sidebars['info'] = 'info-sidebar';

  return $sidebars;

}

和:

add_filter( 'alter_initialization_widgets_info', 'current_info_widgets' );
// Add a filter hook for each sidebar you have. The hook name is derived from
// the array keys passed in the alter_initialization_sidebars filter.
// Each filter has a name of 'alter_initialization_widgets_' and the array
// key appended to it.

function current_info_widgets( $widgets ) {
  // This filter function is used to add widgets to the info sidebar. Add each widget
  // you want to assign to this sidebar to an array.

  return $widgets = array(
    // Use the name of the widget as specified in the call to the WP_Widget constructor
    // as the array key.

    // The archives widget is a widget which is shipped with wordpress by default.
    // The arguments used by this widget, as all other default widgets, can be found
    // in wp-includes/default-widgets.php.

    'archives' => array(
      // Pass in the array options as an array
      'title' => 'Old Content',
      'dropdown' => 'on',
      // The 'on' value is arbitrarily chosen, the widget actually only checks for
      // a non-empty value on both of these options
      'count' => 'on',
    ),
 );

}

理想情況下,您可以在一個安裝程序中調用 initialize_sidebars,該函數調用插件或主題激活,如下所示:主題激活:

add_action( 'after_switch_theme', 'my_activation_function' );
function my_activation_function() {
  initialize_sidebars();
}

插件激活:

register_activation_hook( __FILE__, 'my_activation_function' );
function my_activation_function() {
  initialize_sidebars();
}

總結這個功能集團的用法:

  1. 創建一個初始化掛鈎到’alter_initialization_sidebars’ 過濾器的側邊欄的功能。
  2. 為剛剛添加的每個側邊欄創建一個附加到 「alter_initialization_widgets_ $ sidebarname」 過濾器的函數。將 $ sidebarname 替換為您在步驟 1 中創建的每個側邊欄的名稱。

您也可以將此未註釋的代碼簡單地複製到函數文件中,並立即開始創建過濾器函數:Code on pastie (without initialization filter functions)

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。