Aggiungere widget alle sidebar programmaticamente

22 ago 2011, 14:45:35
Visualizzazioni: 39.3K
Voti: 71

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?

5
Commenti

Dovresti aggiungere la tua risposta qui sotto per rispondere alla tua domanda :)

helenhousandi helenhousandi
22 ago 2011 18:28:54

Per una grande panoramica sui widget della sidebar, dai un'occhiata a questo articolo: http://justintadlock.com/archives/2010/11/08/sidebars-in-wordpress.

Joshua Joshua
22 ago 2011 18:58:07

Monitora il parametro action della chiamata ajax che viene effettuata quando viene aggiunto un widget, poi trova il codice relativo a quell'hook ajax dell'action e vedi come è implementato nel core. Semplice! ;)

Ashfame Ashfame
10 apr 2012 00:50:44

Per favore, ripubblica la tua soluzione come risposta e accettala come "la" risposta al tuo problema.

EAMann EAMann
12 apr 2012 00:52:54
Tutte le risposte alla domanda 4
5
102

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:

screenshot delle opzioni serializzate dei widget

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:

screenshot dei widget attivi

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.

4 mag 2012 05:23:58
Commenti

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 krembo99
3 ago 2013 11:36:39

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

fuxia fuxia
3 ago 2013 14:46:10

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

Snowcrash Snowcrash
16 ott 2015 18:29:01

@SnowCrash È solo il nome di un'opzione, senza riferimenti ad altro.

fuxia fuxia
16 ott 2015 18:37:35

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

Tyler Collier Tyler Collier
29 set 2020 00:13:23
0

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:

  1. crea una funzione che inizializza le sidebar agganciata al filtro 'alter_initialization_sidebars'.

  2. 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)

12 ott 2014 15:25:38
0

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.

19 ago 2014 11:59:19
2

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
));
4 mag 2012 05:13:41
Commenti

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

EresDev EresDev
12 lug 2014 02:34:58

Devi prima ottenere l'array dei widget esistenti, altrimenti li cancellerai tutti come indicato nel commento precedente. $widgets = get_option( 'sidebars_widgets' );

cowgill cowgill
11 nov 2016 12:03:20