Programmgesteuertes Hinzufügen von Widgets zu Seitenleisten

62

Ich möchte meinen beiden Seitenleisten, die ich habe, programmgesteuert Widgets hinzufügen. Ich konnte keinen offiziellen Weg finden, es zu tun?

Ich fing an, in der Datenbank zu suchen. Ich habe festgestellt, dass es die Option "sidebars_widgets" ist, mit der Widgets in die Seitenleisten eingefügt werden. Wenn Sie sich die Optionen ansehen, wird dem Widget-Namen eine Nummer wie folgt hinzugefügt: widget_name-6. Woher kommt diese Nummer?

Irgendeine Idee, wie man das behebt?

Marlun
quelle
6
Sie sollten Ihre Antwort dort unten hinzufügen, um Ihre eigene Frage zu beantworten :)
helenhousandi
In diesem Artikel finden Sie eine Übersicht über Sidebar-Widgets: justintadlock.com/archives/2010/11/08/sidebars-in-wordpress .
Joshua
Überwachen Sie den Aktionsparameter eines Ajax-Aufrufs, der beim Hinzufügen eines Widgets ausgeführt wird, und suchen Sie dann den Code für diesen Ajax-Aktions-Hook, und sehen Sie, wie er im Core ausgeführt wird. Einfach! ;)
Ashfame
5
Bitte senden Sie Ihre Lösung erneut als Antwort und akzeptieren Sie sie als "die" Antwort auf Ihr Problem.
EAMann

Antworten:

91

Als ich mit dieser Antwort anfing, sollte es nur eine kleine Notiz sein. Nun, ich habe versagt. Es tut uns leid! Bleib bei mir, es gibt eine gute Sache, die tief in mir verborgen ist ...

Wie werden WordPress-Widgets gespeichert?

Die Liste der Widgets wird in einer Option mit dem Namen gespeichert 'sidebars_widgets'. A var_export()kann so etwas wie das Folgende geben:

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

Ignorieren 'wp_inactive_widgets'und 'array_version'. Wir müssen uns nicht darum kümmern.
Die anderen Schlüssel sind Bezeichner für registrierte Seitenleisten. In diesem Fall wurden die Seitenleisten möglicherweise mit diesem Code registriert:

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

Standardmäßig sind die Seitenleisten nach der Registrierung leer. Na sicher.

Für jede registrierte Widgetklasse wird eine separate Option erstellt, die alle erforderlichen Optionen enthält. Der Option wird die Zeichenfolge vorangestellt widget_. Um die Optionen für alle aktiven RSS-Widgets zu erhalten, müssen wir uns Folgendes ansehen:

get_option( 'widget_rss' );

Mögliche Ausgabe:

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

Beachten Sie die Nummer 2 . Die Argumente für mehrere Instanzen werden in dieser einen Option nach Zahlen sortiert gespeichert.

Um zu sehen, welche Widget-Klassen WordPress bereits bekannt sind, gehen Sie zu wp-admin/options.phpund scrollen Sie nach unten, bis Sie so etwas sehen:

Screenshot der Optionen für serialisierte Widgets

Ja, serialisierte Daten. Nein, die kannst du hier nicht lesen. Mach dir keine Sorgen, du musst nicht.

Ein Demo-Widget

Um das Innenleben besser zu veranschaulichen, habe ich ein sehr einfaches Demo-Widget geschrieben:

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

Beachten Sie den Konstruktor: 't5_demo_widget'ist die $id_base, die Kennung für dieses Widget. Wie Sie im Screenshot sehen können, werden die Argumente in der Option gespeichert widget_t5_demo_widget. Alle Ihre benutzerdefinierten Widgets werden so behandelt. Sie müssen den Namen nicht erraten. Und da Sie Ihre Widgets (wahrscheinlich) geschrieben haben, kennen Sie alle Argumente aus den $instanceParametern Ihrer Klasse .

Themengrundlagen

Zuerst müssen Sie einige Seitenleisten und das benutzerdefinierte Widget registrieren. Die richtige Maßnahme dafür ist leicht zu merken: 'widgets_init'. Legen Sie alles in einen Container - eine Klasse oder eine Funktion. Der Einfachheit halber verwende ich eine Funktion namens t5_default_widget_demo().

Der gesamte folgende Code geht in das functions.php. Die Klasse T5_Demo_Widgetsollte bereits geladen sein. Ich habe es einfach in die gleiche Datei gelegt ...

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

So weit, so einfach. Unser Theme ist nun Widget-fähig, das Demo-Widget ist bekannt. Nun der Spaß.

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

Sie möchten die Benutzereinstellungen wirklich nicht zerstören. Wenn sich bereits Inhalte in den Seitenleisten befinden, sollte Ihr Code nicht darüber laufen. Deshalb hören wir in diesem Fall auf.

Okay, angenommen die Seitenleisten sind leer ... wir brauchen einen Zähler:

$counter = 1;

Widgets sind nummeriert . Diese Zahlen sind zweite Kennungen für WordPress.

Lassen Sie uns das Array ändern:

$active_widgets = get_option( 'sidebars_widgets' );

Wir brauchen auch einen Zähler (dazu später mehr):

$counter = 1;

Und hier ist, wie wir den Zähler, die Namen der Seitenleiste und die Widget-Argumente verwenden (nun, wir haben nur ein Argument:) 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++;

Beachten Sie, wie die Widget-ID erstellt wird: das id_base, ein Minus -und der Zähler. Der Inhalt des Widgets wird in einer anderen Variablen gespeichert $demo_widget_content. Hier ist der Zähler, in dem der Schlüssel und die Widget-Argumente in einem Array gespeichert sind.

Wir erhöhen den Zähler um eins, wenn wir fertig sind, um Kollisionen zu vermeiden.

Das war einfach. Jetzt ein RSS-Widget. Mehr Felder, mehr Spaß!

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

Folgendes ist neu: update_option()Dadurch wird das RSS-Widget-Argument in einer separaten Option gespeichert. WordPress findet diese später automatisch.
Wir haben die Argumente für das Demo-Widget nicht gespeichert, weil wir unserer zweiten Seitenleiste jetzt eine zweite Instanz hinzufügen ...

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

… Und speichern Sie alle Argumente für die t5_demo_widgetin einem Ansturm. Dieselbe Option muss nicht zweimal aktualisiert werden.

Nun, genug Widgets für heute, speichern wir auch die sidebars_widgets:

update_option( 'sidebars_widgets', $active_widgets );

Jetzt weiß WordPress, dass es einige registrierte Widgets gibt und wo die Argumente für jedes Widget gespeichert sind. A var_export()auf den sidebar_widgets sieht so aus:

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

Der komplette Code nochmal:

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

Wenn Sie wp-admin/widgets.phpjetzt gehen, sehen Sie drei voreingestellte Widgets:

Screenshot der aktiven Widgets

Und das ist es. Verwenden …

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

… Um die Widgets auszudrucken.

Es gibt eine kleine Panne: Sie müssen das Frontend für die Erstregistrierung zweimal laden. Wenn hier jemand helfen kann, bin ich sehr dankbar.

fuxia
quelle
Das ist wirklich interessant. Aber würde dieser Code nicht bei jedem Seitenaufruf ein "neues" Widget hinzufügen? Ein weiteres interessantes Problem ist, wie man diese Widgets, einschließlich ihres Inhalts, von einem Plugin aus steuern kann, im Gegensatz zum Thema (wird früher
geladen
1
@ krembo99 Die Widgets werden nicht hinzugefügt, wenn die Seitenleisten nicht leer sind. Der Code funktioniert in einem Plugin genauso.
Fuxia
Was bezieht widget_t5_demo_widgetsich hier auf update_option( 'widget_t5_demo_widget', $demo_widget_content );:?
Snowcrash
@SnowCrash Das ist nur ein Optionsname, kein Hinweis auf irgendetwas anderes.
fuxia
3

Vielen Dank, dass Sie Ihre Lösung geteilt haben. Ich habe das, was in dieser Frage beschrieben wurde, verwendet, um einen Code zu erstellen, mit dem Seitenleisten sehr einfach initialisiert werden können. Es ist sehr flexibel, Sie können so viele Widgets erstellen, wie Sie möchten, ohne den Code ändern zu müssen. Verwenden Sie einfach die Filter-Hooks und übergeben Sie Argumente in einem Array. Hier ist der kommentierte Code:

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

  }

}

Dies ist eine Hilfsfunktion, die prüft, ob die Seitenleiste bereits Inhalt enthält:

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;

}

Jetzt müssen wir eine Funktion erstellen, die mit der Aktion 'sidebar_init' verknüpft ist.

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

}

Und jetzt die Widget-Initialisierung:

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

  }

}

Die letzte Aktion besteht darin, die Widgets in jeder Seitenleiste zu erstellen:

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;

  }

}

Diese Funktion wird verwendet, um zu verfolgen, wie viele Instanzen eines bestimmten Widgets bereits definiert wurden:

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;

}

Das Letzte, was wir tun müssen, ist, Werte zuzuweisen. Nutzen Sie diese Filterfunktionen:

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;

}

Und:

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

}

Im Idealfall würden Sie initialize_sidebars in einer Setup-Funktion aufrufen, die beim Aktivieren des Plugins oder des Themas wie folgt aufgerufen wird:

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

Plugin Aktivierung:

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

Um die Verwendung dieses Konglomerats von Funktionen zusammenzufassen:

  1. Erstellen Sie eine Funktion, die die Seitenleisten initialisiert, die mit dem Filter 'alter_initialization_sidebars' verknüpft sind.

  2. Erstellen Sie für jede soeben hinzugefügte Seitenleiste eine Funktion, die mit dem Filter "alter_initialization_widgets_ $ sidebarname" verknüpft ist. Ersetzen Sie $ sidebarname durch den Namen jeder Seitenleiste, die Sie in Schritt 1 erstellt haben.

Sie können diesen unkommentierten Code auch einfach in Ihre Funktionsdatei kopieren und sofort mit der Erstellung Ihrer Filterfunktionen beginnen: Code auf Pastie (ohne Initialisierungsfilterfunktionen)

BdN3504
quelle
2

Zunächst einmal vielen Dank an @toscho für die ausführliche Antwort.

Dies ist ein einfaches Beispiel für diejenigen, die nach einer einfachen Lösung und Standard-Widget-Optionen suchen:

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

Hinweis 1: Sie können sidebar-idzum Widgets-Menü wechseln und die gewünschte Seitenleiste anzeigen. Das erste <div id="widgets-holder-wrap">‚s <div>Kind hat dassidebar-id .

Hinweis 2: Sie können das widget_nameMenü "Gehe zu Widgets" aufrufen und das gewünschte Widget überprüfen. Du wirst so etwas sehen <div id="widget-6_widget_name-__i__" class="widget ui-draggable">.

Ich wünschte, es hilft.

Manolo
quelle
0

Das ist wie man es macht:

(ACHTUNG, dies könnte alle vorherigen Widgets ENTFERNEN, wenn Sie die ursprünglichen Widgets nicht wieder in das widgetsArray eingefügt haben .)

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

Die -Nummer kann verwendet werden, wenn Sie dem Widget später Optionen wie folgt hinzufügen möchten:

    update_option('widget_widget_name', array(
    1 => array(
        'title' => 'The tile',
        'number' => 4
    ),
    '_multiwidget' => 1
));
its_me
quelle
1
NICHT FOLGEN, ICH KANN DAS NICHT UNTEN BEWERTEN. ALLE MEINEN WIDGETS SIND NACH DER VERWENDUNG DIESES CODES VERSCHWUNDEN.
EresDev
Sie müssen zuerst das vorhandene Widgets-Array herunterladen, andernfalls löschen Sie alle Widgets wie im obigen Kommentar angegeben. $widgets = get_option( 'sidebars_widgets' );
Cowgill