6

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,

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

4

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.

  • 1
    Nice idea. You could also try to automatically generate a unique ID for each instance, for example with uniqid(). – birgire Apr 5 '14 at 3:55
  • @birgire you mean in lieu of having the user assign an instance number in the shortcode. Very good idea thanks! – MatthewLee Apr 5 '14 at 7:56
  • Yes that's the idea. It might be manageable to keep track of different instance numbers in multiple shortcodes, in a single post. But it might get hairy on the frontpage and the archive pages. So we better try to find a way to do it automatically ;-) – birgire Apr 5 '14 at 8:16
  • Absolutely. Makes it a lot more scalable and easier on the end user. – MatthewLee Apr 5 '14 at 17:08
0

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.

  • Hi Steven, Yes, i have given my div id's each unique identities, problem is the handle in the wp_localize_script is being overwritten <pre>/* <![CDATA[ / var carouselvars = {"autoscroll":"0"}; var carouselvars1 = {"autoscroll":"1"}; / ]]> */</pre> How do i see the handle in the jQuery? – Shoebox Feb 26 '14 at 2:39
  • In the jQuery i set the "var settingObj = carouselvars;" How do i make this incremement to represent the correct handle? hope this makes sense. – Shoebox Feb 26 '14 at 2:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.