Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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.

share|improve this question
add comment

4 Answers

$_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)

share|improve this answer
add comment

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

share|improve this answer
    
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 Apr 20 '11 at 11:38
    
On the contrary. WP_PLUGIN_URL only contains the URL that points directly to the 'plugins' dir. See updated answer. –  scribu Apr 20 '11 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 Apr 20 '11 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 Apr 20 '11 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. –  Jeremy Clarke Jun 10 '11 at 14:09
show 1 more comment

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.

share|improve this answer
    
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. –  MikeSchinkel Nov 18 '12 at 7:45
add comment

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

share|improve this answer
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 Apr 20 '11 at 10:25
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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