John Doe
John Doe

Reputation: 601

Woocommerce ajax call on single product page

I get all my products from an API and those who are variations to each other all share a custom meta key called "api_product_family". The products with the same api_product_family are variants to each other, so on the single page I have a hook where I display the other variants with image and anchor to it's variants.

My code:

function mv_variations() {
  global $post;
  global $wpdb;

  $product_id = $post->ID;

  $product_family = get_post_meta( $post->ID, 'api_product_family', true );

  if(!empty($product_family)) {
    $query = "
      SELECT post_id
      FROM " . $wpdb->prefix . "postmeta
      WHERE meta_value = '" . $product_family . "'
    ";

    $products = $wpdb->get_col($query);

    if(count($products) > 0) {
      for($i=0; $i<count($products); $i++) {
        if($products[$i] == $product_id) {
          unset($products[$i]);
        }
     }

      if(count($products) > 0) {
        print '<h3>Choose other variants: </h3>';
        foreach($products as $product) {
          $image = wp_get_attachment_image_src(get_post_thumbnail_id($product));
          print '<a href="' . get_permalink($product) . '"><img src="' . $image[0] . '" alt="img"/> </a>';
        }
      }
    }
  }
}

add_action( 'woocommerce_single_product_summary', 'mv_variations' );

The problem: I have a LOT of posts, and a lot of post_meta's, so it's taking an eternity to load so I was thinking to move this whole function inside and AJAX call so it's doesn't slow down the initial load. The problem is that I have no idea how to do that with wordpress

Upvotes: 2

Views: 2246

Answers (2)

Stefan S
Stefan S

Reputation: 311

Are you simply looking to run a WP function via AJAX?

1) Add ajax actions

This needs to run inside the main plugin file. If you run this only on the public code, it will not work. WP is a little weird and all ajax uses admin-ajax.php

if ( wp_doing_ajax() ){
    add_action( 'wp_ajax_yourcustomfunction', array($this, 'yourcustomfunction') );
    add_action( 'wp_ajax_nopriv_yourcustomfunction', array($this, 'yourcustomfunction') );
}

function yourcustomfunction(){


    echo 'success';
    exit();

}

2) In JavaScript in the backend, you have the global: ajaxurl for the ajax url BUT in the front end you need to pass this as a variable via wp_localize_script

$datatoBePassed = array(
    'ajaxurl' => admin_url( 'admin-ajax.php' ),
);

wp_localize_script( 'your_javascript_script', 'plugin_display_settings', $datatoBePassed );

In JS:

var datavar = {
     action: 'yourcustomfunction',
};

$.post(plugin_display_settings.ajaxurl, datavar, function(response){
 //response received here. It will be 'success' which is echoed in PHP
});

3) If you also want to run a security nonce check (to check the request truly originates from the WP website, prevents some attacks), it gets a little more complicated:

$datatoBePassed should also include 'security' => wp_create_nonce( 'yourplugin_security_nonce' ), datavar in JS includes security: plugin_display_settings.security,

Finally, your PHP custom function begins with:

// Check security nonce. 
    if ( ! check_ajax_referer( 'yourplugin_security_nonce', 'security' ) ) {
        wp_send_json_error( 'Invalid security token sent.' );
        wp_die();
    }
// If security check passed, run further 

Upvotes: 1

mikerojas
mikerojas

Reputation: 2338

So I think you might get better performance using WP_Query. Below I converted what you have into a custom WP_Query. May need some slight adjustment but should be the right direction.

function mv_variations() {
  global $post_id;

  // get current post "product family"
  $product_family = get_post_meta( $post_id, 'api_product_family', true );

  // build related "product family" products query
  $products_query_args = array(
    'post_type' => 'product', // may need to update this for your case
    'posts_per_page' => -1, // return all found
    'post__not_in' => array($post_id), // exclude current post
    'post_status' => 'publish',

    // use a meta query to pull only posts with same "product family" as current post
    'meta_query' => array(
      array(
        'key' => 'api_product_family',
        'value' => $product_family,
        'compare' => '='
      )
    )
  );

  $products_query = new WP_Query($products_query);

  // use "the loop" to display your products
  if ( $products_query->have_posts() ) :
    print '<h3>Choose other variants: </h3>';
    while ( $products_query->have_posts() ) : $products_query->the_post();
      print '<a href="' . get_permalink() . '">'. wp_get_attachment_image() .'</a>';
    endwhile;
    // restore global post
    wp_reset_postdata();
  endif;
}
add_action( 'woocommerce_single_product_summary', 'mv_variations' );

Upvotes: 0

Related Questions