Fixing plugins that break on symlinked wp-content

A common issue when using a symlinked wp-content directory is broken Javascript and CSS paths in WordPress plugins. The problem occurs when plugins try to include assets relative to their own plugin directory using the __FILE__ php magic constant.

plugin_url(<strong>FILE</strong>, 'css/style.css')

This function is supposed to generate a path like,

/wp-content/plugins/my-plugin/css/style.css

However when wp-content is symlinked to /var/www/mysite/wp-content, the plugins_url generates an incorrect path like,

/var/www/mysite/wp-content/plugins/my-plugin/css/style.css

As a result you start seeing unstyled content and javascript errors because these paths are invalid. This is also a security risk as it leaks your site’s internal folder structure to hackers.

This scenario is quite common in shared hosting environments. Typically these WordPress installations are fixed and individual sites correspond to symlinked wp-content directories. In such cases the problem is seen even when we did not create any symlinks ourselves.

So should we abandon symlinking wp-content and go back to copying files back-and-forth again? Or go about fixing every plugin that uses __FILE__?

Fortunately there is a simple fix. WordPress offers a plugins_url filter hook that can be used to resolve the symlinked path. We need to expand any symlinks in such a filter callback hook. The key is to do this in a plugin that loads before any other plugin.

The wordpress-plugin-symlink is a plugin that does exactly this. It hooks to the plugins_url filter and expands symlinks to their full paths. Thus all plugins get correct results when calling the plugins_url function.

To install it you need to copy this plugin into your plugin directory. Rename it’s directory to aaa-plugin-symlink to ensure it comes before any other plugins. Then enable the plugin in the WordPress admin. With that your broken CSS and Javascript paths will now start working again!

P.S. There is an ongoing discussion on WordPress Trac about this issue. It will most likely get fixed in future versions of WordPress.