WordPress.org

Make WordPress Core

Opened 4 years ago

Last modified 13 months ago

#14686 new defect (bug)

Widget Instance Form Update Bug

Reported by: digitalnature Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 3.0.1
Component: Widgets Keywords: has-patch
Focuses: Cc:

Description

Hi.

When dragging and dropping a widget into a sidebar the widget form doesn't get properly updated, unless you manually press the "Save" button. However the widget instance data is saved (you can see the widget in the frontend even if you don't press 'save').

This problem is noticeable when you're developing a widget and want to display some widget options in the form based on the widget's location or position. You can't do this because $widget->id or $widget->number appear to be initialized within the form() function only after you press Save...

I can provide the code of a test widget if necessary

Attachments (2)

14686.diff (397 bytes) - added by scribu 4 years ago.
doesn't fix anything
widgets.js.patch (432 bytes) - added by dgwyer 13 months ago.

Download all attachments as: .zip

Change History (15)

comment:1 scribu4 years ago

  • Keywords reporter-feedback added

I can provide the code of a test widget if necessary

Please do.

comment:2 digitalnature4 years ago

a basic example:

class test_widget extends WP_Widget{
  function test_widget(){
    $this->WP_Widget(false, 'test');
  }

  function widget($args, $instance){
    echo 'front-end';
  }

  function form($instance){
    print_r($this);
  }
}
add_action('widgets_init', create_function('', 'register_widget("test_widget");'));

$this->id, $this->number and other variables are only available after you press the Save button.

comment:3 scribu4 years ago

  • Keywords widgets reporter-feedback removed

Confirmed: when the widget is saved for the first time, the form is not updated.

That's because $wp_registered_widget_controls[$widget_id] is NULL.

To fix this, we have to get rid of all the global $wp_registered_widget_* rubbish.

scribu4 years ago

doesn't fix anything

comment:4 scribu4 years ago

A dumb workaround would be to automatically click the Save button via JavaScript.

comment:5 mdawaffe3 years ago

  • Keywords needs-patch added
  • Milestone changed from Awaiting Review to Future Release

comment:6 mfields3 years ago

  • Cc michael@… added

comment:7 dgwyer3 years ago

I ran into this problem today. Thought it was something wrong I was doing until I got pointed to this ticket.

My specific issue was not being able to access the jQuery '.click' event when a new widget is dragged into a widget area. You can only do so once the widget has been Saved.

I wanted to hide/show an advanced section of widget options via a jQuery toggle button. This works great apart from the very first time the widget is dragged into the widget area.

As as a stop gap I am looking into automatically clicking the Save button via JavaScript, but this method is a bit of a hack, so it would be great if this was given a closer look for the next release or two.

comment:8 dgwyer2 years ago

  • Version changed from 3.0.1 to 3.3

When you first drag a widget into a widget area the 'save-widget' and 'widgets-order' ajax requests are fired, and when you manually click to save the widget the 'save-widget' ajax request is fired again.

However, the widget object is not accessible on the first ajax request. If the widget object could be set on the FIRST ajax request then there wouldn't be a problem.

Just wondering why it only sets the widget object on the second 'save-widget' ajax response?

Last edited 2 years ago by dgwyer (previous) (diff)

comment:9 azaozz2 years ago

The first 'save-widget' is run to actually create the widget instance in PHP (i.e. let the back-end know there's a new instance of that widget and run any PHP hooks on it). Then all of the new widget instance's HTML is loaded into the new widget "wrap" on the front as return from that XHR request. This includes any changes made by the PHP hooks.

Don't think there's a way around this, seems we can fire a custom event after the initial XHR to trigger changes that need to be made by JS on adding new widget instance.

comment:10 SergeyBiryukov2 years ago

  • Version changed from 3.3 to 3.0.1

Version number indicates when the bug was initially introduced/reported.

comment:11 digitalnature2 years ago

I posted a fix here, still kind of "hacky":
http://wordpress.stackexchange.com/a/37707/1986

This basically fires another save action again after the buggy save action has completed...

I would prefer a proper fix though, by making the first save action return widget instance form HTML

Last edited 2 years ago by digitalnature (previous) (diff)

dgwyer13 months ago

comment:12 dgwyer13 months ago

Added a patch that fixes the issues in this ticket. It basically fires another XHR request when a widget is FIRST dragged into a widget area.

The patch along with the test widget code above works fine. Plus, JS/jQuery is available to the widget, without having to manually click Save, so you can easily add jQuery tabs or toggle advanced widget options etc.

Seeing as this extra XHR request fires ONLY the first time a widget is dragged into a widget area I think it's an acceptable fix.

Obviously it would be preferable to have the form HTML returned along with the first XHR request but it seems this is not possible without some fundamental changes to the widget code (see comment 9 from azaozz).

It 'almost' tantalizingly seems like this is possible looking at the code in ajax-actions.php as the initial XHR request returns nothing back to widgets.php. However there is no access to the global $wp_registered_widget_controls variable in wp_ajax_save_widget() during the initial XHR request so we can't just return the form HTML as a response.

Last edited 13 months ago by dgwyer (previous) (diff)

comment:13 dgwyer13 months ago

  • Keywords has-patch added; needs-patch removed
Note: See TracTickets for help on using tickets.