One of the most common mistakes when you start writing WordPress plugins or themes is building path strings by hand. Something like this:
// Do not do this
include '/home/user/public_html/wp-content/plugins/my-plugin/inc/helper.php';
That code works on your machine and breaks the moment it lands on a different server. WordPress ships a set of functions for getting paths, and the first thing to understand is that there are two completely different kinds of path.
Filesystem paths and URLs
A filesystem path is where the file sits on the server’s disk, for example /var/www/html/wp-content/plugins/my-plugin/. Use it when you are working with files in PHP: include, require, file_get_contents, fopen.
A URL is an address the browser can reach, for example https://example.com/wp-content/plugins/my-plugin/. Use it when you are embedding assets into a page: CSS, JavaScript, images.
Mixing these two up causes a lot of confusing bugs. Put a filesystem path in an <img> tag and the image never loads. include a URL and you either get an error or open a serious security hole.
Quick reference
| Function | Returns | Example result |
|---|---|---|
ABSPATH | WordPress root path | /var/www/html/ |
plugin_dir_path( __FILE__ ) | Path to the current plugin directory | /var/www/html/wp-content/plugins/my-plugin/ |
plugin_dir_url( __FILE__ ) | URL of the current plugin directory | https://example.com/wp-content/plugins/my-plugin/ |
plugins_url() | URL of the /plugins directory | https://example.com/wp-content/plugins |
get_template_directory() | Parent theme path | /var/www/html/wp-content/themes/parent/ |
get_stylesheet_directory() | Active theme path (child if there is one) | /var/www/html/wp-content/themes/child/ |
get_stylesheet_directory_uri() | Active theme URL | https://example.com/wp-content/themes/child |
content_url() | URL of /wp-content | https://example.com/wp-content |
includes_url() | URL of /wp-includes | https://example.com/wp-includes |
admin_url() | URL of the admin area | https://example.com/wp-admin/ |
site_url() | URL where WordPress is installed | https://example.com |
home_url() | URL of the home page | https://example.com |
wp_upload_dir() | Array with both path and URL for uploads | see below |
In a plugin
In the main plugin file, the standard approach is to define constants once and reuse them:
<?php
define( 'MY_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
define( 'MY_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
// Loading PHP files: use PATH
require_once MY_PLUGIN_PATH . 'includes/class-loader.php';
// Enqueuing assets: use URL
function my_plugin_assets() {
wp_enqueue_style( 'my-plugin', MY_PLUGIN_URL . 'assets/style.css', [], '1.0.0' );
wp_enqueue_script( 'my-plugin', MY_PLUGIN_URL . 'assets/app.js', [ 'jquery' ], '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_assets' );
__FILE__ is a PHP constant pointing at the currently executing file, so both functions give correct results no matter where the plugin is installed.
In a theme
For themes, the important thing is telling parent and child apart:
// Always points at the PARENT theme, even when a child theme is active
get_template_directory();
get_template_directory_uri();
// Points at the ACTIVE theme (child if there is one, otherwise the parent)
get_stylesheet_directory();
get_stylesheet_directory_uri();
The practical rule: when you are writing code in a child theme and want to reference the child theme’s own files, use get_stylesheet_directory(). When you want to reference the parent theme’s files, use get_template_directory().
The uploads directory
wp_upload_dir() returns an array rather than a string:
$upload = wp_upload_dir();
echo $upload['basedir']; // /var/www/html/wp-content/uploads
echo $upload['baseurl']; // https://example.com/wp-content/uploads
echo $upload['path']; // .../uploads/2026/09 (current month's folder)
echo $upload['url']; // .../uploads/2026/09
Never assume the uploads directory is at wp-content/uploads, because it can be moved through configuration.
site_url() or home_url()
These two usually return the same value, which is why people mix them up. They only differ when WordPress is installed in a subdirectory but the site runs at the root domain:
site_url()returnshttps://example.com/wordpress(where the code lives)home_url()returnshttps://example.com(the address visitors see)
The rule: for links shown to visitors use home_url(), and for pointing at WordPress core files use site_url().
One note on escaping
None of the URL functions escape their output. When you print them into HTML, wrap them:
<img src="<?php echo esc_url( MY_PLUGIN_URL . 'assets/logo.png' ); ?>" alt="Logo">