Aggiungere widget alle sidebar programmaticamente
Vorrei aggiungere widget alle mie due sidebar in modo programmatico. Non sono riuscito a trovare un metodo ufficiale per farlo?
Ho iniziato a cercare nel database. Ho trovato che è l'opzione 'sidebars_widgets' che posiziona i widget nelle sidebar. Guardando le opzioni, i nomi dei widget hanno un numero aggiunto alla fine, come: widget_name-6. Da dove viene questo numero?
Qualche idea su come risolvere questo problema?
Quando ho iniziato questa risposta doveva essere solo una piccola nota. Beh, ho fallito. Scusate! Seguitemi, c'è una sorpresa nascosta in fondo...
Come vengono memorizzati i widget di WordPress
L'elenco dei widget è memorizzato in un'opzione chiamata 'sidebars_widgets'
. Un var_export()
potrebbe restituire qualcosa come:
array (
'wp_inactive_widgets' =>
array (
),
'top-widget' =>
array (
),
'bottom-widget' =>
array (
),
'array_version' => 3,
)
Ignorate 'wp_inactive_widgets'
e 'array_version'
. Non dobbiamo preoccuparci di questi.
Le altre chiavi sono identificatori per le sidebar registrate. In questo caso le sidebar potrebbero essere state registrate con questo codice:
// Registra due sidebar.
$sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
foreach ( $sidebars as $sidebar )
{
register_sidebar(
array (
'name' => $sidebar,
'id' => $sidebar,
'before_widget' => '',
'after_widget' => ''
)
);
}
Per impostazione predefinita le sidebar sono vuote dopo la registrazione. Ovviamente.
Per ogni classe di widget registrata viene creata un'opzione separata, contenente tutte le opzioni necessarie. L'opzione è prefissata dalla stringa widget_
. Per ottenere le opzioni di tutti i widget RSS attivi dobbiamo guardare in...
get_option( 'widget_rss' );
Possibile output:
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,
),
)
Notate il numero 2. Gli argomenti per più istanze sono tutti memorizzati in questa unica opzione ordinata per numeri.
Per vedere quali classi di widget sono già note a WordPress andate su wp-admin/options.php
e scorrete fino a vedere qualcosa come:
Sì, dati serializzati. No, non potete leggerli qui. Non preoccupatevi, non è necessario.
Un widget dimostrativo
Per illustrare meglio il funzionamento interno ho scritto un widget dimostrativo molto semplice:
/**
* Widget super semplice.
*/
class T5_Demo_Widget extends WP_Widget
{
public function __construct()
{ // id_base , nome visibile
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
);
}
}
Notate il costruttore: 't5_demo_widget'
è l'$id_base
, l'identificatore per questo widget. Come potete vedere nello screenshot i suoi argomenti sono memorizzati nell'opzione widget_t5_demo_widget
. Tutti i vostri widget personalizzati saranno trattati allo stesso modo. Non dovete indovinare il nome. E dato che voi avete scritto i vostri widget (probabilmente) conoscete tutti gli argomenti dai parametri $instance
della vostra classe.
Basi del tema
Per prima cosa dovete registrare alcune sidebar e il widget personalizzato. L'azione corretta per questo è facile da ricordare: 'widgets_init'
. Mettete tutto in un contenitore - una classe o una funzione. Per semplicità userò una funzione chiamata t5_default_widget_demo()
.
Tutto il codice seguente va nel functions.php
. La classe T5_Demo_Widget
dovrebbe essere già caricata. L'ho semplicemente messa nello stesso file...
add_action( 'widgets_init', 't5_default_widget_demo' );
function t5_default_widget_demo()
{
// Registra il nostro widget.
register_widget( 'T5_Demo_Widget' );
// Registra due sidebar.
$sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
foreach ( $sidebars as $sidebar )
{
register_sidebar(
array (
'name' => $sidebar,
'id' => $sidebar,
'before_widget' => '',
'after_widget' => ''
)
);
}
Fin qui tutto semplice. Il nostro tema è ora pronto per i widget, il widget dimostrativo è noto. Ora il divertimento.
$active_widgets = get_option( 'sidebars_widgets' );
if ( ! empty ( $active_widgets[ $sidebars['a'] ] )
or ! empty ( $active_widgets[ $sidebars['b'] ] )
)
{ // Ok, niente più divertimento. C'è già del contenuto.
return;
}
Non volete davvero distruggere le impostazioni dell'utente. Se c'è già del contenuto nelle sidebar il vostro codice non dovrebbe sovrascriverlo. Ecco perché ci fermiamo in questo caso.
Ok, supponendo che le sidebar siano vuote... abbiamo bisogno di un contatore:
$counter = 1;
I widget sono numerati. Questi numeri sono secondi identificatori per WordPress.
Prendiamo l'array per modificarlo:
$active_widgets = get_option( 'sidebars_widgets' );
Abbiamo bisogno anche di un contatore (ne parleremo più avanti):
$counter = 1;
Ed ecco come usiamo il contatore, i nomi delle sidebar e gli argomenti del widget (beh, abbiamo solo un argomento: text
).
// Aggiunge un widget 'demo' alla sidebar superiore...
$active_widgets[ $sidebars['a'] ][0] = 't5_demo_widget-' . $counter;
// ... e scrive del testo al suo interno:
$demo_widget_content[ $counter ] = array ( 'text' => "Funziona!\n\nIncredibile!" );
$counter++;
Notate come viene creato l'identificatore del widget: l'id_base
, un trattino -
e il contatore. Il contenuto del widget è memorizzato in un'altra variabile $demo_widget_content
. Qui il contatore è la chiave e gli argomenti del widget sono memorizzati in un array.
Incrementiamo il contatore di uno quando abbiamo finito per evitare collisioni.
Era facile. Ora un widget RSS. Più campi, più divertimento!
$active_widgets[ $sidebars['a'] ][] = 'rss-' . $counter;
// Le ultime 15 domande da 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++;
Ecco qualcosa di nuovo: update_option()
questo memorizzerà gli argomenti del widget RSS in un'opzione separata. WordPress li troverà automaticamente più tardi.
Non abbiamo salvato gli argomenti del widget dimostrativo perché aggiungiamo una seconda istanza alla nostra seconda sidebar ora...
// Ok, ora alla nostra seconda sidebar. Facciamola breve.
$active_widgets[ $sidebars['b'] ][] = 't5_demo_widget-' . $counter;
#$demo_widget_content = get_option( 'widget_t5_demo_widget', array() );
$demo_widget_content[ $counter ] = array ( 'text' => 'La seconda istanza del nostro fantastico widget dimostrativo.' );
update_option( 'widget_t5_demo_widget', $demo_widget_content );
... e salviamo tutti gli argomenti per t5_demo_widget
in un colpo solo. Non è necessario aggiornare la stessa opzione due volte.
Bene, abbastanza widget per oggi, salviamo anche sidebars_widgets
:
update_option( 'sidebars_widgets', $active_widgets );
Ora WordPress saprà che ci sono alcuni widget registrati e dove sono memorizzati gli argomenti per ogni widget. Un var_export()
su sidebar_widgets apparirà così:
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,
)
Ecco il codice completo di nuovo:
add_action( 'widgets_init', 't5_default_widget_demo' );
function t5_default_widget_demo()
{
// Registra il nostro widget.
register_widget( 'T5_Demo_Widget' );
// Registra due sidebar.
$sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
foreach ( $sidebars as $sidebar )
{
register_sidebar(
array (
'name' => $sidebar,
'id' => $sidebar,
'before_widget' => '',
'after_widget' => ''
)
);
}
// Ok, ora la parte divertente.
// Non vogliamo annullare le modifiche dell'utente, quindi cerchiamo prima le modifiche.
$active_widgets = get_option( 'sidebars_widgets' );
if ( ! empty ( $active_widgets[ $sidebars['a'] ] )
or ! empty ( $active_widgets[ $sidebars['b'] ] )
)
{ // Ok, niente più divertimento. C'è già del contenuto.
return;
}
// Le sidebar sono vuote, inseriamo qualcosa al loro interno.
// Che ne dite di un widget RSS e due istanze del nostro widget dimostrativo?
// Notate che i widget sono numerati. Abbiamo bisogno di un contatore:
$counter = 1;
// Aggiunge un widget 'demo' alla sidebar superiore...
$active_widgets[ $sidebars['a'] ][0] = 't5_demo_widget-' . $counter;
// ... e scrive del testo al suo interno:
$demo_widget_content[ $counter ] = array ( 'text' => "Funziona!\n\nIncredibile!" );
#update_option( 'widget_t5_demo_widget', $demo_widget_content );
$counter++;
// Era facile. Ora un widget RSS. Più campi, più divertimento!
$active_widgets[ $sidebars['a'] ][] = 'rss-' . $counter;
// Le ultime 15 domande da 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++;
// Ok, ora alla nostra seconda sidebar. Facciamola breve.
$active_widgets[ $sidebars['b'] ][] = 't5_demo_widget-' . $counter;
#$demo_widget_content = get_option( 'widget_t5_demo_widget', array() );
$demo_widget_content[ $counter ] = array ( 'text' => 'La seconda istanza del nostro fantastico widget dimostrativo.' );
update_option( 'widget_t5_demo_widget', $demo_widget_content );
// Ora salva l'array $active_widgets.
update_option( 'sidebars_widgets', $active_widgets );
}
Se andate su wp-admin/widgets.php
ora vedrete tre widget preimpostati:
E questo è tutto. Usate...
dynamic_sidebar( 'top-widget' );
dynamic_sidebar( 'bottom-widget' );
... per visualizzare i widget.
C'è un piccolo problema: dovete caricare il front-end due volte per la registrazione iniziale. Se qualcuno può aiutare qui sarò molto grato.

Questo è davvero interessante... ma questo codice non aggiungerebbe un widget "nuovo" ad ogni caricamento di pagina? Inoltre, un altro aspetto interessante è come si possono controllare quei widget, incluso il loro contenuto, all'interno di un plugin invece che nel tema (che si carica prima?).

@krembo99 I widget non vengono aggiunti quando le sidebar non sono vuote. Il codice funziona esattamente allo stesso modo in un plugin.

A cosa si riferisce widget_t5_demo_widget
qui: update_option( 'widget_t5_demo_widget', $demo_widget_content );
?

Ho trovato questa risposta informativa per capire come i dati vengono memorizzati/utilizzati. Poi mi piace quest'altra risposta per un esempio pratico di codice: https://wordpress.stackexchange.com/a/138248/27896

Grazie per aver condiviso la tua soluzione. Ho utilizzato quanto descritto in questa domanda per creare un pezzo di codice che può essere utilizzato per inizializzare le sidebar in modo molto semplice. È molto flessibile, puoi creare quanti widget vuoi senza dover modificare il codice. Basta utilizzare i filtri hook e passare gli argomenti in un array. Ecco il codice commentato:
function initialize_sidebars(){
$sidebars = array();
// Fornisci le sidebar che vuoi inizializzare in un filtro
$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;
// passiamo i nostri argomenti come riferimento, così possiamo modificarne il contenuto
do_action( 'your_plugin_sidebar_init', array( &$args ) );
}
// dobbiamo aggiornare le sidebar solo se non sono ancora state inizializzate
// e abbiamo anche dati con cui inizializzare le sidebar
if ( ! empty( $args['update_widget_content'] ) {
foreach ( $args['update_widget_content'] as $widget => $widget_occurence ) {
// l'array update_widget_content memorizza tutte le istanze di ogni widget
update_option( 'widget_' . $widget, $args['update_widget_content'][ $widget ] );
}
// dopo aver aggiornato tutti i widget, aggiorniamo l'array active_widgets
update_option( 'sidebars_widgets', $args['active_widgets'] );
}
}
Questa è una funzione helper che verifica se la sidebar ha già contenuto:
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;
}
Ora dobbiamo creare una funzione agganciata all'azione 'sidebar_init'.
add_action( 'your_plugin_sidebar_init', 'add_widgets_to_sidebar' );
function add_widgets_to_sidebar( $args ) {
extract( $args[0] );
// Verifichiamo se la sidebar corrente ha già contenuto e in tal caso usciamo
$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 ora l'inizializzazione dei widget:
add_action( 'your_plugin_widget_init', 'your_plugin_initialize_widgets' );
function your_plugin_initialize_widgets( $args ) {
extract( $args[0][0] );
$widgets = array();
// Qui i widget precedentemente definiti nelle funzioni di filtro vengono inizializzati,
// ma solo quelli corrispondenti alla sidebar corrente
$widgets = apply_filters( 'alter_initialization_widgets_' . $current_sidebar_short_name, $widgets );
if ( ! empty( $widgets ) ) {
do_action( 'create_widgets_for_sidebar', array( &$args ), $widgets );
}
}
L'ultima azione è creare i widget in ogni sidebar:
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 ) {
// Il contatore viene incrementato per ogni widget. Ad esempio, se avessi tre widget,
// due dei quali widget archivio e uno un widget personalizzato, allora il
// contatore corretto aggiunto a ognuno sarebbe archive-1, archive-2 e custom-1.
// Quindi il contatore del widget non è globale ma conta le istanze (le
// occorrenze del widget come le ho chiamate) di ogni widget.
$counter = count_widget_occurence( $widget, $args[0][0][0]['update_widget_content'] );
// Aggiungiamo ogni istanza ai widget attivi...
$args[0][0][0]['active_widgets'][ $sidebars[ $current_sidebar_short_name ] ][] = $widget . '-' . $counter;
// ...e salviamo anche il contenuto in un altro array associativo.
$args[0][0][0]['update_widget_content'][ $widget ][ $counter ] = $widget_content;
}
}
Questa funzione viene utilizzata per tenere traccia di quante istanze di un widget specifico sono già state definite:
function count_widget_occurence( $widget, $update_widget_content ) {
$widget_occurrence = 0;
// Guardiamo l'array update_widget_content che memorizza ogni
// istanza del widget corrente con il contatore corrente in un
// array associativo. La chiave di questo array è il nome del
// widget corrente.
// Avere tre widget archivio ad esempio sarebbe così:
// '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;
}
L'ultima cosa da fare è assegnare i valori effettivi. Utilizza queste funzioni di filtro:
add_filter( 'alter_initialization_sidebars', 'current_initialization_sidebars' ) ;
// Usa questo filtro per specificare quali sidebar vuoi inizializzare
function current_initialization_sidebars( $sidebars ) {
// Le sidebar vengono assegnate in questo modo.
// La chiave dell'array è molto importante perché viene utilizzata come suffisso nella funzione di inizializzazione
// per ogni sidebar. Il valore è ciò che viene utilizzato negli attributi html.
$sidebars['info'] = 'info-sidebar';
return $sidebars;
}
E:
add_filter( 'alter_initialization_widgets_info', 'current_info_widgets' );
// Aggiungi un filtro per ogni sidebar che hai. Il nome dell'hook deriva dalle
// chiavi dell'array passate nel filtro alter_initialization_sidebars.
// Ogni filtro ha un nome 'alter_initialization_widgets_' con la chiave
// dell'array aggiunta alla fine.
function current_info_widgets( $widgets ) {
// Questa funzione di filtro viene utilizzata per aggiungere widget alla sidebar info. Aggiungi ogni widget
// che vuoi assegnare a questa sidebar in un array.
return $widgets = array(
// Usa il nome del widget come specificato nella chiamata al costruttore WP_Widget
// come chiave dell'array.
// Il widget archivio è un widget incluso di default in WordPress.
// Gli argomenti utilizzati da questo widget, come tutti gli altri widget predefiniti, possono essere trovati
// in wp-includes/default-widgets.php.
'archives' => array(
// Passa le opzioni dell'array come array
'title' => 'Contenuti vecchi',
'dropdown' => 'on',
// Il valore 'on' è scelto arbitrariamente, il widget in realtà controlla solo
// un valore non vuoto per entrambe queste opzioni
'count' => 'on',
),
);
}
Idealmente dovresti chiamare initialize_sidebars in una funzione di setup che viene chiamata all'attivazione del plugin o del tema in questo modo: Attivazione tema:
add_action( 'after_switch_theme', 'my_activation_function' );
function my_activation_function() {
initialize_sidebars();
}
Attivazione plugin:
register_activation_hook( __FILE__, 'my_activation_function' );
function my_activation_function() {
initialize_sidebars();
}
Per riassumere l'utilizzo di questo insieme di funzioni:
crea una funzione che inizializza le sidebar agganciata al filtro 'alter_initialization_sidebars'.
crea una funzione per ogni sidebar che hai appena aggiunto agganciata al filtro 'alter_initialization_widgets_$nomesidebar'. Sostituisci $nomesidebar con il nome di ogni sidebar creata nel passo 1.
Puoi anche semplicemente copiare questo codice non commentato nel tuo file functions e iniziare subito a creare le tue funzioni di filtro: Codice su pastie (senza funzioni di filtro di inizializzazione)

Prima di tutto, grazie a @toscho per la risposta dettagliata.
Questo è un semplice esempio per coloro che cercano una soluzione semplice e le opzioni predefinite dei widget:
$active_sidebars = get_option( 'sidebars_widgets' ); //ottiene tutte le sidebar e i widget
$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'])) { //verifica se la sidebar esiste ed è vuota
$active_sidebars['sidebar-id'] = array('widget_name-1'); //aggiunge un widget alla sidebar
update_option('widget_name-1', $widget_options); //aggiorna le opzioni predefinite del widget
update_option('sidebars_widgets', $active_sidebars); //aggiorna le sidebar
}
Nota 1: Puoi ottenere il sidebar-id
andando nel menu dei widget e ispezionando la sidebar desiderata. Il primo elemento figlio <div>
di <div id="widgets-holder-wrap">
contiene il sidebar-id
.
Nota 2: Puoi ottenere il widget_name
andando nel menu dei widget e ispezionando il widget desiderato. Vedrai qualcosa come <div id="widget-6_widget_name-__i__" class="widget ui-draggable">
.
Spero che possa essere utile.

Ecco come fare:
(ATTENZIONE, questo potrebbe RIMUOVERE tutti i widget precedenti se non hai reinserito i widget originali nell'array widgets
.)
$widgets = array(
'middle-sidebar' => array(
'widget_name'
),
'right-sidebar' => array(
'widget2_name-1'
)
);
update_option('sidebars_widgets', $widgets);
Il numero (-number) può essere utilizzato se in seguito desideri aggiungere opzioni al widget con qualcosa del genere:
update_option('widget_widget_name', array(
1 => array(
'title' => 'Il titolo',
'number' => 4
),
'_multiwidget' => 1
));

NON SEGUIRE QUESTO, NON POSSO VALUTARLO NEGATIVAMENTE. TUTTI I MIEI WIDGET SONO SCOMPARSI DOPO AVER USATO QUESTO CODICE.
