Programowo dodawaj widżety do pasków bocznych


62

Chciałbym programowo dodać widżety do moich dwóch pasków bocznych, które mam. Nie mogłem znaleźć żadnego oficjalnego sposobu na zrobienie tego?

Zacząłem szukać w bazie danych. Odkryłem, że jest to opcja „sidebars_widgets”, która umieszcza widżety na paskach bocznych. Gdy patrzymy na opcje, nazwy widżetów mają na końcu dodany numer, taki jak: nazwa_widgetu-6. Skąd ta liczba?

Masz pomysł, jak to naprawić?


6
Powinieneś dodać tam swoją odpowiedź, aby odpowiedzieć na własne pytanie :)
helenhousandi

Świetny przegląd widżetów paska bocznego znajduje się w tym artykule: justintadlock.com/archives/2010/11/08/sidebars-in-wordpress .
Joshua

Monitoruj parametr akcji wywołania ajax wykonywanego podczas dodawania widżetu, a następnie znajdź kod związany z tą akcją hook hook i zobacz, jak odbywa się to w rdzeniu. Prosty! ;)
Ashfame,

5
Prześlij ponownie swoje rozwiązanie jako odpowiedź i zaakceptuj je jako „odpowiedź” na Twój problem.
EAMann

Odpowiedzi:


91

Kiedy zacząłem tę odpowiedź, powinna to być tylko mała uwaga. Cóż, nie udało mi się. Przepraszam! Zostań ze mną, w głębi jest ukryty skarb…

Jak są przechowywane widżety WordPress

Lista widżetów jest przechowywana w opcji o nazwie 'sidebars_widgets'. A var_export()może dać coś takiego:

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

Ignoruj 'wp_inactive_widgets'i 'array_version'. Nie musimy się tym przejmować.
Pozostałe klucze są identyfikatorem zarejestrowanych pasków bocznych. W takim przypadku paski boczne mogły zostać zarejestrowane za pomocą tego kodu:

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

Domyślnie paski boczne są puste po rejestracji. Oczywiście.

Dla każdej zarejestrowanej klasy widżetu tworzona jest osobna opcja, zawierająca wszystkie niezbędne opcje. Opcja jest poprzedzona ciągiem widget_. Aby uzyskać opcje dla wszystkich aktywnych widżetów RSS, musimy przyjrzeć się…

get_option( 'widget_rss' );

Możliwe wyjście:

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

Zwróć uwagę na liczbę 2 . Wszystkie argumenty dla wielu instancji są przechowywane w tej jednej opcji posortowanej według liczb.

Aby zobaczyć, które klasy widżetów są już znane WordPressowi, przejdź do wp-admin/options.phpi przewiń w dół, aż zobaczysz coś takiego:

zrzut ekranu z serializowanych opcji widżetów

Tak, dane serializowane. Nie, nie możesz ich tutaj przeczytać. Nie martw się, nie musisz.

Widżet demonstracyjny

Aby lepiej zilustrować wewnętrzne funkcjonowanie, napisałem bardzo prosty widżet demonstracyjny:

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

Uwaga konstruktor: 't5_demo_widget'jest $id_baseidentyfikatorem tego widgetu. Jak widać na zrzucie ekranu, jego argumenty są przechowywane w opcji widget_t5_demo_widget. Wszystkie niestandardowe widżety będą traktowane w ten sposób. Nie musisz zgadywać nazwy. A skoro masz napisane swoje widżety (prawdopodobnie) znasz wszystkie argumenty ze swoimi klasa $instanceparametrów.

Podstawy motywu

Najpierw musisz zarejestrować niektóre paski boczne i niestandardowy widget. Prawidłowe działanie tego jest łatwy do zapamiętania: 'widgets_init'. Umieść wszystko w pojemniku - klasa lub funkcja. Dla uproszczenia użyję funkcji o nazwie t5_default_widget_demo().

Cały poniższy kod przechodzi do functions.php. Klasa T5_Demo_Widgetpowinna być już załadowana. Po prostu umieściłem go w tym samym pliku…

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

Do tej pory takie proste. Nasz motyw jest teraz gotowy na widżet, widżet demo jest znany. Teraz zabawa.

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

Naprawdę nie chcesz niszczyć ustawień użytkownika. Jeśli na paskach bocznych jest już trochę treści, twój kod nie powinien na niej działać. Dlatego zatrzymujemy się w tym przypadku.

Okej, zakładając, że paski boczne są puste… potrzebujemy licznika:

$counter = 1;

Widżety są ponumerowane . Te liczby są drugim identyfikatorem WordPress.

Niech tablica to zmieni:

$active_widgets = get_option( 'sidebars_widgets' );

Potrzebujemy też licznika (więcej na ten temat później):

$counter = 1;

A oto jak używamy licznika, nazw paska bocznego i argumentów widgetu (cóż, mamy tylko jeden 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++;

Zwróć uwagę, jak tworzony jest identyfikator widżetu: id_baseminus, -licznik. Zawartość widget jest przechowywany w innej zmiennej $demo_widget_content. Oto licznik, w którym klucz i argumenty widgetu są przechowywane w tablicy.

Zwiększamy licznik o jeden, gdy skończymy, aby uniknąć kolizji.

To było łatwe. Teraz widżet RSS. Więcej pól, więcej zabawy!

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

Oto coś nowego: update_option()spowoduje to zapisanie argumentu widgetu RSS w osobnej opcji. WordPress znajdzie je automatycznie później.
Nie zapisaliśmy argumentów widżetu demonstracyjnego, ponieważ teraz dodajemy drugą instancję do naszego drugiego paska bocznego…

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

… I zachowaj wszystkie argumenty za t5_demo_widgetjednym razem. Nie trzeba dwa razy aktualizować tej samej opcji.

Cóż, wystarczy widżetów na dziś, zapiszmy sidebars_widgetsteż:

update_option( 'sidebars_widgets', $active_widgets );

Teraz WordPress będzie wiedział, że istnieją zarejestrowane widżety i gdzie przechowywane są argumenty dla każdego widżetu. A var_export()na pasku bocznym będzie wyglądać następująco:

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

Kompletny kod ponownie:

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

Jeśli przejdziesz do wp-admin/widgets.phpteraz, zobaczysz trzy wstępnie ustawione widżety:

zrzut ekranu aktywnych widżetów

I to wszystko. Posługiwać się …

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

… Aby wydrukować widżety.

Istnieje niewielka usterka: w celu wstępnej rejestracji musisz dwa razy załadować interfejs. Jeśli ktoś może tu pomóc, będę bardzo wdzięczny.


To naprawdę interesujące ... ale czy ten kod nie dodałby „nowego” widżetu przy każdym ładowaniu strony? Innym interesującym zagadnieniem jest to, w jaki sposób można kontrolować te widżety, w tym ich zawartość z wtyczki, a nie motywu (ładuje się wcześniej?)
krembo99

1
@ krembo99 Widżety nie są dodawane, gdy paski boczne nie są puste. Kod działa we wtyczce dokładnie w ten sam sposób.
fuxia

Co widget_t5_demo_widgetdotyczy tutaj update_option( 'widget_t5_demo_widget', $demo_widget_content );:?
Snowcrash

@SnowCrash To tylko nazwa opcji, bez odniesienia do niczego innego.
fuxia

3

Dziękujemy za udostępnienie rozwiązania. Użyłem tego, co zostało opisane w tym pytaniu, aby utworzyć fragment kodu, którego można użyć do bardzo łatwej inicjalizacji pasków bocznych. Jest bardzo elastyczny, możesz utworzyć tyle widżetów, ile chcesz, bez konieczności modyfikacji kodu. Wystarczy skorzystać z haków filtru i przekazać argumenty w tablicy. Oto skomentowany kod:

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

  }

}

To jest funkcja pomocnicza, która sprawdza, czy pasek boczny zawiera już zawartość:

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;

}

Teraz musimy utworzyć funkcję, która jest podpięta do akcji „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 ) );

}

A teraz inicjalizacja widgetu:

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

  }

}

Ostatnią czynnością jest utworzenie widgetów na każdym pasku bocznym:

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;

  }

}

Ta funkcja służy do śledzenia, ile wystąpień określonego widżetu zostało już zdefiniowanych:

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;

}

Ostatnią rzeczą, którą musimy zrobić, to faktycznie przypisać wartości. Skorzystaj z tych funkcji filtrów:

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;

}

I:

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

}

Idealnie byłoby wywołać initialize_sidebars w funkcji konfiguracji, która jest wywoływana po aktywacji wtyczki lub motywu w następujący sposób: Aktywacja motywu:

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

Aktywacja wtyczki:

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

Podsumowując użycie tego konglomeratu funkcji:

  1. utwórz funkcję, która inicjuje paski boczne, które są podłączone do filtra „alter_initialization_sidebars”.

  2. utwórz funkcję dla każdego właśnie dodanego paska bocznego, który jest podłączony do filtra „alter_initialization_widgets_ $ sidebarname”. Zamień $ sidebarname na nazwę każdego paska bocznego utworzonego w kroku 1.

Możesz również po prostu skopiować ten niezakomentowany kod do pliku funkcji i od razu rozpocząć tworzenie funkcji filtrowania: Kod na pastie (bez funkcji filtra inicjującego)


2

Przede wszystkim dziękuję @toscho za szczegółową odpowiedź.

To prosty przykład dla tych, którzy szukają prostego rozwiązania i domyślnych opcji widgetu:

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

Uwaga 1: Możesz przejść sidebar-iddo menu widżetów i sprawdzić pożądany pasek boczny. Pierwszy <div id="widgets-holder-wrap">„s <div>dziecko masidebar-id .

Uwaga 2: Możesz przejść widget_namedo menu widżetów i sprawdzić żądany widżet. Zobaczysz coś takiego <div id="widget-6_widget_name-__i__" class="widget ui-draggable">.

Chciałbym, żeby to pomogło.


0

Tak to się robi:

(OSTRZEŻENIE, to może USUNĄĆ wszystkie poprzednie widżety, jeśli nie włożysz oryginalnych widgetów do widgetstablicy).

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

-Numer może być użyty, jeśli później chcesz dodać opcje do widżetu za pomocą czegoś takiego:

    update_option('widget_widget_name', array(
    1 => array(
        'title' => 'The tile',
        'number' => 4
    ),
    '_multiwidget' => 1
));

1
NIE ŚLEDŹ SIĘ TEGO, NIE MOGĘ OCENIĆ TEGO W DÓŁ. WSZYSTKIE MOJE WIDŻETY ZNIKAŁY PO UŻYCIU TEGO KODU.
EresDev

Najpierw musisz pobrać istniejącą tablicę widżetów, w przeciwnym razie usuniesz je wszystkie, jak podano w powyższym komentarzu. $widgets = get_option( 'sidebars_widgets' );
cowgill
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.