WordPress.org

Make WordPress Core

Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#10426 closed enhancement (wontfix)

Should introduce JavaScript hooks/events/callback after a widget has been added from the admin interface

Reported by: godfreykfc Owned by: azaozz
Milestone: Priority: normal
Severity: normal Version:
Component: JavaScript Keywords: close widgets, javascript, admin, events, hooks, callbacks
Focuses: Cc:

Description

The new widget interface provides a very nice experience for the end-users, but not so much for the developers.

As a developer, you will often find the need to use JavaScript in your widget controls, such as creating the tabs in our section widget (see: http://wordpress.org/extend/plugins/section-widget/screenshots/). This, however, is really a lot more tricky than it should have been. When WP loads the widgets interface, it will create some "stub" widgets on the left. In the "stub" widgets, all HTML IDs will include a placeholder like section-widget-_i_. When the user drags the stub widget to the sidebar, WP will copy its content and then do a search and replace of all the IDs so it will look like section-widget-1 in the end.

This ID change causes a lot of problem for other JS code. For instance, if you tab-ify your divs on document.ready using jQueryUI Tabs, it would no longer work after the stub widget is copied over to the sidebar, because the actions it uses are dependent on the actual IDs of the divs. You might think that adding an event listener for the onClick event on the expand button will solve the problem, but it won't work because WP already attached a listen to that event, which unfortunately returns "false" - which stops the event from bubbling up.

Currently, it requires a lot of hacking to get around this problem, (see: http://svn.wp-plugins.org/section-widget/trunk/section-widget.dev.js) so I am suggesting we should either: a) provide a way to register JS callbacks when a widget has been added to the sidebar, or b) trigger a custom event on the widget after it has been added to the sidebar.

Change History (5)

comment:1 azaozz5 years ago

  • Component changed from Widgets to JavaScript

Since most widgets are multi-instance chances are that there will be more than one of each on the screen. So html IDs cannot be used anywhere in the widgets (that would break any js). In that terms using the ID of the widgets is not recommended as it needs to change for each widget added to a sidebar.

We could add a callback to wpWidgets.addEvents() however in js it's very easy to overwrite this (like you've already done):

wpWidgets._addEvents = wpWidgets.addEvents;
wpWidgets.addEvents = function(scope) {...}

Other notes:

  • Returning "false" for an event doesn't stop other listeners attached to it, propagation or bubbling. Copying the widget's html and inserting it in a sidebar removes all previously attached events. Also when a widget is saved, the html is reloaded from the ajax return.
  • Unless you need some (quite) advanced functionality like ajax loading an arbitrary number of tabs, etc. it's better not to use ui.tabs. The basic tab switching/hiding/disabling is easily done directly with jQuery (and won't break next time they decide to change ui.tabs).
  • You can use the jQuery.live() (new in 1.3) to attach the functions to all tabs at once, including tabs that are loaded after a widget has been saved. Then you can get the current ID (if you still need it) by doing jQuery(this).parents('.widget').attr('id').

comment:2 Denis-de-Bernardy5 years ago

  • Keywords close added

you can also use livequery. suggesting wontfix.

comment:3 godfreykfc5 years ago

I think the ultimate problem is that all of these "solutions" are very hackish and are very dependent of the current widget interface. Plugins that needs to hook into these places will break if another plugin/admin theme make changes to the widget admin interface. Also, if a future version of wordpress changes the widgets interface again (even just the look-and-feel), maintaing backwards compatibility is going to be painful.

comment:4 azaozz5 years ago

  • Milestone Unassigned deleted
  • Resolution set to wontfix
  • Status changed from new to closed
  • Version 2.8 deleted

Not exactly. Using $.live() or livequery to attach events to html created by your plugin will work in all cases regardless of the other elements or scripts.

comment:5 Denis-de-Bernardy5 years ago

Expanding on andrew's comment, the livequery approach has worked fine since 2.5. there was a slight issue with 2.8, since jquery got upgraded, and livequery needed version 1.1 which is still in beta (so needs to be checked out from CVS). But it totally works.

Things end up looking like this:

jQuery(document).ready(function(){
	jQuery("div.nav_menu_item_sortables").livequery(function() {
		// do stuff
	});
	jQuery("input.nav_menu_item_add").livequery('click', function() {
		// do stuff
	});
});
Note: See TracTickets for help on using tickets.