Support » Plugins » Hacks » Adding widgets to sidebar programmatically

  • Resolved edtiley

    (@edtiley)


    I’m trying to add a registered widget to a sidebar programatically.

    The idea is to get the current list of active widgets from using get_option(‘sidebar_widgets’) then add an element to the array for the main sidebar, and use update_options() to write the new value to sidebar_widgets. In pseudo-code:
    `
    $sb = ‘sidebar-1’; // the sidebar id to place the widget into
    $widget_sets = get_option(‘sidebars_widgets’, array());

    // a foreach loop makes sure the sidebar isn’t already specified
    // if not, use array_unshift to add the widget name
    // to the sidebar in the first position
    // Since the widget has no settings it shouldn’t matter
    // what the instance number of the widget is, so append -1
    array_unshift($widget_sets[$sb],’my_neaux_widget-1′);

    update_option(‘sidebars_widgets’, $widget_sets);

    A print_r() and a manual inspection of the table with PHPmyAdmin both confirm that the sidebar_widgets array now has my_neaux_widget listed, but it doesn’t show up in the sidebar.

    What is the missing step? If you drag the widget into the sidebar manually, sidebar_widgets is exactly equal to what my code puts there.

    Is there a cache that needs to be flushed? Some other option that needs tweaking? The widgets page uses an AJAX call to instantiate the widget. What does that code do differently than update_option()?

    Thanks,
    Ed

Viewing 12 replies - 1 through 12 (of 12 total)
  • At what time is your code getting run ? Could it be that your page sidebar has already been rendered and so your addition does not get displayed.

    I thought of that which is why I moved it back to after_setup_theme which is before init or get_sidebar.

    I’m not so sure that’s it though, because I’ve gone so far as to reboot and come back to the site, and it still doesn’t show up.

    Moderator bcworkz

    (@bcworkz)

    Widgets are also maintained in some global structures. These are initiated early, so your updating options is likely after the initialization occurs. Thus you need to update these globals as well. See what the AJAX callback does in this situation for guidance on how to do this. https://developer.wordpress.org/reference/functions/wp_ajax_save_widget/#source-code

    Yes, there are globals, specifically:
    global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;

    $sidebars_widgets is empty at the time my code calls get_option for the settings.

    I need to study that link you cite, but a quick look raises a can of Pandora’s Box style worms, in that it calls wp_set_sidebars_widgets.
    Both wp_get_sidebars_widgets and wp_set_sidebar_widgets are maked in the codex as private core funtions that shouldn’t be used by developers.

    Looking at their source code shows they mostly format the array written to sidebars_widgets in wp_options. They don’t make any magical calls at that I noticed.

    I’ve got to dig deeper I guess. I’m finding the retrieve_widgets funtion interesting, but it could be a dead end.

    Sigh…

    bcworkz,

    I wrote a reply late last night, but I guess I was so tired I failed to hit the post button. The first part of the answer lay not in the AJAX module you cited, but in this article:

    http://www.wpcustoms.net/snippets/programmatically-add-widgets-to-sidebars/

    About the sixth or seventh readthrough I finally noticed that he was doing an update_option on the widget_example_name. A widget specified in sidebars_widgets, that hasn’t got matching instantiation in its own option gets ignored. So:

    if ($has_widget == 'N'){ // match the widget name instance
                              // number (my_neaux_widget-2) to
                              // the array index of the
                              // widget_ option (e.g. 2)
      array_unshift($widget_sets[$sb],'my_neaux_widget-2');
      $widg['2' ] = array ('text' => 'Inserted Widget');
      update_option( 'widget_my_neaux_widget', $widg );
      update_option('sidebars_widgets', $widget_sets);
    }

    Seemingly there is one last hurdle. (Isn’t there always?) In testing, I’m finding that changing themes somehow changes sidebars_widgets
    such that I’m getting an error in the foreach expression on some transitions. Gotta track that down.

    I won’t mark this resolved till I figure it out.

    Moderator bcworkz

    (@bcworkz)

    Ah! Thanks for the update. Good luck on that last hurdle, and may it truly be the last!

    Well, it was one and a half hurdles.

    Remember a couple days ago and Ross Mitchell asked when I was hooking the action and I said after_setup_theme? Well at that point the globals aren’t populated yet.

    It’s a good lesson in “Don’t hook an action too early either.”

    The foreach was bellyaching because on a fresh theme change it is possible for malformed array data to be returned by get_option($sidebars_widgets) Sidebars_widgets is an array of arrays, and for some reason the orphaned_widgets array is sometimes left unterminated, but it can happen to inactive_widgets as well.

    So, I moved the action hook to wp_loaded. By that time the sidebars have all been rendered properly and the newly activated theme has populated sidebars_widgets with a properly formed array. Thus the foreach in my plugin always gets a “good” array and the error warnings are banished.

    Bwaaa Ha Haa! As long as my plugin knows the sidebar_id of the target sidebar in network enabled themes, my widget is added to the sidebar on the second page served up after any theme change.

    The only thing unresolved is that I’m really REALLY curious as to why wp_get_sidebars_widgets and wp_set_sidebar_widgets are marked in the codex as private core funtions that shouldn’t be used by developers.

    That’s probably a new & different thread.

    Moderator bcworkz

    (@bcworkz)

    Good work getting this all resolved!

    The private functions issue is a bit off topic, but since you brought it up, I seem to keep running up against private functions and properties all the time, it can get very frustrating! Being a self-taught coder, I miss out on a lot of the “why” behind certain practices. I end up making up my own reasons in an attempt to understand something. What follows is one of my speculations, FWIW.

    I think it’s largely a matter of principle to declare everything private by default. Then the developer thinks “How will other coders interact with my class?” The methods and properties needed to do this interaction are changed to public, everything else remains private. Then people like us come along and want to use a class in a way the developer never intended, running into private road blocks at each turn.

    I know the functions you mentioned are not in a class, but the logic is seen more in classes, and the private declaration is a real hindrance there. Public functions, in a class or not, do require putting more thought into validating passed parameters and ensuring stable, safe operation, so defaulting to private does make sense, but it can be crazy making for us creative coders.

    So to answer your question about private widget functions, it’s probably just because no one thought anyone else would or should want to use those functions.

    Whoa, whoa, whoa! It’s not off topic at all. I mentioned this a couple of days ago when you sent me the AJAX link. See my message that starts: “Yes, there are globals…”

    I’m not talking about scopes of funtions inside or outside of classes. I’m talking about the codex says not to use wp_get_sidebars_widgets and wp_set_sidebar_widgets because they are “private” functions to be used by core. See: http://codex.wordpress.org/Function_Reference/wp_set_sidebars_widgets

    In fact, these functions ARE in the WP_Widget_Factory class (/wp-includes/widgets.php) and both are technically PUBLIC functions since they aren’t declared PRIVATE in the source code. They are marked in commenting as /* Internal Functions */

    The source code (around line 1392) is pretty simple and clear, doesn’t involve voodoo internals or anything like that.

    I’d like an answer to why they are taboo as they potentially could have made by job a lot easier.

    Moderator bcworkz

    (@bcworkz)

    Yes, I realize the functions are not truly private, that they are merely commented to be for internal use. It’s my belief that the reason for this is exactly the same as for declaring class methods as private. I made a leap in reasoning with no warning or explanation. My bad.

    It takes extra effort to develop functions intended to be used by third party coders, many of whom have no business coding anything. The functionality of the site and the integrity of the data needs to be protected to the extent possible.

    If I were a core developer, I’d want to avoid all that extra error trapping etc. code for functions I can’t imagine anyone really needing to use. Much easier to add a comment “for internal use” than to try and anticipate what stupid things sub-standard coders might try to do.

    Naturally there is a disconnect between what functions core developers think we want to use and the ones we actually want to use. This all remains pure speculation on my part. I cannot hope to truly understand the actual reasoning used by core developers.

    site and the integrity of the data needs to be protected to the extent possible.

    There we must agree to disagree. If security is the issue, then the function should be declared as PRIVATE and you couldn’t get to it outside the Widget_Factory class.

    Just telling programmers not to use something is an open invitation to get on it. Sort of like the current trend to use WP_List despite the documentation telling you not to.

    Anyhow, thanks again for your encouragement. Onward to building Dashboard Widgets! YeeHaw!

    Moderator bcworkz

    (@bcworkz)

    Thank you for documenting your voyage of discovery 🙂 At least dashboard widgets are much more in the realm of “normal” plugin development.

    FWIW, I do agree with you. Just because I try to explain the reasoning behind something observed doesn’t mean I agree with that reasoning. Not that I mind a good argument…

Viewing 12 replies - 1 through 12 (of 12 total)
  • The topic ‘Adding widgets to sidebar programmatically’ is closed to new replies.