admin管理员组文章数量:1336008
What is the idea way to register/enqueue scripts and/or styles for use in plugins?
I recently made a plugin simple plugin to add the user avatar/gravatar with a shortcode. I have different style options for displaying the avatar (square, round, etc.) and decided to put the css directly in the shortcode itself.
However, I realize now this isn't a good approach since it will repeat the css every time the shortcode is used on a page. I've seen several other approaches on this site and the wp codex even has two examples of their own so it's hard to know what approach is most consistent and fastest.
Here are the methods I currently am aware of:
Method 1: Include directly in shortcode - This is what I'm currently doing in the plugin, but doesn't seem good since it repeats code.
class My_Shortcode {
function handle_shortcode( $atts, $content="" ) {
/* simply enqueue or print the scripts/styles in the shortcode itself */
?>
<style type="text/css">
</style>
<?php
return "$content";
}
}
add_shortcode( 'myshortcode', array( 'My_Shortcode', 'handle_shortcode' ) );
Method 2: Use class for enqueueing scripts or styles conditionally
class My_Shortcode {
static $add_script;
static function init() {
add_shortcode('myshortcode', array(__CLASS__, 'handle_shortcode'));
add_action('init', array(__CLASS__, 'register_script'));
add_action('wp_footer', array(__CLASS__, 'print_script'));
}
static function handle_shortcode($atts) {
self::$add_script = true;
// shortcode handling here
}
static function register_script() {
wp_register_script('my-script', plugins_url('my-script.js', __FILE__), array('jquery'), '1.0', true);
}
static function print_script() {
if ( ! self::$add_script )
return;
wp_print_scripts('my-script');
}
}
My_Shortcode::init();
Method 3: Using get_shortcode_regex();
function your_prefix_detect_shortcode() {
global $wp_query;
$posts = $wp_query->posts;
$pattern = get_shortcode_regex();
foreach ($posts as $post){
if ( preg_match_all( '/'. $pattern .'/s', $post->post_content, $matches )
&& array_key_exists( 2, $matches )
&& in_array( 'myshortcode', $matches[2] ) )
{
// css/js
break;
}
}
}
add_action( 'wp', 'your_prefix_detect_shortcode' );
Method 4: Using has_shortcode();
function custom_shortcode_scripts() {
global $post;
if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'myshortcode') ) {
wp_enqueue_script( 'my-script');
}
}
add_action( 'wp_enqueue_scripts', 'custom_shortcode_scripts');
What is the idea way to register/enqueue scripts and/or styles for use in plugins?
I recently made a plugin simple plugin to add the user avatar/gravatar with a shortcode. I have different style options for displaying the avatar (square, round, etc.) and decided to put the css directly in the shortcode itself.
However, I realize now this isn't a good approach since it will repeat the css every time the shortcode is used on a page. I've seen several other approaches on this site and the wp codex even has two examples of their own so it's hard to know what approach is most consistent and fastest.
Here are the methods I currently am aware of:
Method 1: Include directly in shortcode - This is what I'm currently doing in the plugin, but doesn't seem good since it repeats code.
class My_Shortcode {
function handle_shortcode( $atts, $content="" ) {
/* simply enqueue or print the scripts/styles in the shortcode itself */
?>
<style type="text/css">
</style>
<?php
return "$content";
}
}
add_shortcode( 'myshortcode', array( 'My_Shortcode', 'handle_shortcode' ) );
Method 2: Use class for enqueueing scripts or styles conditionally
class My_Shortcode {
static $add_script;
static function init() {
add_shortcode('myshortcode', array(__CLASS__, 'handle_shortcode'));
add_action('init', array(__CLASS__, 'register_script'));
add_action('wp_footer', array(__CLASS__, 'print_script'));
}
static function handle_shortcode($atts) {
self::$add_script = true;
// shortcode handling here
}
static function register_script() {
wp_register_script('my-script', plugins_url('my-script.js', __FILE__), array('jquery'), '1.0', true);
}
static function print_script() {
if ( ! self::$add_script )
return;
wp_print_scripts('my-script');
}
}
My_Shortcode::init();
Method 3: Using get_shortcode_regex();
function your_prefix_detect_shortcode() {
global $wp_query;
$posts = $wp_query->posts;
$pattern = get_shortcode_regex();
foreach ($posts as $post){
if ( preg_match_all( '/'. $pattern .'/s', $post->post_content, $matches )
&& array_key_exists( 2, $matches )
&& in_array( 'myshortcode', $matches[2] ) )
{
// css/js
break;
}
}
}
add_action( 'wp', 'your_prefix_detect_shortcode' );
Method 4: Using has_shortcode();
function custom_shortcode_scripts() {
global $post;
if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'myshortcode') ) {
wp_enqueue_script( 'my-script');
}
}
add_action( 'wp_enqueue_scripts', 'custom_shortcode_scripts');
Share
Improve this question
asked Oct 18, 2014 at 7:07
Bryan WillisBryan Willis
4,4793 gold badges34 silver badges47 bronze badges
4
|
10 Answers
Reset to default 88I found an other way that works well for me:
When initializing the plugin, do not enqueue your scripts and styles, but register them with
wp_register_style
andwp_register_script
.Next you can load the script/style on demand. For example when you render a shortcode with
wp_enqueue_style("your_style")
andwp_enqueue_script("your_script")
.
Here is an example plugin using this method that lets you use get_avatar in a shortcode. The stylesheet is only enqueued when the shortcode is present.
Usage (id defaults to current user):
[get_avatar id="" size="32" default="mystery" alt="Profile Photo" class="round"]
function wpse_165754_avatar_shortcode_wp_enqueue_scripts() {
wp_register_style( 'get-avatar-style', plugins_url( '/css/style.css', __FILE__ ), array(), '1.0.0', 'all' );
}
add_action( 'wp_enqueue_scripts', 'wpse_165754_avatar_shortcode_wp_enqueue_scripts' );
if ( function_exists( 'get_avatar' ) ) {
function wpse_165754_user_avatar_shortcode( $attributes ) {
global $current_user;
get_currentuserinfo();
extract( shortcode_atts(
array(
"id" => $current_user->ID,
"size" => 32,
"default" => 'mystery',
"alt" => '',
"class" => '',
), $attributes, 'get_avatar' ) );
$get_avatar = get_avatar( $id, $size, $default, $alt );
wp_enqueue_style( 'get-avatar-style' );
return '<span class="get_avatar ' . $class . '">' . $get_avatar . '</span>';
}
add_shortcode( 'get_avatar', wpse_165754_user_avatar_shortcode' );
}
Before starting answer I have to say that regarding this topic css and js are not the same.
The reason is simple: while adding js to the body of the page (in footer) is a common and valid way to go, css need to be placed in the <head>
section of the page: even if majority of browsers can proper render css in page body, that's not valid HTML code.
When a shortcode is rendered, <head>
section was already printed, it means that js can be added without any problem on footer, but css must be added before the shortcode is rendered.
Scripts
If your shortcode needs only js you are lucky and can just use wp_enqueue_script
in the body of shortcode callback:
add_shortcode( 'myshortcode', 'my_handle_shortcode' );
function my_handle_shortcode() {
wp_enqueue_script( 'myshortcodejs', '/path/to/js/file.js' );
// rest of code here...
}
Doing so your script is added to the footer and only once, even if the shortcode is used more than once in the page.
Styles
If you code needs styles, then you need to act before shortcode is actually rendered.
There are different ways to do this:
look at all the posts in current query and add the shortcode styles if needed. This is what you do in both method #3 and #4 in OP. In fact, both two methods do same thing, but
has_shortcode
was added in WP 3.6, whileget_shortcode_regex
is available since version 2.5, so useget_shortcode_regex
only if you want make your plugin compatible with older versions.always add shortcode style, in all pages
Issues
Issue with #1 is performance. Regex are pretty slow operations and launch regex in a loop of all posts may slow down page consistently. Moreover, it's a pretty common task in themes to show only post excerpt in archives and show full content with shortcodes only in singular views. If that happen, when an archive is shown, your plugin will launch a regex matching in a loop with the aim to add a style that will never be used: an unnecessary double performance impact: slow down page generation + additional unnecessary HTTP request
Issue with #2 is performance, again. Adding style to all pages means add an additional HTTP request for all pages, even when not needed. Even if server side page generation time is not affected, total page rendering time will, and for all site pages.
So, what does a plugin developer should do?
I think that best thing to do is adding an option page to plugin, where users can choose if the shortcode should be handled in singular view only or even in archives. In both cases is better to provide another option to choose for which post types enable shortcode.
In that way is possible to hook "template_redirect"
to check if current query satisfy requirements and in that case add the style.
If user choose to use shortcode only in singular post views, is a good idea check if post has shortcode or not: once only one regex is required it should not slow down page so much.
If user choose to use shortcode even in archives, then I would avoid to run regex for all posts if number of posts is high and just enqueue the style if query fit requirements.
What to consider "high" on this regard should be get using some performance tests or, as alternative, add another option and give choice to users.
For my plugin I found that sometimes users have a theme builder that has shortcode stored in post meta data. Here is what I am using to detect whether my plugin shortcode is present in current post or post meta data:
function abcd_load_my_shorcode_resources() {
global $post, $wpdb;
// determine whether this page contains "my_shortcode" shortcode
$shortcode_found = false;
if ( has_shortcode($post->post_content, 'my_shortcode') ) {
$shortcode_found = true;
} else if ( isset($post->ID) ) {
$result = $wpdb->get_var( $wpdb->prepare(
"SELECT count(*) FROM $wpdb->postmeta " .
"WHERE post_id = %d and meta_value LIKE '%%my_shortcode%%'", $post->ID ) );
$shortcode_found = ! empty( $result );
}
if ( $shortcode_found ) {
wp_enqueue_script(...);
wp_enqueue_style(...);
}
}
add_action( 'wp_enqueue_scripts', 'abcd_load_my_shorcode_resources' );
WordPress has a built-in function to do something based on a specific Shortcode presenting status. The function name is has_shortcode()
. You can use the following code to enqueue your style and scripts.
Here I used the is_a( $post, 'WP_Post' )
to check if the $post
object is of the WP_Post
class and I used $post->post_content
to check the post content.
if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'shortcode_tag') ) {
wp_enqueue_style( 'handle', get_template_directory_uri() . '/your_file_filename.css' );
}
I do so:
class My_Shortcode {
function __construct() {
do_action('my_start_shortcode'); // call
....
and catch hook in other functions (or other plugins):
function wpse_3232_load_script(){
wp_enqueue_script('js-myjs');
}
add_action('my_start_shortcode','wpse_3232_load_script',10);
As someone mentioned using 'has_shortcode' will do it. Here's the example I found very helpful (Source: Wordpress)
function wpdocs_shortcode_scripts() {
global $post;
if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'wpdocs-shortcode') ) {
wp_enqueue_script( 'wpdocs-script');
}
}
add_action( 'wp_enqueue_scripts', 'wpdocs_shortcode_scripts');
We can indeed conditionally load CSS and JS files via shortcode without using any overly elaborate functions:
First, let's assume we registered all of our CSS/JS files previously (perhaps when wp_enqueue_scripts
ran)
function prep_css_and_js() {
wp_register_style('my-css', $_css_url);
wp_register_script('my-js', $_js_url);
}
add_action( 'wp_enqueue_scripts', 'prep_css_and_js', 5 );
Next, lets examine our shortcode function:
function my_shortcode_func( $atts, $content = null ) {
if( ! wp_style_is( "my-css", $list = 'enqueued' ) ) { wp_enqueue_style('my-css'); }
if( ! wp_script_is( "my-js", $list = 'enqueued' ) ) { wp_enqueue_script('my-js'); }
...
}
Simple. Done. Ergo: we can "conditionally load" css/js files, (only when [shortcode] runs).
Let's consider the following ideology:
- We want to load certain CSS/JS files (but only when shortcode is triggered)
- Maybe we do not want those files to load on every page, or at all if the shortcode is not used on a page/post. (light weight)
- We can accomplish this by making sure WP registers ALL of the css/js files prior to calling the shortcode and prior to the enqueue.
- IE: Maybe during my
prep_css_and_js()
function I load ALL .css/.js files that are in certain folders...
Now that WP sees them as registered scripts, we can indeed call them, conditionally, based on a variety of situations, including but not limited to my_shortcode_func()
Benefits: (no MySQL, no advanced functions and no filters needed)
- this is "WP orthodox", elegant, fast loading, easy and simple
- allows compilers/minifiers to detect such scripts
- uses the WP functions (wp_register_style/wp_register_script)
- compatible with more themes/plugins that might want to de-register those scripts for a variety of reasons.
- will not trigger multiple times
- very little processing or code is involved
References:
- https://codex.wordpress/Function_Reference/wp_script_is
- https://codex.wordpress/Function_Reference/wp_register_style
- https://codex.wordpress/Function_Reference/wp_register_script
- https://developer.wordpress/reference/functions/wp_enqueue_scripts/
I did find out for my own plugin, if the shortcode is present in the text widget.
function check_shortcode($text) {
$pattern = get_shortcode_regex();
if ( preg_match_all( '/'. $pattern .'/s', $text, $matches )
&& array_key_exists( 2, $matches )
&& in_array( 'myshortcode', $matches[2] ) )
{
// myshortcode is being used
// enque my css and js
/****** Enqueu RFNB ******/
wp_enqueue_style('css-mycss');
wp_enqueue_script('js-myjs');
// OPTIONAL ALLOW SHORTCODE TO WORK IN TEXT WIDGET
add_filter( 'widget_text', 'shortcode_unautop');
add_filter( 'widget_text', 'do_shortcode');
}
return $text;
}
add_filter('widget_text', 'check_shortcode');
I made a combination of the example code from the Wordpress page for has_shortcode() and the answer zndencka gave. I did notice that the has_shortcode function is added in Wordpress 3.6, so that's why I first check if the function exists. Maybe that check is a bit obsolete though, since there aren't many users from below wordpress 3.6 anymore according to wordpress their own stats.
// This makes sure the styling is already enqueued in the header, so before the shortcode loads in the page/post
function enqueue_shortcode_header_script() {
global $post;
if ( function_exists( 'has_shortcode' ) ){ // is added in wordpress 3.6
// Source: https://codex.wordpress/Function_Reference/has_shortcode
if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'my_shortcode') ) {
wp_enqueue_style( 'shortcode-css' );
}
}
else if ( isset($post->ID) ) { // Small percentage wordpress users are below 3.6 https://wordpress/about/stats/
global $wpdb;
$result = $wpdb->get_var(
$wpdb->prepare(
"SELECT count(*) FROM $wpdb->postmeta " .
"WHERE post_id = %d and meta_value LIKE '%%my_shortcode%%'",
$post->ID )
);
if (!empty( $result )) { wp_enqueue_style( 'shortcode-css' ); }
}
}
add_action( 'wp_enqueue_scripts', 'enqueue_shortcode_header_script');
I use WordPress Version 5.4 with OOP style of code i dont know if this affect why none of the above solutions didn't work for me so i come up with this solution:
public function enqueue_scripts() {
global $post;
//error_log( print_r( $post, true ) );
//error_log( print_r( $post->post_content, true ) );
//error_log( print_r( strpos($post->post_content, '[YOUR_SHORTCODE]'),true));
if ( is_a( $post, 'WP_Post' ) && strpos($post->post_content, '[YOUR_SHORTCODE]') )
{
wp_register_style('my-css', $_css_url);
wp_register_script('my-js', $_js_url);
}
}
Hope this help someone.
本文标签: Enqueue ScriptsStyles when shortcode is present
版权声明:本文标题:Enqueue ScriptsStyles when shortcode is present 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741799738a2398147.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Method 4: Using has_shortcode();
is best because it will ensure that scripts and styles will load once if post content has shortcode regardless of multiple uses of shortcode. Although it might not work for shortcode uses in widgets or in sidebar, not sure though. If it's for a plugin then I would not recommend you to tie scripts with shortcode because some might call your function instead of shortcode to get desired output. – Robert hue Commented Oct 18, 2014 at 7:46! wp_style_is
along with method 4 and enqueue the style there incase it's not added in the earlierwp_enqueue_scripts
callback – Adeel Raza Commented Oct 14, 2020 at 10:23