Adicionar programaticamente widgets às barras laterais

62

Gostaria de adicionar programaticamente widgets às minhas duas barras laterais que tenho. Não consegui encontrar nenhuma maneira oficial de fazer isso?

Comecei a procurar no banco de dados. Eu descobri que é a opção 'sidebars_widgets' que coloca widgets nas barras laterais. Ao examinar as opções, os nomes dos widgets têm um número adicionado ao final, como: widget_name-6. De onde vem esse número?

Alguma ideia de como consertar isso?

Marlun
fonte
6
Você deve adicionar a sua resposta lá para responder à sua própria pergunta :)
helenhousandi
Para um ótimo resumo dos widgets da barra lateral, consulte este artigo: justintadlock.com/archives/2010/11/08/sidebars-in-wordpress .
21711 Joshua
Monitore o parâmetro de ação da chamada ajax que é feita quando um widget é adicionado e, em seguida, encontre o código relacionado ao gancho ajax da ação e veja como isso é feito no núcleo. Simples! ;)
Ashfame
5
Volte a postar sua solução como resposta e aceite-a como "a" resposta ao seu problema.
EAMann #

Respostas:

91

Quando comecei esta resposta, deveria ser apenas uma pequena nota. Bem, eu falhei. Desculpa! Fique comigo, há um broche escondido no fundo…

Como os widgets do WordPress são armazenados

A lista de widget é armazenado em uma opção chamada 'sidebars_widgets'. A var_export()pode fornecer algo como o seguinte:

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

Ignore 'wp_inactive_widgets'e 'array_version'. Não precisamos nos preocupar com isso.
As outras chaves são identificadoras de barras laterais registradas. Nesse caso, as barras laterais podem ter sido registradas com este código:

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

Por padrão, as barras laterais estão vazias após o registro. Claro.

Para cada classe de widget registrada, uma opção separada é criada, contendo todas as opções necessárias. A opção é prefixada pela sequência widget_. Para obter as opções para todos os widgets RSS ativos, precisamos analisar…

get_option( 'widget_rss' );

Saída possível:

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

Anote o número 2 . Os argumentos para várias instâncias são todos armazenados nessa opção, ordenada por números.

Para ver quais classes de widgets já são conhecidas pelo WordPress, vá wp-admin/options.phpe role para baixo até ver algo assim:

captura de tela das opções de widgets serializados

Sim, dados serializados. Não, você não pode ler esses aqui. Não se preocupe, você não precisa.

Um widget de demonstração

Para ilustrar melhor o funcionamento interno, escrevi um widget de demonstração muito simples:

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

Observe o construtor: 't5_demo_widget'é $id_baseo identificador para este widget. Como você pode ver na captura de tela seus argumentos são armazenados na opção widget_t5_demo_widget. Todos os seus widgets personalizados serão tratados assim. Você não precisa adivinhar o nome. E desde que você escreveu seus widgets (provavelmente), você conhece todos os argumentos dos parâmetros da sua classe $instance.

Noções básicas de tema

Primeiro, você precisa registrar algumas barras laterais e o widget personalizado. A ação adequada para isso é fácil de lembrar: 'widgets_init'. Coloque tudo em um contêiner - uma classe ou uma função. Para simplificar eu vou usar uma função chamada t5_default_widget_demo().

Todo o código a seguir entra no functions.php. A classe T5_Demo_Widgetjá deve estar carregada. Eu apenas coloquei no mesmo arquivo ...

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

Até agora, tão simples. Nosso tema agora está pronto para o widget, o widget de demonstração é conhecido. Agora a diversão.

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

Você realmente não quer destruir as configurações do usuário. Se já houver algum conteúdo nas barras laterais, seu código não deve ser executado sobre ele. É por isso que paramos neste caso.

Ok, assumimos que as barras laterais estão vazias ... precisamos de um contador:

$counter = 1;

Os widgets são numerados . Esses números são segundos identificadores para o WordPress.

Vamos fazer com que o array mude:

$active_widgets = get_option( 'sidebars_widgets' );

Também precisamos de um contador (mais sobre isso mais tarde):

$counter = 1;

E aqui está como usamos o contador, os nomes da barra lateral e os argumentos do widget (bem, temos apenas um argumento:) 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++;

Observe como o identificador do widget é criado: o id_base, um menos -e o contador. O conteúdo do widget é armazenado em outra variável $demo_widget_content. Aqui está o contador da chave e os argumentos do widget são armazenados em uma matriz.

Aumentamos o contador em um quando terminamos para evitar colisões.

Essa foi fácil. Agora um widget de RSS. Mais campos, mais diversão!

$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++;

Aqui está algo novo: update_option()isso armazenará o argumento do widget RSS em uma opção separada. O WordPress os encontrará automaticamente mais tarde.
Não salvamos os argumentos do widget de demonstração porque agora adicionamos uma segunda instância à nossa segunda barra lateral…

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

… E salve todos os argumentos para t5_demo_widgetuma corrida. Não há necessidade de atualizar a mesma opção duas vezes.

Bem, widgets suficientes para hoje, vamos salvar sidebars_widgetstambém:

update_option( 'sidebars_widgets', $active_widgets );

Agora, o WordPress saberá que existem alguns widgets registrados e onde os argumentos para cada widget são armazenados. Um var_export()na sidebar_widgets ficará assim:

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

O código completo novamente:

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

Se você for wp-admin/widgets.phpagora, verá três widgets predefinidos:

captura de tela de widgets ativos

E é isso. Usar …

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

… Para imprimir os widgets.

Há uma pequena falha: você precisa carregar o front-end duas vezes para o registro inicial. Se alguém puder ajudar aqui, ficarei muito grato.

fuxia
fonte
Isso é realmente interessante .. mas esse código não adicionaria um widget "novo" a cada carregamento da página `? Além disso, outra questão interessante é como se pode controlar esses widgets, incluindo o seu conteúdo a partir de dentro de um plug-in em oposição ao tema (cargas mais cedo?)
krembo99
1
@ krembo99 Os widgets não são adicionados quando as barras laterais não estão vazias. O código funciona em um plugin exatamente da mesma maneira.
fuxia
O que se widget_t5_demo_widgetrefere aqui update_option( 'widget_t5_demo_widget', $demo_widget_content );:?
Snowcrash
@SnowCrash Esse é apenas o nome de uma opção, sem referência a mais nada.
fuxia
3

Obrigado por compartilhar sua solução. Eu usei o que foi descrito nesta pergunta para criar um pedaço de código que pode ser usado para inicializar barras laterais com muita facilidade. É muito flexível, você pode criar quantos widgets desejar, sem precisar modificar o código. Basta usar os ganchos de filtro e passar argumentos em uma matriz. Aqui está o código comentado:

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

  }

}

Esta é uma função auxiliar que verifica se a barra lateral já possui conteúdo:

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;

}

Agora precisamos criar uma função que esteja conectada à ação '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 ) );

}

E agora a inicialização do 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 );

  }

}

A última ação é criar os widgets em cada barra lateral:

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;

  }

}

Esta função é usada para acompanhar quantas instâncias de um widget específico já foram definidas:

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;

}

A última coisa que precisamos fazer é atribuir valores. Utilize estas funções de filtro:

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;

}

E:

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

}

Idealmente, você chamaria initialize_sidebars em uma função de configuração chamada após a ativação do plug-in ou do tema, assim: Ativação do tema:

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

Ativação do plug-in:

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

Para resumir o uso desse conglomerado de funções:

  1. crie uma função que inicialize as barras laterais conectadas ao filtro 'alter_initialization_sidebars'.

  2. crie uma função para cada barra lateral que você acabou de adicionar, conectada ao filtro 'alter_initialization_widgets_ $ sidebarname'. Substitua $ sidebarname pelo nome de cada barra lateral criada na etapa 1.

Você também pode simplesmente copiar esse código não comentado no seu arquivo de funções e começar a criar suas funções de filtro imediatamente: Código em Pastie (sem funções de filtro de inicialização)

BdN3504
fonte
2

Antes de tudo, obrigado a @toscho pela resposta detalhada.

Este é um exemplo simples para quem está procurando uma solução simples e opções de widget padrão:

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

Nota 1: Você pode sidebar-idacessar o menu de widgets e inspecionar a barra lateral desejada. O primeiro <div id="widgets-holder-wrap">'s <div>criança temsidebar-id .

Nota 2: Você pode widget_nameacessar o menu de widgets e inspecionar o widget desejado. Você verá algo como <div id="widget-6_widget_name-__i__" class="widget ui-draggable">.

Eu desejo que ajude.

Manolo
fonte
0

É assim que se faz:

(AVISO, isso poderá REMOVER todos os widgets anteriores, se você não colocar os widgets originais de volta na widgetsmatriz.)

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

O número-pode ser usado se você desejar adicionar opções ao widget posteriormente com algo como isto:

    update_option('widget_widget_name', array(
    1 => array(
        'title' => 'The tile',
        'number' => 4
    ),
    '_multiwidget' => 1
));
its_me
fonte
1
NÃO SIGA ISSO, NÃO POSSO AVALIAR ISSO. TODOS OS MEUS WIDGETS DESAPARECERAM DEPOIS DE USAR ESTE CÓDIGO.
EresDev
Você precisa obter a matriz de widgets existente primeiro, caso contrário, todas elas serão apagadas como o comentário acima. $widgets = get_option( 'sidebars_widgets' );
Cowgill