I created a WordPress plug which provides a custom post type (Slides) and these can be grouped by a taxonomy (Slideshows). Using a shortcode [slides], you can display these Slides and filter them by Slideshow. Here’s how I coded the shortcode:
function slds_shortcode( $atts ) {
extract( shortcode_atts( array(
'slideshow' => 'all',
'timeout' => '5000',
), $atts ) );
$slideshow = $atts[slideshow];
global $post;
$tmp_post = $post;
$args = array( 'slideshows' => $slideshow, 'timeout' => $timeout, );
$myposts = get_posts( $args );
ob_start(); // Helps output the HTML where the shortcode is (otherwise it outputs before the content).
?>
<div id="<?php echo $slideshow; ?>" class="slds-slideshow">
<div class="timeout-<?php echo $timeout; ?>">
<?php foreach( $myposts as $post ) : setup_postdata($post); ?>
<div class="slide">
<?php the_content(); ?>
</div>
<?php endforeach; ?>
</div>
</div>
<?php
$post = $tmp_post;
return ob_get_clean();
}
add_shortcode('slides', 'slds_shortcode');
The scripts and stylesheet are included in the footer, only if a shortcode is found in the post. The script (responsiveslides.js) requires an init, which currently outputs in the footer whether a shortcode is found in the post or not. Here’s how I generate that:
function slds_init() {
echo '
<script>
jQuery(function($) {
$(document).ready(function() {
$(".slds-slideshow .timeout-5000").responsiveSlides({
pause: true,
nav: true,
pager: true,
timeout: 5000,
speed: 1800
});
$(".slds-slideshow .timeout-10000").responsiveSlides({
pause: true,
nav: true,
pager: true,
timeout: 10000,
speed: 1800
});
});
});
</script>';
}
add_action('wp_footer', 'slds_init');
This works great, so long as the defaults I coded in there are suitable for the project. Instead, I’d like to be able to set these parameters in the shortcode like: [slides slideshow=tour timeout=10000 speed=1200]. As you can see above, the init has a few major limitations. It selects ALL instances of .slds-slideshow instead of selecting each shortcode output individually by a unique id or class, meaning these default parameters have to be used for all shortcode outputs. In fact, the reason I have two jQuery selectors is so I can add an alternate .timeout class to the output, which just changes which jQuery selector is affecting the shortcode output (or slideshow HTML if you will). This is a shoddy solution. Obviously if I relied on classes for all the parameters this way, with the virtually infinite number of parameter combinations, the init would become extremely heavy and clunky.
How can I generate that middle section of the init (the jQuery selectors and their parameters) based on the shortcode attributes in such a way that they still correlate to the HTML output of the shortcodes in the post?
Edit
Thanks again @birgire for your ideas! I think they got me much closer to where I need to be.
I tried out a lot of options. I think the main thing I’m still running into is getting shortcode instances to generate anything in my javascript initialization. I put wp_localize_script() in my shortcode function as @birgire suggested:
wp_localize_script('slds_script', 'slds_vars', array(
'instance' => $instance,
'timeout' => $timeout,
'speed' => $speed
));
So with two shortcodes on the page with timeout
and speed
set differently, I now get:
/* <![CDATA[ */
var avrgslds_vars = {"instance":"53442837d55c2","timeout":"10000","speed":"500"};
var avrgslds_vars = {"instance":"5344283814479","timeout":"5000","speed":"200"};
/* ]]> */
(I set a new variable for the instance: $instance = uniqid();
)
That seems like a significant improvement! So in my javascript initialization, I tried echoing a variable set in my shortcode, which would have all the shortcode “atts” (parameters):
$jQselectors = "";
$jQselectors .= " // Hoping this will keep the array keys from overwriting eachother.
$(slds_vars.instance).responsiveSlides({
pause: true,
nav: true,
pager: true,
timeout: $timeout,
speed: $speed
});
";
Of course, I realized after I saw this result…
<script>
jQuery(function($) {
$(document).ready(function() {
});
});
</script>
I can’t select the variable from outside my shortcode function like I was attempt to do:
function slds_init() { ?>
<script>
jQuery(function($) {
$(document).ready(function() {
<?php echo $jQselectors; ?>
});
});
</script>
<?php
}
add_action('wp_footer', 'slds_init'); }
I’m having trouble wrapping my head around how to do this. I may just have a misunderstanding on how arrays work. Any ideas? Any/all help is greatly appreciated.
Score! Figured it out. It’s mostly just a variable scope matter.
First though, I wound up not using
wp_localize_script()
at all as this requires more JavaScript know-how, where as I have more PHP know-how. Seems like a great solution for a more JavaScript savvy person though and thanks again to @birgire for the advise! I used theuniqid()
function he recommended though, to assign a unique class to each shortcode instance (within my shortcode function):So then I set a variable before my shortcode function starts (before, so it can be used within and after my shortcode function):
I pulled it into my shortcode function:
That way I could add a jQuery selector to it with all the relevant parameters from the shortcode instance being processed each time the shortcode function is run:
So in my init function (which runs after my shortcode function) I pulled that variable in again to write the middle section of my JavaScript initialization:
As far as I could tell from trial and error, this sequence is important. It basically goes:
Hope this helps someone. :j
You could try to include
wp_enqueue_script()
andwp_localise_script
directly into your shortcode callback.But if you got more than one shortcode call on your page, you might get into an overwriting problem from multiple
wp_localise_script
calls:where only the last one is picked up by the enqueued script.
Here’s similar problem described on WPSE
Fortunately, there are some workarounds available, like this one on WPSE, trying to seperate the instances with:
Instead of
[myshortcode instance="1"]
kind of workaround, you could try to automatically generate a unique ID for each shortcode call. There’s exists a handy PHP function for that:uniqid()
.ps: It’s not so good practice to use
extract
in your PHP code.Hope this helps.