Программно добавлять виджеты на боковые панели

62

Я хотел бы программно добавить виджеты на мои две боковые панели, которые у меня есть. Я не мог найти какой-либо официальный способ сделать это?

Я начал искать в базе данных. Я обнаружил, что это опция 'sidebars_widgets', которая помещает виджеты на боковые панели. При просмотре опций к именам виджетов добавляется номер, добавленный в конец, например: widget_name-6. Откуда этот номер?

Есть идеи, как это исправить?

Marlun
источник
6
Вы должны добавить свой ответ там, чтобы ответить на свой вопрос :)
helenhousandi
Для большого изложения на виджетах боковой панели, проверьте эту статью: justintadlock.com/archives/2010/11/08/sidebars-in-wordpress .
Джошуа
Следите за параметром действия вызова ajax, который выполняется при добавлении виджета, а затем найдите код, связанный с этим зацеплением действия ajax, и посмотрите, как это делается в ядре. Просто! ;)
Ashfame
5
Пожалуйста, повторно опубликуйте свое решение в качестве ответа и примите его как «ответ» на вашу проблему.
EAMann

Ответы:

91

Когда я начал этот ответ, это была просто небольшая заметка. Ну, я потерпел неудачу. Сожалею! Оставайся со мной, там в глубине души спрятано ...

Как хранятся виджеты 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.php. Класс уже T5_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!\n\nAmazing!" );

$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 будет знать, что есть несколько зарегистрированных виджетов и где хранятся аргументы для каждого виджета. А var_export()на sidebar_widgets будет выглядеть так:

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,
)

Полный код еще раз:

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!\n\nAmazing!" );
    #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сейчас, вы увидите три предустановленных виджета:

снимок экрана активных виджетов

Вот и все. Используйте ...

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

... чтобы распечатать виджеты.

Есть небольшой глюк: вы должны загрузить интерфейс два раза для первоначальной регистрации. Если кто-то может помочь здесь, я буду очень благодарен.

Фуксия
источник
Это действительно интересно ... но разве этот код не добавляет "новый" виджет при каждой загрузке страницы? Кроме того, еще один интересный вопрос заключается в том, как можно управлять этими виджетами, в том числе их содержимым из плагина, в отличие от темы (загружается раньше?)
krembo99
1
@ krembo99 Виджеты не добавляются, когда боковые панели не пусты. Код работает в плагине точно так же.
fuxia
Что widget_t5_demo_widgetотносится к здесь update_option( 'widget_t5_demo_widget', $demo_widget_content );:?
Снегопад
@SnowCrash Это просто имя опции, без ссылки на что-либо еще.
fuxia
3

Спасибо, что поделились своим решением. Я использовал то, что было описано в этом вопросе, чтобы создать фрагмент кода, который можно использовать для очень простой инициализации боковых панелей. Он очень гибкий, вы можете создавать столько виджетов, сколько захотите, без необходимости вообще изменять код. Просто используйте зацепки фильтра и передайте аргументы в массиве. Вот прокомментированный код:

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

}

А теперь инициализация виджета:

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.

Вы также можете просто скопировать этот незакомментированный код в файл функций и сразу же приступить к созданию функций фильтра: Код на pastie (без функций фильтра инициализации)

BdN3504
источник
2

Прежде всего, спасибо @toscho за подробный ответ.

Это простой пример для тех, кто ищет простое решение и параметры виджета по умолчанию:

$active_sidebars = get_option( 'sidebars_widgets' ); //get all sidebars and widgets
$widget_options = get_option( 'widget_name-1' );
$widget_options[1] = array( 'option1' => 'value', 'option2' => 'value2' );

if(isset($active_sidebars['sidebar-id']) && empty($active_sidebars['sidebar-id'])) { //check if sidebar exists and it is empty

    $active_sidebars['sidebar-id'] = array('widget_name-1'); //add a widget to sidebar
    update_option('widget_name-1', $widget_options); //update widget default options
    update_option('sidebars_widgets', $active_sidebars); //update sidebars
}

Примечание 1: Вы можете sidebar-idперейти в меню виджетов и проверить нужную боковую панель. Первый <div id="widgets-holder-wrap">«s <div>ребенок имеетsidebar-id .

Примечание 2: Вы можете widget_nameперейти в меню виджетов и проверить нужный виджет. Вы увидите что-то подобное <div id="widget-6_widget_name-__i__" class="widget ui-draggable">.

Я желаю, чтобы это помогло.

Маноло
источник
0

Вот как вы это делаете:

(ВНИМАНИЕ, это может УДАЛИТЬ все предыдущие виджеты, если вы не вернули исходные виджеты в widgetsмассив.)

    $widgets = array(
    'middle-sidebar' => array(
        'widget_name'
    ),
    'right-sidebar' => array(
        'widget2_name-1'
    )
);
update_option('sidebars_widgets', $widgets);

-Number можно использовать, если позже вы захотите добавить опции к виджету примерно так:

    update_option('widget_widget_name', array(
    1 => array(
        'title' => 'The tile',
        'number' => 4
    ),
    '_multiwidget' => 1
));
its_me
источник
1
НЕ СОБЛЮДАЙТЕ ЭТО, Я НЕ МОГУ ОЦЕНИТЬ ЭТО ВНИЗ. ВСЕ мои виджеты исчезли после использования этого кода.
EresDev
Сначала вам нужно получить массив существующих виджетов, иначе вы удалите их все, как указано выше. $widgets = get_option( 'sidebars_widgets' );
Cowgill