2

I have a framework for WordPress that can be embedded into either a plugin, a theme or a child theme. In order to return proper URLs, the script needs to determine from where it is being executed.

I believe I could do something like matching __FILE__ against:

  • get_template_directory_uri() (theme),
  • get_stylesheet_directory_uri() (theme or child theme), or
  • plugin_dir_url( __FILE__ ) (plugin)

Is there a better, more reliable approach? Any any case, how would I go about it?

Community
  • 4,922
  • 7
  • 25
  • 37
  • FYI: [Is cross-posting a question on multiple Stack Exchange sites permitted if the question is on-topic for each site?](http://meta.stackexchange.com/q/64068/185667) – brasofilo May 13 '14 at 22:43

3 Answers3

2

This answer assumes that you don't actually care if the script file is in a plugin, theme, or child theme but instead want to find out the proper URL of some assets that you package with the script that will either be in the same directory or a sub directory.

function proper_url($directory) {
    $current_directory = forward_slashes($directory);
    $plugins_directory = forward_slashes(WP_PLUGIN_DIR);
    $themes_directory = forward_slashes(get_theme_root());

    if ( strpos( $current_directory, $plugins_directory ) !== FALSE ) {
        // Script is in a plugin
        $dir = str_replace( $plugins_directory, '', $current_directory);
        $url = plugins_url() . $dir;

    } elseif ( strpos ( $current_directory, $themes_directory ) !== FALSE ) {
        // Script is in a theme
        $dir = str_replace( $themes_directory, '', $current_directory);
        $url = get_theme_root_uri() . $dir;

    } else {
        // If needed, do error handling here
        $url = FALSE;
    }

    return $url;
}

/**
 * Handle Windows paths
 */
function forward_slashes($string) {
    return str_replace('\\', '/', $string);
}

Using proper_url(__DIR__) will return the URL of wherever the script that calls the function is. As an example, if using the function from:

/wp-content/themes/my-awesome-theme/my-framework/framework.php

will return:

http://www.example.com/wp-content/themes/my-awesome-theme/my-framework/

You will notice I'm using the constant WP_PLUGIN_DIR rather than plugin_dir_path() as the latter is just a wrapper for trailingslashit( dirname( $file ) ).

vvanasten
  • 941
  • 8
  • 14
  • Thanks for your great answer! Upvoted ;) However, I'm looking for a `where_am_i()` function instead, which would return either _"plugin"_, _"theme"_ or _"child-theme"_ as a string. That would allow me to also determine internal PATH in addition to the URL. Also, a `where_am_i()` function would allow me to use the WordPress methods mentioned in the OP, which are less prone to error especially in Multisite networks, and other specific scenarios. I hope that makes sense! – Community May 14 '14 at 06:02
  • I have a couple thoughts on how to do that. If I come up with something I'll leave it as another answer in case someone is ever interested in the code above. – vvanasten May 14 '14 at 13:33
  • I added another answer that returns the strings you're looking for. – vvanasten May 14 '14 at 14:59
2

This function will return a string indicating where it is called from. The possible return values are plugin, mu-plugin, child-theme, theme, or FALSE if it is not in a theme or plugin.

When using this function, always pass __DIR__ as the parameter, example: where_am_i(__DIR__).

/**
 * @param string $directory always __DIR__
 */
function where_am_i($directory) {
    $current_directory = forward_slashes($directory);
    $plugins_directory = forward_slashes(WP_PLUGIN_DIR);
    $mu_plugins_directory = forward_slashes(WPMU_PLUGIN_DIR);
    $themes_directory = forward_slashes(get_theme_root());

    if ( strpos ( $current_directory, $plugins_directory ) !== FALSE ) {
        $location = 'plugin';

    } elseif ( strpos ( $current_directory, $mu_plugins_directory ) !== FALSE ) {
        $location = 'mu-plugin';

    } elseif ( strpos ( $current_directory, $themes_directory ) !== FALSE ) {
        // Script is in a theme, determine if parent or child
        $stylesheet_directory = forward_slashes(get_stylesheet_directory());

        if ( is_child_theme() && ( strpos ( $current_directory, $stylesheet_directory ) !== FALSE ) ) {
            $location = 'child-theme';
        } else {
            $location = 'theme';
        }

    } else {
        // not in a theme or plugin
        $location = FALSE;
    }

    return $location;
}

/**
 * Handle Windows paths
 */
function forward_slashes($string) {
    return str_replace('\\', '/', $string);
}

The following function, where_am_i_dir(), will give you the directory structure of the location it was called from, but omit */wp-content/{$subdir}. If it was called from /wp-content/themes/twentyfourteen/libs/script.php it will return /twentyfourteen/libs (if you want it to return with a trailing slash you can concatenate one to $directory when the slashes are filterd).

The first parameter is the return value from where_am_i() and the second parameter is always __DIR__. Example: where_am_i_dir($location, __DIR__).

/**
 * @param string $location return from where_am_i()
 * @param string $directory always __DIR__
 */
function where_am_i_dir($location, $directory) {
    if ($location == 'plugin') {
        $subdirectory_name = '/plugins';

    } elseif ($location == 'mu-plugin') {
        $subdirectory_name = '/mu-plugins';

    } elseif ($location == 'theme' || $location == 'child-theme') {
        $subdirectory_name = '/themes';

    } else {
        return FALSE;
    }

    $directory = forward_slashes($directory);
    $wp_content_directory = forward_slashes(WP_CONTENT_DIR) . $subdirectory_name;

    return str_replace($wp_content_directory, '', $directory);
}

If you were interested you could probably combine where_am_i() and where_am_i_dir() into one function that returns an array with both values.

vvanasten
  • 941
  • 8
  • 14
  • Thank you very much sir, I have upvoted and accepted your answer! In addition to that, would you recommend a way to get the actual path in which the script is located within the themes/plugins dir? What I mean is, for example if the script is located in `/wp-content/themes/mytheme/libs/script.php` then your function will return "theme", which is great, but then how do I know it's in `/mytheme/libs/`? Thanks again! – Community May 15 '14 at 18:52
  • I've updated my answer to add an extra function that will do what you're looking for in respect to the paths. – vvanasten May 15 '14 at 20:38
  • You're awesome, thanks a lot! I wish I could upvote you twice ;) – Community May 15 '14 at 20:55
  • _"If you were interested you could probably combine where_am_i() and where_am_i_dir() into one function that returns an array with both values."_ Yes that would make better sense actually! – Community May 15 '14 at 20:56
-1

See php function http://php.net/manual/en/function.debug-backtrace.php

Source: Caller function in PHP 5?

I hope it helps you!

Community
  • 1
  • 1
  • Sorry for downvoting but your answer is not related to the question at all. I don't need to get the location of the caller function as I already know where I am using `__FILE__`, the question is to know if the current file is within any of the known WordPress hierarchy directories that contain plugins and themes. We can do that using [`strpos()`](http://www.php.net/strpos) but it's not that easy because the plugins and themes directories could change from one installation to another. – Community May 14 '14 at 06:08