22

When I develop plugins I test them on multiple versions of WordPress by symlinking my plugin directory in the different wp-content directories. This is great since I only have to edit the files once, but it breaks an important construct to generate references to resources in my plugin: __FILE__ refers to the physical plugin location, not the one in wp-content. How should I solve this?

My directory structure looks like this:

  • /path/to/wordpress/development/dir/
    • plugin-development/
      • monkeyman-rewrite-analyzer/
        • monkeyman-rewrite-analyzer.php
        • js/
          • monkeyman-rewrite-analyzer.js
    • versions/
      • 3.1/
        • wp-content/
          • plugins/
            • monkeyman-rewrite-analyzer as a symlink to the above plugin
      • 3.1-multi-dir/
        • wp-content/
          • plugins/
            • monkeyman-rewrite-analyzer as a symlink to the above plugin
      • 3.1-multi-domain/
        • wp-content/
          • plugins/
            • monkeyman-rewrite-analyzer as a symlink to the above plugin

If I want to enqueue the Javascript file, I should use plugins_url( 'monkeyman-rewrite-analyzer.js', [base file] ), but using __FILE__ here will not work, because the actual file path will be /path/to/wordpress/development/dir/plugin-development/monkeyman-rewrite-analyzer/monkeyman-rewrite-analyzer.php, not /path/to/wordpress/development/dir/versions/*/wp-content/plugins/monkeyman-rewrite-analyzer/monkeyman-rewrite-analyzer.php, so WordPress cannot strip the first part out and generate a URL relative to the WordPress installation.

4 Answers 4

7

The problem can partially be addressed with a must-use plugin hooking into the plugins_url filter.

It won't handle all other cases where plugin_basename() is used, such as register_activation_hook() and co.

More info: http://core.trac.wordpress.org/ticket/16953

7
  • I believe using WP_PLUGIN_URL is not recommended because administrators should be allowed to change the name of this specific plugin's directory, but is there also another reason to avoid it? And indeed, your ticket would be a simple solution.
    – Jan Fabry
    Commented Apr 20, 2011 at 11:38
  • On the contrary. WP_PLUGIN_URL only contains the URL that points directly to the 'plugins' dir. See updated answer.
    – scribu
    Commented Apr 20, 2011 at 15:18
  • @scribu: But what if my plugins lives in /external/folder/banana-plugin/ but the admin links to that directory as /httpd-root/wp-content/plugins/apple-plugin/? Then it will try to go to /wp-content/plugins/banana-plugin/, no? And I believe the admin should be free to choose the individual plugin directory names?
    – Jan Fabry
    Commented Apr 20, 2011 at 15:35
  • I won't argue with you about that anymore, because I found the solution: the 'plugins_url' filter. Updated answer again.
    – scribu
    Commented Apr 20, 2011 at 15:38
  • FWIW this solution can be error prone and depends on plugin devs only using plugins_url() after all plugins have loaded, otherwise you can't register a filter before the function is called. the Akismet plugin and many others have that problem.
    – jerclarke
    Commented Jun 10, 2011 at 14:09
3

I currently use a trick to get the WordPress-relative file location: wp_get_active_and_valid_plugins() returns the file paths, and wp_settings.php loops over them and includes the files. So the global $plugin variable will refer to your current plugin (of course only when the plugin is loaded, so I save it in a prefixed global variable):

$monkeyman_Rewrite_Analyzer_file = $plugin;

Because plugins can also be loaded as must-use or network plugins and these loops use other variable names, the complete code looks like this:

$monkeyman_Rewrite_Analyzer_file = __FILE__;
if ( isset( $mu_plugin ) ) {
    $monkeyman_Rewrite_Analyzer_file = $mu_plugin;
}
if ( isset( $network_plugin ) ) {
    $monkeyman_Rewrite_Analyzer_file = $network_plugin;
}
if ( isset( $plugin ) ) {
    $monkeyman_Rewrite_Analyzer_file = $plugin;
}

The fallback is still __FILE__, so if someone changes the loop variable name in the future my code should still work for 99% of all installations, only my development setup will fail and I can release a new version with ease.

1
  • Great solution @Jan. I implemented something similar by calling the functions and looping because I forgot those variables were accessible as global. Thanks to your post here I realized I could make it much simpler. BTW, I'm also testing for false === strpos( __FILE__, WP_CONTENT_DIR ) before running your if statements because I'm assuming if the plugin is in the WP_CONTENT_DIR it's not symlinked; I'm hoping that's valid logic. Commented Nov 18, 2012 at 7:45
0

A comment in bug 46260 suggests to use $_SERVER["SCRIPT_FILENAME"] instead of __FILE__. Does this work?

1
  • 1
    No, this does not change in included files. So if index.php includes library.php, $_SERVER['SCRIPT_FILENAME'] in library.php will still be index.php. But thanks for the reference to the bug, I'll follow it closely!
    – Jan Fabry
    Commented Apr 20, 2011 at 10:25
0

$_SERVER["SCRIPT_FILENAME"] works if you use it right. You just have to use it to set a base path, and then include your files using a path relative to that base path.

Something like:

$plugin_dir = dirname($_SERVER["SCRIPT_FILENAME"]);
$myFile = $plugin_dir."/includes/js/myJavascriptFile.js";

Note, this is more useful when you don't have access to wp-blog-header.php yet (i.e. in processing an ajax-based form request)

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.