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 usewp_register_plugin_realpath()
directly to ensure that your subdirectories are handled.The following example code demonstrates how to use the function:
<?php $plugins = array( 'my-mu-plugin/my-mu-plugin.php', ); 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
This is super handy
Mike Schinkel 4:25 am on April 14, 2014 Permalink
Kudos Ryan for pushing that feature through.
Ryan McCue 5:48 am on April 14, 2014 Permalink
Props to you Mike for catching the spots I missed!
Julien 6:50 am on April 14, 2014 Permalink
That’s great news! Thanks!
Fab1en 7:36 am on April 14, 2014 Permalink
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
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
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
Thanks a lot! Great enhancement! Makes my developer live much easier!
Frank 3:18 pm on April 14, 2014 Permalink
Really useful, reduce the custom work.
Brian Layman 3:44 pm on April 14, 2014 Permalink
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
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
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
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.
Primoz Cigler 5:39 pm on April 14, 2014 Permalink
Oh, please delete one of my comments, it rejected me to post 2 times and now both of them are published?
hinnerk 7:28 am on April 15, 2014 Permalink
Same here: “error, comment not posted”, but they appeared after.
hinnerk 7:25 am on April 15, 2014 Permalink
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
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
This is totally awesome!
elimc 7:00 pm on April 16, 2014 Permalink
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
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
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.
Ryan McCue 11:26 am on April 18, 2014 Permalink
This sounds like your site didn’t fully update correctly. Try doing a manual update instead, hopefully that fixes it
experiencedbadmom 11:57 am on April 18, 2014 Permalink
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 do I deactivate plugins if I can’t even get into my dashboard? GoDaddy is my host – do I deactivate plugins somewhere on their servers?
Ipstenu (Mika Epstein) 2:02 pm on April 18, 2014 Permalink
If you need that much help, please post in the support forums: https://wordpress.org/support/
Read this post first: https://wordpress.org/support/topic/wordpress-39-master-list?replies=5
(This blog is not actually for support you see)
satimis 6:14 am on May 1, 2014 Permalink
H all,
I encountered similar problem on moving a website on Godaddy Deluxe hosting plan to Ultimate hosting plan (the website still works without problem on the former plan)
On preview after moving
Fatal error: Call to undefined function wp_register_plugin_realpath() in /home/gopublic2014/public_html/cuisine/wp-settings.php on line 213
wp-settings.php
line 213 wp_register_plugin_realpath( $plugin );
but I couldn’t resolve where to enter;
How to change ( $path ) ?
Please help. Thanks
satimis
styledev 11:39 pm on May 11, 2014 Permalink
I have a local multisite setup and I am symlinking in the entire plugins directory. When I network activate Advanced Custom Fields and go to one of my sites’s ACF Custom Fields page the resource files are still loading in as
http://oc.flocers.dev/Users/dbushaw/Dropbox/Parapxl/Wordpress/plugins/advanced-custom-fields/css/global.css
Instead of
http://oc.flocers.dev/wp-content/plugins/advanced-custom-fields/css/global.css.
I thought WordPress 3.9 fixed this like you note above?
jancbeck 6:37 pm on June 2, 2014 Permalink
Apparently this is a know issue:
https://github.com/elliotcondon/acf/issues/124
ThreadPasser 10:41 am on June 15, 2014 Permalink
How about when I decide to “remove” the plugin from one install but I want to keep it in the other… will that remove just the symlink (affects only this install) or the entire directory (affects all installs)?
How about updates which require database changes? Will all this work or is this all very experimental? Or is this just meant to be used by developers and for temporary setups?
Ipstenu (Mika Epstein) 4:29 pm on June 15, 2014 Permalink
If you remove the symlink from one install, it won’t impact the others.
DB changes… should be fine, since the plugin would detect in each install where it’s called what needs to happen.
ThreadPasser 6:44 pm on June 15, 2014 Permalink
Thanks for your response, that’s clear (about the DB changes).
About the symlinks: if an unaware client clicks “uninstall plugin” from backend (just making up a possibly bad scenario), does the wordpress framework automatically detect that it’s a symlink or does it completely uninstall the targetted directory?
ScreenfeedFr 3:10 pm on June 25, 2014 Permalink
I’m trying this out and this is great.
For MU Plugins with the loader file, there’s still a problem: `plugin_dir_url()` won’t work