Update widget form after drag-and-drop (WP save bug)

I’ve posted a bug-report about this a few months ago (on WordPress trac (Widget Instance Form Update Bug)) and I thought I’d try writing about it here too. Maybe someone has a better solution to this issue than me.

Basically the problem is that if you drop a widget into a sidebar, the widget form doesn’t get updated until you manually press save (or reload the page).

This makes unusable all the code from the form() function that relies on the widget instance ID to do something (until you press the save button). Any stuff like ajax requests, jQuery things like colorpickers and so on will not work right away, because from that function it would appear that the widget instance has not yet been initialized.

A dirty fix would be to trigger the save button automatically using something like livequery:

$("#widgets-right .needfix").livequery(function(){
  var widget = $(this).closest('div.widget');
  wpWidgets.save(widget, 0, 1, 0);
  return false;
});

and add the .needfix class in form() if the widget instance doesn’t look initialized:

 <div <?php if(!is_numeric($this->number)): ?>class="needfix"<?php endif; ?>
   ...
 </div>

One drawback of this solution is that if you have lots of widgets registered, the browser will eat lots of CPU, because livequery checks for DOM changes every second (tho I didn’t specifically test this, it’s just my assumption 🙂

Any suggestions for a better way to fix the bug?

4

I did battle with a similar situation recently. Ajax in widgets is no joke! Need to write some pretty crazy code to get things to work across instances. I’m not familiar with live query, but if you say it checks the DOM every second, I might have a less intense solution for you:

var get_widget_id = function ( selector ) {
    var selector, widget_id = false;
    var id_attr = $( selector ).closest( 'form' ).find( 'input[name="widget-id"]' ).val();
    if ( typeof( id_attr ) != 'undefined' ) {
        var parts = id_attr.split( '-' );
        widget_id = parts[parts.length-1];
    }
    return parseInt( widget_id );
};

You can pass this function a selector or jQuery object and it will return the instance ID of the current instance. I could find no other way around this issue. Glad to hear I’m not the only one 🙂

Leave a Comment