Ready to get started?Download WordPress

Make WordPress Core

Tagged: 3.9 Toggle Comment Threads | Keyboard Shortcuts

  • Andrew Nacin 5:25 am on April 21, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, 3.9.1,   

    Let’s have a meeting in #wordpress-dev on April 21, 2014 18:00 UTC, to discuss WordPress 3.9.1 and triage those tickets. As preparation for the meeting:

    Reception has been overwhelmingly positive and, anecdotally at least, we’ve seen more issues as they relate to deliberately changed aspects (TinyMCE/editing) versus generic plugin breakage. I think we’re in pretty good shape based on the bug reports that have come in, but with automatic updates at our disposal, there’s no reason to wait three or four weeks before shipping 3.9.1.

    I think we should try to fix the big, obvious stuff by Tuesday and release 3.9.1 as early as Wednesday. Some of the reported issues are pretty core to TinyMCE 4.0 and the various rewrites it triggered (like image editing), which means many of them won’t be handled by 3.9.1. That’s quite OK, especially since some of these may require some upstream fixes in TinyMCE, and since there can always be a 3.9.2 in the weeks ahead.

    What I do want to do is have no “unknowns” — we should know exactly what regressed or otherwise is broken, under what circumstances, how major or minor it is, how high or low of a priority it should be, etc. That includes unit tests (if applicable) or at least clear test cases.

    cc @azaozz @helen @wonderboymusic @gcorne @avryl @mcsf @ehg @jeremyfelt @ocean90 @westonruter

    • Andrew Nacin 5:28 am on April 21, 2014 Permalink | Log in to Reply

      If you’re able to look through tickets in your domain ahead of the meeting that would make it go pretty quick, and we can cover them really at any point during the day (I’ll be around all day), I just wanted to make sure the ball gets rolling.

    • Weston Ruter 11:39 am on April 21, 2014 Permalink | Log in to Reply

      Alas, I’ll be in the air at this time. Not sure I’ll have WiFi. I think widget customizer is in good shape for 3.9.1 with critical #27897 being committed and with minor #27878 having a patch.

  • Weston Ruter 8:10 pm on April 17, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, , appearance,   

    Live Widget Previews: Widget Management in the Customizer in WordPress 3.9 

    The WordPress 3.9 release includes widget management in the Customizer: previewing changes to widget areas before publishing them live for the world to see. This feature was birthed out of the Widget Customizer plugin which started development in the 3.8 release cycle, it was formally proposed for merging into core at the start of the 3.9 release cycle, and then it was merged and followed by many changes. I wanted to follow-up here to talk through the changes to Widget Customizer since it was initially proposed (read this post for a full overview of the feature). Here is what has changed since then:

    No more opt-in for theme support

    The Widget Customizer plugin implemented a mechanism for doing fast live widget previews. By default, all changes made to settings in the customizer cause the preview window to do a full page refresh. This causes a lag between when you make a change and when the change appears. The customizer also supports an alternate non-refresh mechanism for previewing changes in the customizer (the postMessage transport) which you often see themes implement for live-previewing the blog name or the header color.

    Implementing such immediate live-previews requires all of the logic for previewing the change to be implemented in JavaScript, in addition to the underlying PHP logic for rendering the change when the setting is saved. This is not possible for widgets, since they all use PHP to handle the sanitization of the form inputs and for rendering arbitrary content that a widget may contain. (You’ll notice that when you make a change to a widget in the customizer, it actually does an Ajax request to submit the widget form for sanitization every time.) Well, to get around having the customizer preview refresh for every widget change, we implemented an Ajax renderer for the widgets, and then used the postMessage transport to initiate this widget render request, and then the rendered widget response would get swapped out in the DOM.

    Long story short, we decided to remove this feature to use postMessage for faster live previews. We have created #27355 to re-add this feature, but to generalize it so that any customizer control can take advantage of doing these partial preview refreshes. So for now, you’ll have to wait a moment for the preview to refresh when you make a change to a widget area, but now you don’t change your themes or widgets to add explicit support for Widget Customizer.

    No more Update button (usually)

    Widget forms on the admin page have a familiar Save button. In previous versions of Widget Customizer, we adapted the Save button to be an Update button, since it wouldn’t actually save the widget but would just update the preview with the widget’s latest state. Having to click this Update button to see the preview update, however, was a poor user experience and was unnecessary. Therefore, we implemented a means of submitting the form to update the widget’s state in the preview whenever a field in the control is updated: the Update button was hidden and the spinner appears when a change is being synced to the preview.

    The logic which does this live submission of the widget form as you interact with it, depends on the fields in the widget form to be the same fields which get returned when the widget form is sanitized. This is so that the fields can be aligned for being updated with their sanitized values. We couldn’t go the route of the widget forms on the widgets admin page, which actually get fully replaced with the newly-sanitized form, because this would interfere with the user quickly inputting into these fields.

    So if a widget form dynamically adds or changes which input fields are included, the live-as-you-type-them updates will stop and the Update button will re-appear. When you click this button, the form will replace itself with the sanitized version just like on the widgets admin page. We also introduced new jQuery events to help handle these form changes…

    New widget-added and widget-updated jQuery events

    In the widgets admin page, when you add a new widget to a widget area, a widget template element gets cloned and then inserted into the selected widget area. This widget template is cloned in a way that any event handlers initially added to the widget template do not persist on any newly-added widgets. Any widgets previously-added to the widget areas would have these event handlers attached, as well as any dynamically-created fields (e.g. jQuery Chosen), but again, newly-added widgets fail to retain these. The same problem exists, however, whenever you update a widget: since the newly-sanitized widget form replaces the old one, any dynamic elements get lost. (This is why event delegation is often required.)

    The same challenges here for the widgets admin page are also challenges for widgets in the customizer. And so in #19675 and #27491, we’ve introduced widget-added and widget-updated jQuery events which pass along the widget container as the second argument for the event handler. So to initialize and re-initialize a widget’s dynamic UI, you can now use these events in something like this:

    jQuery( function ( $ ) {
    	function init( widget_el, is_cloned ) {
    		// Clean up from the clone which lost all events and data
    		if ( is_cloned ) {
    			widget_el.find( '.chosen-container' ).remove();
    		widget_el.find( 'select.dynamic-field-chosen-select' ).chosen( { width: '100%' } );
    	 * <a href='http://profiles.wordpress.org/param' class='mention'>@param</a> {jQuery.Event} e
    	 * <a href='http://profiles.wordpress.org/param' class='mention'>@param</a> {jQuery} widget_el
    	function on_form_update( e, widget_el ) {
    		if ( 'dynamic_fields_test' === widget_el.find( 'input[name=&quot;id_base&quot;]' ).val() ) {
    			init( widget_el, 'widget-added' === e.type );
    	$( document ).on( 'widget-updated', on_form_update );
    	$( document ).on( 'widget-added', on_form_update );
    	$( '.widget:has(.dynamic-field-chosen-select)' ).each( function () {
    		init( $( this ) );
    	} );
    } );

    This is admittedly still not ideal, but it is much better than hacking the jQuery Ajax events to detect when a form update happens. In the future, I’m keen to see the widgets be revamped to use Backbone extensively.

    Configuring widgets during a theme switch

    We had a surprise late in the release (#27767) when it was reported that when you activate a new theme via the customizer, any changes made to the widget areas get lost when the theme is activated. This issue has been fixed, so now you can preview a theme and fully configure all of the widget areas before going live.

    Beware of widgets and caching

    We had another challenge in #27538 where widget changes previewed in the customizer would leak outside the preview and on the live site if the widget cached the output for performance. The core widgets Recent Posts and Recent Comments both cache their outputs in the object cache, and if a persistent object cache plugin is enabled (e.g. Memcached or APC) then the cache would get poisoned with the previewed widget, even though the widget’s changes weren’t saved. The same behavior would be experienced for widgets that use transients to cache the rendered output.

    To help widgets do the right thing in regards to caching, we introduced a WP_Widget::is_preview() method which widgets should always check before they interact with the cache. For example, a widget’s widget()method which caches its output should do something like this:

    if ( ! $this->is_preview() ) {
        $cached = wp_cache_get( 'foo-widget' );
        if ( ! empty( $cached ) ) {
            echo $cached;
    extract( $args );
    echo $before_widget;
    // ...
    echo $after_widget;
    if ( ! $this->is_preview() ) {
        $cached = ob_get_flush();
        wp_cache_set( 'foo-widget', $cached );

    Look forward to more improvements to widgets and the customizer in future releases!

  • Dominik Schilling (ocean90) 2:17 pm on April 16, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, ,   

    Dashicons in WordPress 3.9 

    WordPress 3.8 has introduced an icon font for the WordPress admin, named Dashicons. Dashicons includes 167 icons until now.
    WordPress 3.9 includes 30 new fresh and clean icons. Thanks to all contributors to ticket #26936, especially @melchoyce and @empireoflight.

    Media Icons

    All media file type icons got a huge facelift, see #26936. There are also two new icons for the playlists feature.

    Icon CSS Class Code
    dashicons-media-archive f501
    dashicons-media-audio f500
    dashicons-media-code f499
    dashicons-media-default f498
    dashicons-media-document f497
    dashicons-media-interactive f496
    dashicons-media-spreadsheet f495
    dashicons-media-text f491
    dashicons-media-video f490
    dashicons-playlist-audio f492
    dashicons-playlist-video f493


    With the update to TinyMCE 4.0 you can now use four new icons for editor related UI.

    Icon CSS Class Code
    dashicons-editor-contract f506
    dashicons-editor-break f464
    dashicons-editor-code f475
    dashicons-editor-paragraph f476


    Use dashicons-external for external uses or randomize a list with dashicons-randomize.

    Icon CSS Class Code
    dashicons-external f504
    dashicons-randomize f503

    WPorg specific: Jobs, Profiles, WordCamps

    We all WordCamps.

    Icon CSS Class Code
    dashicons-universal-access f483
    dashicons-universal-access-alt f507
    dashicons-tickets f486
    dashicons-nametag f484
    dashicons-clipboard f481
    dashicons-heart f487
    dashicons-megaphone f488
    dashicons-schedule f489


    Have you already tried the live widget previews? You should. The following icons are created for this feature.

    Icon CSS Class Code
    dashicons-archive f478
    dashicons-tagcloud f479
    dashicons-text f480


    The minus icon has an alternative icon, plus now too. Welcome.

    Icon CSS Class Code
    dashicons-plus-alt f502


    End of .

    Icon CSS Class Code
    dashicons-microphone f482

    To get a complete overview of all icons please visit http://melchoyce.github.io/dashicons/.

  • Andrew Nacin 1:40 pm on April 16, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, , , external libraries   

    jQuery UI and wpdialogs in WordPress 3.9 

    WordPress 3.9 does not use the “wpdialogs” TinyMCE plugin as part of the TinyMCE 4.0 update ( #16284, #24067), which comes with a new dialog manager. (For more, see this post and their migration guide.) This was a jQuery UI wrapper we had introduced back in WP 3.1. If you were using this in your own scripts, please be sure you are setting “wpdialogs” as a script dependency.

    If you were using jQuery UI for anything on the post screen, please be sure you are setting this as a script dependency.

    In both cases you may need to enqueue the “wp-jquery-ui-dialog” stylesheet, if you are using the WP UI dialog design.

  • Jeremy Felt 6:31 am on April 16, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, ,   

    Multisite Changes in 3.9 

    Much of the bootstrap code for Multisite in ms-settings.php has been refactored in #27003 with the intent to improve how we handle the detection of domains and paths for sites and networks in core. Several other smaller enhancements and bugs have been completed in this and in other tickets.

    How networks and sites are found

    In the most common multisite scenario, the network finding process is the same. The constants DOMAIN_CURRENT_SITE and PATH_CURRENT_SITE in your wp-config.php define the network to be loaded by WordPress. In the large majority of installations there is only one network.

    The default process for finding the requested site now goes through a new function, get_site_by_path(). See the new functions section below for more details.

    If you use a sunrise file—likely through a domain mapping or multi-network plugin—and the $current_site and $current_blog globals are configured there through a custom network and site detection process, the finding portions of ms-settings.php will continue to be skipped entirely. Nothing changes.

    In some (very) rare scenarios, multiple networks may be configured in WordPress without a sunrise file. It is here where both the site and network finding process has been altered to use new functions rather than the stream of bootstrap code.

    Deprecated Functions

    There are two deprecated functions that may appear in your sunrise or in plugins to watch out for. Both of these were intended for private use by core, but came in handy as helpers to hack around various bits and pieces of the load process.

    wpmu_current_site() is deprecated. It was previously used to find the network and site information for a request. All functionality has been removed from this in favor of replacement functions. In its current form, it returns the $current_site global.

    get_current_site_name() is deprecated. It was previously used to set the site_name property on a given $current_site object. In its current form, it returns the passed $current_site object. This will likely not break anything, but any code relying on retrieving a site name using this function should be modified to use get_current_site() instead.

    New Functions

    Three new functions have been added to ms-load.php in 3.9 development. All of these have the focus of making sites and networks easier to find. These are meant to be public replacements for the previously private and somewhat inaccessible logic that existed in the bootstrap.

    wp_get_network() retrieves an object containing the network’s information from the database when passed a network ID.

    get_site_by_path() retrieves a site object when passed a domain and path. Two new filters are available here.

    get_network_by_path() retrieves a network object when passed a domain and path. Two new filters are available here as well.

    New Filters

    Inside the new site and network finding functions are a few filters that go a long way in providing for a less hacky sunrise.php file in the future. These can be used to shape the multisite bootstrap process without entirely replacing the logic.

    site_by_path_segments_count fires in get_site_by_path() and sets the number of possible path segments a site may have when we’re searching for it.

    pre_get_site_by_path fires in get_site_by_path() and allows you to short-circuit core’s default logic for finding a site.

    network_by_path_segments_count fires in get_network_by_path() and sets the number of possible path segments a network may have when we’re searching for it.

    pre_get_network_by_path fires in get_network_by_path() and allows you to short-circuit core’s default logic for finding a network.


    It’s exciting to see some of the progress we’re making around multisite. We’d like to see what can be solved or broken with the new filters. More future improvements will be made around this and we want to make sure the base is right.

    Also take a look at the multisite focused tickets closed as fixed for 3.9. There are several other improvements and bug fixes that are worth taking a look at.

    See #25348 for autocompleting users when adding a new site. See #20601 for proper 404 handling of non member author archives. See #24178 for past confusion with a plugin that is activated on the network and locally.

    Thanks all!

    • Ryan McCue 6:37 am on April 16, 2014 Permalink | Log in to Reply

      In the most common multisite scenario, the network finding process is the same. The constants DOMAIN_CURRENT_SITE and PATH_CURRENT_SITE in your wp-config.php define the network to be loaded by WordPress. In the large majority of installations there is only one network.

      It’s worth emphasising: these constants refer to your network, not the site; get_site_by_path, however, refers to the site. (This is an artifact of the blog/site naming convention that’s being replaced with site/network.)

    • bvl 11:03 am on April 16, 2014 Permalink | Log in to Reply

      Great news, although I am a little disappointed that https://core.trac.wordpress.org/ticket/19722 still isn’t fixed, maybe in the next release?

    • rclilly 9:08 pm on April 16, 2014 Permalink | Log in to Reply

      Jeremy, Thanks for all work you’ve into improving multisite!

    • David 6:24 pm on April 17, 2014 Permalink | Log in to Reply

      I upgraded my multisite to 3.9 and this issue has occured….http://wordpress.stackexchange.com/questions/141578/3-9-breaks-multisite.
      Seems to be a bug of some sort as others are having the same issues. Looks to be a redirect issue of some sort.

    • lborgman 11:44 am on April 19, 2014 Permalink | Log in to Reply

      Many thanks for all the work with multisite!

      Here is however another issue that people coming here for information might be interested in:

      Solved: WP Multisite Stuck in Redirect Loop After 3.9 Upgrade http://www.webhostinghero.com/wp-multisite-stuck-in-redirect-loop/

      • Ipstenu (Mika Epstein) 3:09 am on April 20, 2014 Permalink | Log in to Reply

        That’s a poor choice of fixes, when a simple .htaccess redirect to force NON www will work fine (I don’t recommend using www on a Multisite as the default in general, and WP actually suggests you not do so at all when you’re installing, so I wouldn’t think that a fix that says to use it is the best call). Not to mention that how-to didn’t change the rest of the DB, which it should for consistency across the board. If you’re not using www in your site, a much easier fix is this:

        	RewriteEngine On
        	RewriteBase /
        	RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
        	RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

        Just added that to my site and it’s better. However I made a trac for this, since www should not be treated as a subdomain. It’s special.


  • Andrew Nacin 12:14 pm on April 15, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9,   

    Let’s have a meeting today, Tuesday April 15, 2014, 18:00 UTC, to make sure we have everything in place for a release. (#wordpress-dev)

  • Konstantin Obenland 1:55 am on April 15, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, , , , ,   

    HTML5 Galleries & Captions in WordPress 3.9 

    WordPress 3.6 introduced HTML5 versions of popular template tags, starting out with comments, the comment form, and the search form. With the 3.9 release we add galleries and captions to that list. Now, when adding HTML5 support for those features, WordPress will use <figure> and <figcaption> elements, instead of the generic definition list markup.

    To declare that your theme supports these new HTML5 features, add the following call to your theme’s functions.php file, preferably in a callback to the after_setup_theme action:

    add_theme_support( 'html5', array( 'gallery', 'caption' ) );

    For forward compatibility reasons, the second argument with the specific parts can’t be omitted when registering support. Otherwise a theme would automatically declare its support for HTML5 features that might be added in the future, possibly breaking its visually because of it.

    For both galleries and captions not only the markup changes when a theme declares its support for them, there are also peripheral changes that come with it.


    By default, galleries will not include inline styles anymore when in HTML5 mode. This caters to the trend of disabling default gallery styles through the use_default_gallery_style filter, a filter that even the last two default themes used. With that, theme developers can always start with a clean slate when creating their own set of gallery styles.

    We also took the opportunity to remove the line breaks between rows of images. Not only did they encourage an inferior way of positioning elements, more importantly they were non-semantic html elements that are meant for presentational use, and they made it harder to style galleries.


    Up until now, captions received an additional 10 pixels of width, to keep text flowing around the caption, from bumping into the image. As @nacin put it, this has vexxed theme developers for years, and even resulted in the addition of a filter in WordPress 3.7 to manipulate the caption width.

    We were not able to completely remove the inline style in HTML5 mode, it’s still necessary to force captions to wrap, but we’re no longer the adding 10px of width. We also removed caption styles in the editor, bringing it on par with how non-captioned images are displayed:

    Twenty Thirteen and Twenty Fourteen have been updated to support both features, while retaining backwards compatibility with older WordPress versions. There is a remote possibility however, that child themes that use element selectors to overwrite gallery or caption styles can lose those customizations. Please test your child themes with the current development versions of the last two default themes.

    If there are any questions about the current implementation, feel free to leave a comment below.

    • andrei1709 5:08 am on April 15, 2014 Permalink | Log in to Reply

      Awesome! Thank you very much for this update :)

    • Manuel Schmalstieg 12:07 pm on April 15, 2014 Permalink | Log in to Reply

      Glad to see that the HTML5 mode removes the BR tags from the gallery markup. That’s great news for responsive theme development!

    • Morten Rand-Hendriksen 3:12 pm on April 15, 2014 Permalink | Log in to Reply

      This is great and long overdue. I always say WordPress is at the forefront of web standards and the two thing that have been lagging behind are the galleries and comments. This is a major milestone that will change the way we think about built in features.

    • glueckpress 9:15 am on April 16, 2014 Permalink | Log in to Reply

      (goes updating themes)

    • Justin Kopepasah 6:43 am on April 17, 2014 Permalink | Log in to Reply

      This is great news. I was happy when the filter was introduced and now I am elated to see the ability to implement HTML5 galleries completely. Definitely adding this to my latest theme.

  • Ryan McCue 2:12 am on April 14, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, , , symlinks   

    Symlinked Plugins in WordPress 3.9 

    One of the cool little features included with 3.9 is the ability to symlink plugin directories. While it has been possible to symlink plugins in the past, functions such as plugins_url() return the wrong URL, which causes breakage in most plugins.

    In #16953, r27158 and the followup r27999, we corrected this with the help of a new function: wp_register_plugin_realpath(). This function is called automatically during the plugin loading phase, and registers which plugin directories are symlinked, and where they’re symlinked to. This functionality is then used by plugin_basename() (the core of plugins_url(), along with other
    functions) to reverse symlinks and find the correct plugin directory.

    This enhancement means that you can symlink individual plugin directories, or even the whole plugins directory itself.

    For anyone who’d like to use this, keep in mind that there are a few caveats:

    • Single-file plugins are not handled by this code. Any plugins you’d like to symlink must be in subdirectories of the main plugins folder. This restriction is due to the way these paths are registered.

      You can still symlink single-file plugins, however any use of plugin_basename() will be as broken as it was before 3.9. This is not a huge issue, as the main use of this is in plugins_url(), which is not frequently used in single-file plugins.

    • Must-use plugins cannot be symlinked. For the same reasons as single-file plugins, mu-plugins are not handled.

      For anyone using the common pattern of subdirectories within mu-plugins with a common loader file, you can use wp_register_plugin_realpath() directly to ensure that your subdirectories are handled.

      The following example code demonstrates how to use the function:

      $plugins = array(
      foreach ( $plugins as $plugin ) {
      	$path = dirname( __FILE__ ) . '/' . $plugin;
      	// Add this line to ensure mu-plugins subdirectories can be symlinked
      	wp_register_plugin_realpath( $path );
      	include $path;

      Hopefully this change is as helpful for you as it was for me! One of the great advantages to this is that plugin developers can keep their plugin separate from their WordPress installation. This is a boon for developers with multiple installs who want to test compatibility; keep in mind that you can symlink the entire plugins directory if you're testing multiple!

      If you have any questions about this, please leave a comment on this post and we'll be happy to help you out!

    • PeterRKnight 2:29 am on April 14, 2014 Permalink | Log in to Reply

      This is super handy

    • Mike Schinkel 4:25 am on April 14, 2014 Permalink | Log in to Reply

      Kudos Ryan for pushing that feature through.

    • Julien 6:50 am on April 14, 2014 Permalink | Log in to Reply

      That’s great news! Thanks!

    • Fab1en 7:36 am on April 14, 2014 Permalink | Log in to Reply

      Thanks for this Ryan !
      I was using a custom plugin that tweaked `plugin_basename` to make it work with symlinked plugins. Thanks to you, I will not need this plugin anymore !

    • klihelp 12:37 pm on April 14, 2014 Permalink | Log in to Reply

      Thanks for the post.

      >> This is a boon for developers with multiple installs who want to test compatibility
      Tell me more about this.
      Could I read as a multiple WP installs uses the same plugin directory, so you don’t have multiple copies of the plugins?

      • Fab1en 3:42 pm on April 15, 2014 Permalink | Log in to Reply

        yes, that is what you can read ! Just add a symlink to a shared plugins directory in each WP install wp-content folder, and your installs will share the same plugins copy.

    • hinnerk 3:06 pm on April 14, 2014 Permalink | Log in to Reply

      Thanks a lot! Great enhancement! Makes my developer live much easier!

    • Frank 3:18 pm on April 14, 2014 Permalink | Log in to Reply

      Really useful, reduce the custom work.

    • Brian Layman 3:44 pm on April 14, 2014 Permalink | Log in to Reply

      This is a neat little thing. We’d experimented with symlinking the files back in b5media days with our 350ish sites, but there were enough little oddities to make it not the right choice for a poor man’s MU option.

    • Primoz Cigler 5:33 pm on April 14, 2014 Permalink | Log in to Reply

      Very important and useful update. But I have a question: is something like this possible with the themes as well? Would make perfect sense for the same reason, if you are a theme developer: “One of the great advantages to this is that theme developers could keep their theme separate from their WordPress installation. This is a boon for developers with multiple installs who want to test compatibility; keep in mind that you could symlink the entire themes directory if you’re testing multiple!”

      • Ryan McCue 2:12 am on April 17, 2014 Permalink | Log in to Reply

        But I have a question: is something like this possible with the themes as well?

        I can’t think of any issues with allowing this; file a ticket on Trac! :)

    • Primoz Cigler 5:34 pm on April 14, 2014 Permalink | Log in to Reply

      This is very important and useful update. But I wonder if something similar would be possible with the themes too? For the same obvious reasons as for plugins.

    • hinnerk 7:25 am on April 15, 2014 Permalink | Log in to Reply

      I had to add Options +FollowSymLinks to my .htaccess in order to remove a 403 Forbidden on all pages (using symlinks in plugins directory).

    • hinnerk 7:27 am on April 15, 2014 Permalink | Log in to Reply

      I had to add Options +FollowSymLinks to my .htaccess to remove a 403 Forbidden on all pages (using symlinks in /wp-content/plugins/).

    • Todd Lahman 8:45 am on April 15, 2014 Permalink | Log in to Reply

      This is totally awesome!

    • elimc 7:00 pm on April 16, 2014 Permalink | Log in to Reply

      I’m a bit confused about what this future does. Does this allow me to define a constant on my local server that links to the plugin directory on remote sites, thereby, preventing the need to duplicate the same plugins on both the local and remote server?

      • Ryan McCue 2:13 am on April 17, 2014 Permalink | Log in to Reply

        This doesn’t allow you to share plugin files across HTTP, no. It does allow you to have certain plugins live outside of your WordPress content directory, which means you can share the same code between multiple installations on the same server.

    • experiencedbadmom 11:39 pm on April 17, 2014 Permalink | Log in to Reply

      Total newbie here. I blog as a hobby. I do not know code. I updated to 3.9 today and now ALL I get is this error message:

      Fatal error: Call to undefined function wp_register_plugin_realpath() in /home/content/92/8889792/html/wp-settings.php on line 213

      I can’t get to my login page or see my blog anymore. I found this thread by searching “Fatal error: Call to undefined function wp_register_plugin_realpath()”. Any advice would be greatly appreciated to restore my blog! Thank you.

  • Konstantin Kovshenin 11:20 am on April 11, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, , ,   

    Plupload 2.x in WordPress 3.9 

    Plupload is the library that powers most of the file upload interfaces in WordPress, and in 3.9 we’ve updated the bundled library to version 2.1.1 (#25663). Here are some of things that have changed, which may affect WordPress plugins and themes.

    If you’re using direct references to Plupload’s runtime .js files, such as plupload.html5.js, note that these files are now gone. The following script handles were removed: plupload-html5, plupload-flash, plupload-silverlight and plupload-html4. If you need to enqueue the Plupload library, just use the plupload handle.

    If you’re constructing your own Plupload settings array vs. using wp_plupload_default_settings() and/or the _wpPluploadSettings object, note that some of the arguments have changed, most notably:

    • flash_swf_url should point to the new Moxie.swf file (See update)
    • Similarly, silverlight_xap_url should use the new Moxie.xap (See update)
    • The multiple_queues argument is no longer used
    • The max_file_size key has been moved to the filters array
    • The filters array now supports multiple keys, and the list of file types array has been moved to its mime_types key

    To illustrate that with code:

    $settings = array(
        // ...
        'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ), // Unchanged
        'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ), // Unchanged
        'filters' => array( 
            'max_file_size' => $max_upload_size . 'b', 

    Plupload version 2.1.1 has also added some exciting new options and methods, which you can find in the updated documentation.

    As a result of this update in WordPress 3.9 we were able to add drag and drop upload support directly to our TinyMCE editor (#19845), and we’ve also added a new boolean flag to wp_editor(), which you can use to enable drag and drop upload support in your own instance of the editor (#27465):

    wp_editor( '', 'my-editor', array(
        // ...
        'drag_drop_upload' => true,
    ) );

    If you run into any problems with this update in 3.9, please leave a comment on this post and we’ll be happy to help you out!

    Update: I opened #27763 to address some of the compatibility issues around the update. We might be renaming the swf/xap files for backwards compatibility.

    Update, April 13: The original swf/xap filenames were restored.

    • Andrew Nacin 1:20 am on April 14, 2014 Permalink | Log in to Reply

      Post updated to reflect changes via #27763.

    • experiencedbadmom 11:54 am on April 18, 2014 Permalink | Log in to Reply

      Thank you for the link to the manual instructions. My blog is experiencedbadmom.com tho, not experiencedbadmom.com/wordpress/ – does that matter? Also, one of the steps says to deactivate plugins – how am I to deactivate plugins if I can’t even get into my dashboard? GoDaddy is my host – do I deactivate plugins somewhere on their servers?

    • Najeeb 6:16 am on April 21, 2014 Permalink | Log in to Reply

      Hello there,

      well I am using pluploader library in my plugin and when try ‘plupload’ handle to use shipped scripts it not applying to my uploader object, even I can see libraries are loading. Any help will be much appreciated.


      • Konstantin Kovshenin 7:32 am on April 21, 2014 Permalink | Log in to Reply

        Hi there! Can you please provide more details, like a code sample? Also, has it worked in 3.8 and broken in 3.9 or does it just not work in general? Thanks!

    • pbusardo 7:13 pm on April 21, 2014 Permalink | Log in to Reply

      Perhaps this is relevant. I believe the FLA gallery uses Plupload. When I try to upload multiple files to the gallery, the GUI no longer appears.

  • Gary Pendergast 6:20 am on April 7, 2014 Permalink | Log in to leave a Comment
    Tags: 3.9, , database, ,   

    MySQL in WordPress 3.9 

    In WordPress 3.9, we added an extra layer to WPDB, causing it to switch to using the mysqli PHP library, when using PHP 5.5 or higher.

    For plugin developers, this means that you absolutely shouldn’t be using PHP’s mysql_*() functions any more – you can use the equivalent WPDB functions instead.


    There are a few different options for replacing the query functions, depending on what you want to do:

    As a drop in replacement to run a query that you don’t expect a return value from (i.e., an INSERT, UPDATE or DELETE query), use $wpdb->query(). This will always return the number of rows effected by the query.

    Alternatively, $wpdb->insert(), $wpdb->update(), $wpdb->delete() and $wpdb->replace() are all helper functions that will automatically escape your data, then generate and run the queries for you. Ideally, you should never need to write an SQL statement!


    If you have a SELECT query, for which you’d normally do a mysql_query() followed by a mysql_fetch_*(), WPDB lets you combine this into one function call.

    To get all of the results from a query that returns more than one row, use $wpdb->get_results() to return an array of objects containing your data.

    There are also some shortcut functions for common usage:

    If you only need a single row from your query, $wpdb->get_row() will return just the data object from that row.

    If you only need a single column from a single row, $wpdb->get_var() will return only that field.

    And if you need a single column, $wpdb->get_col() will return an array of all the data from that column.


    For a drop in replacement, you can use esc_sql(). That said, we strongly recommend switching to $wpdb->prepare(), instead. We have a pretty thorough tutorial available for $wpdb->prepare().


    If you need to get the Insert ID from the last query, $wpdb->insert_id is where you need to look.

    Updating your plugin to use WPDB will also future proof it for if we make changes to how WordPress connects to the database – we’ll always maintain backwards compatibility with the current WPDB interface.

    For more reading, check the WPDB Codex page, and #21663.

    If you’re using MySQL in a way that I haven’t covered here, please post it in the comments, we’d be happy to help you out!

    • Samuel Wood (Otto) 6:23 am on April 7, 2014 Permalink | Log in to Reply

      Note: $wpdb->escape() is deprecated. Please use esc_sql() instead. Or $wpdb->prepare(), of course.

      Also note that $wpdb->escape() is not a proper replacement for mysql_real_escape_string() to begin with, as it only does weak escaping.

    • Doug Wollison 12:09 pm on April 7, 2014 Permalink | Log in to Reply

      I though I heard it was going to switch to PDO, not MySQLi?

      • Gary Pendergast 12:30 pm on April 7, 2014 Permalink | Log in to Reply

        That’s still on the cards for a future release, but it will be a significantly bigger project. The primary goal with this change was to stop using ext/mysql on PHP 5.5+, where it’s deprecated.

    • Brian Layman 4:10 pm on April 7, 2014 Permalink | Log in to Reply

      Wow! Huge change, and with the MySQL extension being deprecated in PHP 5.5 it’s a good one. I am trying to remember if 5.5 REQUIRES MySQLi to be built in. Does anyone know? Should you also throw in a check for the existence of mysqli_connect?

      Also, are there plans to start preparing queries? (Not WP prepare but the database meaning of prepare.)

      • Gary Pendergast 3:06 am on April 10, 2014 Permalink | Log in to Reply

        We do check that mysqli_connect() exists before trying to use it. (See wpdb::__construct().)

        There are no plans for adding statement prepare in the near future, though it is something I would like to get to!

    • webaware 10:46 pm on April 7, 2014 Permalink | Log in to Reply

      Plugin writers sometimes call mysql_get_server_info() to get the raw version information that $wpdb->db_version() strips out. Since the database handle isn’t public (nor is the mysqli indicator), there isn’t a way to do this in 3.9-beta3. I’ve opened a trac in hopes we can get a new method added to class wpdb so that plugin writers can still access this raw version information:


      • Gary Pendergast 5:28 am on April 8, 2014 Permalink | Log in to Reply

        To summarise the ticket, for anyone using mysql_get_server_info() – the best option is to have a switch in your code for mysqli, we’ll look at expanding $wpdb->db_version() at a later date.

        if ( empty( $wpdb->use_mysqli ) ) {
        	$ver = mysql_get_server_info();
        } else {
        	$ver = mysqli_get_server_info( $wpdb->dbh );
    • Claudio 8:51 pm on April 13, 2014 Permalink | Log in to Reply

      I use mysql_connect to test DB connectivity. How should I replace it for WP3.9/PHP5.5 compatibility?

      • Gary Pendergast 12:13 am on April 14, 2014 Permalink | Log in to Reply

        To test the connection, you can use $wpdb->check_connection(), which will check that the connection is up, and try to reconnect if it isn’t.

        This is particularly useful for long running cron jobs, where the MySQL connection might drop out due to inactivity, but there’s no actual problem with the server.

compose new post
next post/next comment
previous post/previous comment
show/hide comments
go to top
go to login
show/hide help
shift + esc