Creating Multiple wp_localize_script for Shortcode?

I have a shortcode that displays recent WooCommerce products in a carousel, however i would like the end user to be able to use the shortcode multiple times on the same page, currently when this happens the jQuery carousel has conflicts.

Here is the code i’m using for the shortcode,

Read More
function recent_products_slider_func($atts) {
global $woocommerce_loop;
static $count = 0;
if (empty($atts)) return;

extract(shortcode_atts(array(
    'title'            => 'Recent Products',
    'order'         => 'DESC',
    'orderby'         => 'date',
    'mousewheel'     => 'false',
    'autoscroll'     => '1',
    'swipe'         => 'false',
    'scroll'         => '1',
    'items'         => 6
), $atts));

$args = array(
    'post_type'    => 'product',
    'post_status' => 'publish',
    'posts_per_page' => $items,
    'ignore_sticky_posts'    => 1,
    'orderby' => $orderby,
    'order' => $order,
    'meta_query' => array(
        array(
            'key'         => '_visibility',
            'value'     => array('catalog', 'visible'),
            'compare'     => 'IN'
        )
    )
);
wp_enqueue_script('owlcarouselcustom', get_template_directory_uri() . '/includes/pixelstores/shortcodes/js/' . 'owlcarousel.js');
wp_localize_script('owlcarouselcustom', 'carouselvars', array(
  'autoscroll' => $autoscroll
  )
);

ob_start();

$products = new WP_Query( $args );

if ( $products->have_posts() ) : ?>

    <div class="row ps-carousel">
        <div class="col-xs-10">        
            <h3><?php echo $title; ?></h3>
        </div>
        <div class="col-xs-2">
            <div class="ps-carousel-btns">        
                <a class="btn prev"><i class="fa fa-angle-left" /></a>
                <a class="btn next"><i class="fa fa-angle-right" /></a>
            </div>    
        </div>    
    </div>

    <div class="row">
        <div id="owl-example" class="owl-carousel">
            <?php while ( $products->have_posts() ) : $products->the_post(); ?>
                <?php if ( class_exists('woocommerce') ) {  woocommerce_get_template_part( 'content', 'product' ); } ?>
            <?php endwhile; ?>
        </div>
    </div>

<?php endif; 

wp_reset_query();       
$count++;                  

return ob_get_clean();
}                  
add_shortcode('recent_products_slider', 'recent_products_slider_func'); 

For the jQuery i use the following,

jQuery(document).ready(function($) {
var settingObj = carouselvars;
var owlcontainer = $("#owl-example");

if(settingObj.autoscroll == 1) {settingObj.autoscroll = true;} else {settingObj.autoscroll = false;}

$(owlcontainer).owlCarousel({
    autoPlay: settingObj.autoscroll,

    });
});

I know why this isn’t working but not sure whats the best solution, the ‘carouselvars’ handle in the wp_localize_script is being called out without a unique name, so the variable is being called twice.

Any solutions much appreciated.

Kind Regards

Related posts

2 comments

  1. I am not a jQuery expert, but I ran into the same problem and I believe I have a workable solution. The problem is that each time you run wp_localize_script it creates a javascript variable using the $name setting. In your case that is ‘carouselvars’. As this is set before the jQuery in run, only the last values passed to the variable are ‘seen’ by jQuery, so again in your case, settingObj.autoscroll will always be whatever the value was set to in the last instance of the shortcode.

    My solution is to set a dynamic variable name for the wp_localize_script call, something like:

    wp_localize_script('owlcarouselcustom', 'carouselvars' . $instance, array(
      'autoscroll' => $autoscroll
      )
    );
    

    where $instance can be whatever the user wants to set it to. So the usage would be:

    [recent_products_slider instance=1 autoscroll=0]
    [recent_products_slider instance=2 autoscroll=1]
    

    and your code to extract the settings would need to be:

    extract(shortcode_atts(array(
        'title'            => 'Recent Products',
        'order'         => 'DESC',
        'orderby'         => 'date',
        'mousewheel'     => 'false',
        'autoscroll'     => '1',
        'swipe'         => 'false',
        'scroll'         => '1',
        'items'         => 6,
        'instance'      => 1
    ), $atts));
    

    I am sure there is a more clever way to do this, so no instance needs to be set, but, like I said, I’m not an expert in jQuery.

    Then the trick is to get the right data to pull into the right instance of the shortcode. I did it using html5 data-types. So in the php portion of your code I think it would be best to do this:

    <div id="owl-' . $instance . '" class="owl-carousel" data-instance="' . $instance . '">
    

    Then your jQuery would look like this:

    jQuery(document).ready(function($) {
        $('.owl-carousel').each(function( index ) {
            var instance = $( this ).data('instance');
            SetOwlCarousel(instance);
        });
    });
    
    function SetOwlCarousel(instance) {
        var settingObj = window["carouselvars"+instance];
        var owlcontainer = $("#owl-" + instance);
    
        if(settingObj.autoscroll == 1) {settingObj.autoscroll = true;} else {settingObj.autoscroll = false;}
    
        jQuery(owlcontainer).owlCarousel({
            autoPlay: settingObj.autoscroll,
    
            });
        });
    }
    

    So this jQuery script will loop over each instance of ‘.owl-carousel’ and run the SetOwlCarousel function on it. Calling the window object when you set settingObj allows you to evaluate “carouselvars”+instance to the variable you set using wp_localize_script, so in my example carouselvars1 and carouselvars2.

    If someone has a cleaner way to do this I would love to use it, but this should get you what you are looking for. I have not tested this code, but it is substantially the same as what I used myself which worked.

  2. Providing everything else is working – in order to use an ID to target the slider it must be unique. Therefore all the slider containers cannot have an ID of #owl-example – it needs to be #owl-example-1, #owl-example-2 etc.

    To avoid this completely you might want to try using the .owl-carousel class instead.

Comments are closed.