I'm late answering this question but since Ian started this thread on the wp-hackers list today it made me think it worth answering especially considering I've been planning to add such a feature to some plugins I've been working on.
An approach to consider is to check on the first page load to see if the shortcode is actually used and then save the shortcode usage status to a post meta key. Here's how:
Step-by-Step How-To
- Set a
$shortcode_used
flag to 'no'
.
- In the shortcode function itself set the
$shortcode_used
flag to 'yes'
.
- Set a
'the_content'
hook priority 12
which is after WordPress has processed shortcodes and check post meta for a ''
using the key "_has_{$shortcode_name}_shortcode"
. (A value of ''
is returned when a post meta key doesn't exist for the post ID.)
- Use a
'save_post'
hook to delete the post meta clearing the persistent flag for that post in case the user changes shortcode usage.
- Also in the
'save_post'
hook use wp_remote_request()
to send a non-blocking HTTP GET to the post's own permalink to trigger to first page load and the setting of the persistent flag.
- Lastly set a
'wp_print_styles'
and check post meta for a value of 'yes'
, 'no'
or ''
using the key "_has_{$shortcode_name}_shortcode"
. If the value is 'no'
don't serve the external. If the value is 'yes'
or ''
go ahead and serve the external.
And that should do it. I've written and tested an example plugin to show how this all works.
Example Plugin Code
The plugin wakes up on a [trigger-css]
shortcode which sets the <h2>
elements on the page to white-on-red so you can easily see it working. It assumes a css
subdirectory containing style.css
file with this CSS in it:
/*
* Filename: css/style.css
*/
h2 {
color: white;
background: red;
}
And below is the code in a working plugin:
<?php
/**
* Plugin Name: CSS on Shortcode
* Description: Shows how to conditionally load a shortcode
* Author: Mike Schinkel <[email protected]>
*/
class CSS_On_Shortcode {
/**
* @var CSS_On_Shortcode
*/
private static $_this;
/**
* @var string 'yes'/'no' vs. true/false as get_post_meta() returns '' for false and not found.
*/
var $shortcode_used = 'no';
/**
* @var string
*/
var $HAS_SHORTCODE_KEY = '_has_trigger-css_shortcode';
/**
*
*/
function __construct() {
self::$_this = $this;
add_shortcode( 'trigger-css', array( $this, 'do_shortcode' ) );
add_filter( 'the_content', array( $this, 'the_content' ), 12 ); // AFTER WordPress' do_shortcode()
add_action( 'save_post', array( $this, 'save_post' ) );
add_action( 'wp_print_styles', array( $this, 'wp_print_styles' ) );
}
/**
* @return CSS_On_Shortcode
*/
function this() {
return self::$_this;
}
/**
* @param array $arguments
* @param string $content
* @return string
*/
function do_shortcode( $arguments, $content ) {
/**
* If this shortcode is being used, capture the value so we can save to post_meta in the 'the_content' filter.
*/
$this->shortcode_used = 'yes';
return '<h2>THIS POST WILL ADD CSS TO MAKE H2 TAGS WHITE ON RED</h2>';
}
/**
* Delete the 'has_shortcode' meta value so that it can be regenerated
* on first page load in case shortcode use has changed.
*
* @param int $post_id
*/
function save_post( $post_id ) {
delete_post_meta( $post_id, $this->HAS_SHORTCODE_KEY );
/**
* Now load the post asynchronously via HTTP to pre-set the meta value for $this->HAS_SHORTCODE_KEY.
*/
wp_remote_request( get_permalink( $post_id ), array( 'blocking' => false ) );
}
/**
* @param array $args
*
* @return array
*/
function wp_print_styles( $args ) {
global $post;
if ( 'no' != get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
/**
* Only bypass if set to 'no' as '' is unknown.
*/
wp_enqueue_style( 'css-on-shortcode', plugins_url( 'css/style.css', __FILE__ ) );
}
}
/**
* @param string $content
* @return string
*/
function the_content( $content ) {
global $post;
if ( '' === get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
/**
* This is the first time the shortcode has ever been seen for this post.
* Save a post_meta key so that next time we'll know this post uses this shortcode
*/
update_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, $this->shortcode_used );
}
/**
* Remove this filter now. We don't need it for this post again.
*/
remove_filter( 'the_content', array( $this, 'the_content' ), 12 );
return $content;
}
}
new CSS_On_Shortcode();
Example Screenshots
Here's a series of screenshots
Basic Post Editor, No Content
Post Display, No Content
Basic Post Editor with [trigger-css]
Shortcode
Post Display with [trigger-css]
Shortcode
Not Sure if it's 100%
I believe the above should work in almost all cases but as I just wrote this code I can't be 100% sure. If you can find situations where it doesn't work I'd really like to know so I can fix the code in some plugins I just added this to. Thanks in advance.