Whether you’re building a simple feature plugin or a full-fledged product, adding your scripts and styles is often essential. Handling these front-end assets the right way in WordPress ensures compatibility and maintainability and prevents conflicts with other plugins or themes. The proper approach is to enqueue your scripts and styles rather than hardcoding them directly into templates.
In this article, we’ll explain how to enqueue scripts and styles in a WordPress plugin properly. We’ll discuss best practices for using wp_enqueue_script() and wp_enqueue_style(), which hooks to use, how to ensure correct file paths, dependency management, versioning, and conditionally loading assets only where needed. By following these guidelines, you can ensure your plugin behaves gracefully in any WordPress environment.
Why not just print <link> and <script> tags directly? While it might be tempting to echo out your stylesheets and scripts in a template file or admin page, this leads to potential problems:
In short, the enqueue system is central to how WordPress handles front-end assets. Embracing it leads to cleaner code, fewer conflicts, and a better-maintained plugin.

What it does: Registers and enqueues JavaScript files. It ensures each script is loaded once, in the correct order based on declared dependencies.
Function Signature:
wp_enqueue_script(
string $handle,
string $src = '',
array $deps = [],
string|bool|null $ver = false,
bool $in_footer = false
);
What it does: Registers and enqueues CSS stylesheets.
Function Signature:
wp_enqueue_style(
string $handle,
string $src = '',
array $deps = [],
string|bool|null $ver = false,
string $media = 'all'
);

To ensure WordPress knows when to load your assets, you should place your enqueue calls inside specific hooks:
For front-end assets: Use the wp_enqueue_scripts hook.
add_action( 'wp_enqueue_scripts', 'myplugin_enqueue_frontend_assets' );
For admin assets: Use the admin_enqueue_scripts hook.
add_action( 'admin_enqueue_scripts', 'myplugin_enqueue_admin_assets' );
Example:
add_action( 'wp_enqueue_scripts', 'myplugin_enqueue_frontend_assets' );
function myplugin_enqueue_frontend_assets() {
wp_enqueue_script( 'myplugin-script', plugin_dir_url(__FILE__) . 'js/myplugin-frontend.js', ['jquery'], '1.0.0', true );
wp_enqueue_style( 'myplugin-style', plugin_dir_url(__FILE__) . 'css/myplugin-style.css', [], '1.0.0' );
}
By using plugin_dir_url(__FILE__), we dynamically get the plugin’s directory URL, ensuring that paths are always correct regardless of where the plugin is installed.
When enqueuing assets, you need the correct file URL. Hardcoding paths can break when someone moves your plugin to a different folder. To avoid this, use WordPress functions:
Example:
$plugin_url = plugin_dir_url( __FILE__ );
wp_enqueue_script( 'myplugin-script', $plugin_url . 'js/myplugin.js', [], '1.0.0', true );
This is preferred over get_stylesheet_directory_uri() or get_template_directory_uri() because those point to the theme directory, not the plugin folder.
Sometimes, your script relies on another script to be loaded first. For example, if you use jQuery functions in your script, you must ensure jQuery loads before your code. WordPress includes a set of default scripts (like jQuery) you can rely on as dependencies.
Example:
wp_enqueue_script( 'myplugin-script', $plugin_url . 'js/myplugin.js', ['jquery'], '1.0.0', true );
It ensures jQuery loads first. For styles, you can depend on another stylesheet handle to ensure the correct load order.
Identifying handles:
Common core script handles include jQuery, wp-element, wp-blocks, and wp-i18n. You can also depend on styles or scripts registered by other plugins or themes if you know their handles.
When you update your plugin’s CSS or JS, browsers might serve older cached files. To prevent this, use the $ver parameter in wp_enqueue_script() and wp_enqueue_style(). Incrementing the version forces browsers to fetch the latest file.
Example:
wp_enqueue_style( 'myplugin-style', $plugin_url . 'css/myplugin-style.css', [], '1.0.1' );
Alternatively, you can use a file modification time as a version:
$version = filemtime( plugin_dir_path(__FILE__) . 'css/myplugin-style.css' );
wp_enqueue_style( 'myplugin-style', $plugin_url . 'css/myplugin-style.css', [], $version );
It ensures whenever the file changes, the version changes automatically.
By default, scripts load in the header. To improve performance and prevent blocking the rendering of the page, you can load scripts in the footer by setting $in_footer = true.
Example:
wp_enqueue_script( 'myplugin-script', $plugin_url . 'js/myplugin.js', ['jquery'], '1.0.0', true );
It places your script before the </body> tag, making the page appear faster and more responsive.
It’s wasteful to load assets site-wide if only needed on a single page or admin screen. For example, if your plugin adds a custom settings page in the admin, load scripts only on that page.
Using get_current_screen() in the admin:
add_action( 'admin_enqueue_scripts', 'myplugin_admin_assets' );
function myplugin_admin_assets( $hook_suffix ) {
$screen = get_current_screen();
if ( $screen && 'toplevel_page_myplugin-settings' === $screen->id ) {
// Enqueue scripts and styles only on myplugin settings page
wp_enqueue_script( 'myplugin-admin', plugin_dir_url(__FILE__) . 'js/myplugin-admin.js', [], '1.0.0', true );
}
}
Using $_GET[‘page’]:
If you know the page parameter for your plugin’s admin page, you can use it:
if ( isset( $_GET['page'] ) && 'myplugin-settings' === $_GET['page'] ) {
wp_enqueue_script( 'myplugin-admin', plugin_dir_url(__FILE__) . 'js/myplugin-admin.js', [], '1.0.0', true );
}
On the Front End:
If your script is only needed on a specific template (like single posts), you might use conditions like is_single():
add_action( 'wp_enqueue_scripts', 'myplugin_frontend_assets' );
function myplugin_frontend_assets() {
if ( is_single() ) {
wp_enqueue_style( 'myplugin-style', plugin_dir_url(__FILE__) . 'css/myplugin-single.css', [], '1.0.0' );
}
}
It prevents unnecessary code from loading on the home page or archives.
Your plugin might need different assets for the front end and the back end. By using separate hooks (wp_enqueue_scripts for front end, admin_enqueue_scripts for admin), you keep logic clean and straightforward.
Front end:
add_action( 'wp_enqueue_scripts', 'myplugin_frontend_assets' );
function myplugin_frontend_assets() {
wp_enqueue_script( 'myplugin-frontend', plugin_dir_url(__FILE__) . 'js/frontend.js', ['jquery'], '1.0.0', true );
wp_enqueue_style( 'myplugin-frontend-style', plugin_dir_url(__FILE__) . 'css/frontend.css', [], '1.0.0' );
}
Admin:
add_action( 'admin_enqueue_scripts', 'myplugin_admin_assets' );
function myplugin_admin_assets( $hook ) {
if ( 'toplevel_page_myplugin-settings' === $hook ) {
wp_enqueue_script( 'myplugin-admin', plugin_dir_url(__FILE__) . 'js/admin.js', [], '1.0.0', true );
wp_enqueue_style( 'myplugin-admin-style', plugin_dir_url(__FILE__) . 'css/admin.css', [], '1.0.0' );
}
}
Often, you need to pass dynamic data from PHP to your JavaScript code. For example, API endpoints, nonce values, or user roles. WordPress offers wp_localize_script() to inject data as a JavaScript object before your script runs.
Example:
add_action( 'wp_enqueue_scripts', 'myplugin_frontend_assets' );
function myplugin_frontend_assets() {
wp_enqueue_script( 'myplugin-frontend', plugin_dir_url(__FILE__) . 'js/frontend.js', ['jquery'], '1.0.0', true );
$data = [
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'myplugin_nonce' )
];
wp_localize_script( 'myplugin-frontend', 'mypluginData', $data );
}
In your JavaScript, mypluginData.ajax_url and mypluginData.nonce are now available.
Note: wp_localize_script() must be called after wp_enqueue_script() for the same handle.
To avoid conflicts:
Sometimes, you want to register scripts and styles first without immediately enqueuing them. Then, enqueue them conditionally later.
Example:
add_action( 'init', 'myplugin_register_assets' );
function myplugin_register_assets() {
wp_register_script( 'myplugin-conditional', plugin_dir_url(__FILE__) . 'js/conditional.js', [], '1.0.0', true );
wp_register_style( 'myplugin-conditional', plugin_dir_url(__FILE__) . 'css/conditional.css', [], '1.0.0' );
}
add_action( 'wp_enqueue_scripts', 'myplugin_enqueue_conditional' );
function myplugin_enqueue_conditional() {
if ( is_page( 'special-page' ) ) {
wp_enqueue_script( 'myplugin-conditional' );
wp_enqueue_style( 'myplugin-conditional' );
}
}
This approach gives you flexibility and improves performance by not loading assets unnecessarily.
If your plugin creates Gutenberg blocks, enqueue block editor scripts and styles using enqueue_block_editor_assets. For front-end block styles, use enqueue_block_assets.
Example:
add_action( 'enqueue_block_editor_assets', 'myplugin_block_editor_scripts' );
function myplugin_block_editor_scripts() {
wp_enqueue_script( 'myplugin-block-editor', plugin_dir_url(__FILE__) . 'js/block-editor.js', ['wp-blocks', 'wp-element'], '1.0.0', true );
wp_enqueue_style( 'myplugin-block-editor-style', plugin_dir_url(__FILE__) . 'css/block-editor.css', [], '1.0.0' );
}
add_action( 'enqueue_block_assets', 'myplugin_block_frontend_styles' );
function myplugin_block_frontend_styles() {
wp_enqueue_style( 'myplugin-block-style', plugin_dir_url(__FILE__) . 'css/block-style.css', [], '1.0.0' );
}
It ensures the correct assets load only in the appropriate context—editor or front end.
Properly enqueuing scripts and styles in a WordPress plugin is a fundamental skill that ensures your code integrates smoothly with WordPress’s built-in mechanisms for asset management. By following the guidelines:
By taking these steps, your plugin will be more robust, conflict-free, and easier to maintain. Embracing these best practices leads to a better experience for you as a developer and for the users who install your plugin.
God willing, this guide helps you become more confident in handling scripts and styles within WordPress, making your plugins more professional, efficient, and user-friendly.

Hassan Tahir wrote this article, drawing on his experience to clarify WordPress concepts and enhance developer understanding. Through his work, he aims to help both beginners and professionals refine their skills and tackle WordPress projects with greater confidence.