Adiciona widgets de forma programática a barras laterais

60

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

Eu comecei a procurar no banco de dados. Descobri que é a opção 'sidebars_widgets' que coloca widgets em barras laterais. Ao olhar para 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 corrigir isso?

    
por Marlun 22.08.2011 / 13:45
fonte

4 respostas

86

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

Como os widgets do WordPress são armazenados

A lista de widgets é armazenada em uma opção chamada 'sidebars_widgets' . Um var_export() pode dar 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ós não precisamos nos preocupar com isso.
As outras chaves são identificadores de barras laterais registradas. Neste 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 string 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 nesta opção, classificados por números.

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

Sim,dadosserializados.Não,vocênãopodeleraquelesaqui.Nãosepreocupe,vocênãoprecisa.

Umwidgetdedemonstração

Parailustrarmelhorofuncionamentointerno,escreviumwidgetdedemonstraçãomuitosimples:

/***Supersimplewidget.*/classT5_Demo_WidgetextendsWP_Widget{publicfunction__construct(){//id_base,visiblenameparent::__construct('t5_demo_widget','T5DemoWidget');}publicfunctionwidget($args,$instance){echo$args['before_widget'],wpautop($instance['text']),$args['after_widget'];}publicfunctionform($instance){$text=isset($instance['text'])?esc_textarea($instance['text']):'';printf('<textareaclass="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' é o $id_base , o identificador deste widget. Como você pode ver na 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 como você escreveu seus widgets (provavelmente), você conhece todos os argumentos da sua classe ' $instance parameters.

Noções básicas sobre temas

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, usarei uma função chamada t5_default_widget_demo() .

Todo o código a seguir entra no functions.php . A classe T5_Demo_Widget deve ser carregada já. Eu apenas coloco 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, o seu código não deve passar por cima dele. É por isso que paramos neste caso.

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

$counter = 1;

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 depois):

$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 de 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.

Isso foi fácil. Agora um widget de RSS. Mais campos, mais divertidos!

$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() isto armazenará o argumento do widget de RSS em uma opção separada. WordPress irá encontrá-los automaticamente mais tarde.
Não salvamos os argumentos do widget de demonstração porque adicionamos uma segunda instância à nossa segunda barra lateral agora…

// 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 o t5_demo_widget em uma corrida. Não é necessário atualizar a mesma opção duas vezes.

Bem, widgets suficientes para hoje, vamos salvar o sidebars_widgets també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() nos sidebar_widgets será parecido com este:

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 complete < href="https://github.com/toscho/T5-Default-Widget-Demo" title="Eu realmente espero que Chip Bennett nunca veja isso. Eu violei todos os requisitos de um tema conhecido."> código 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 para wp-admin/widgets.php , verá três widgets predefinidos:

E é isso. Use…

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

… para imprimir os widgets.

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

    
por fuxia 04.05.2012 / 04:23
fonte
3

Obrigado por compartilhar sua solução. Eu usei o que foi descrito nesta questão 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 quiser sem ter que modificar o código. Basta fazer uso dos 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á tem 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 é realmente atribuir valores. Faça uso dessas 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 de ativação de plug-in ou de tema, desta forma: Ativação do tema:

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

Ativação de 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 ligadas ao filtro 'alter_initialization_sidebars'.

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

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

    
por BdN3504 12.10.2014 / 14:25
fonte
2

Em primeiro lugar, agradecemos 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 obter sidebar-id indo para o menu de widgets e inspecionando a barra lateral desejada. O primeiro <div id="widgets-holder-wrap"> ' <div> child tem o sidebar-id .

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

Eu gostaria que isso ajudasse.

    
por Manolo 19.08.2014 / 10:59
fonte
0

É assim que você faz:

(ATENÇÃO, isso poderia REMOVER todos os widgets anteriores se você não tiver colocado os widgets originais no array widgets .)

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

O -number pode ser usado se mais tarde você quiser adicionar opções ao widget com algo parecido com isto:

    update_option('widget_widget_name', array(
    1 => array(
        'title' => 'The tile',
        'number' => 4
    ),
    '_multiwidget' => 1
));
    
por its_me 10.03.2017 / 06:25
fonte