0

I'm trying to get order details with WP_Query, this must be work with an ajax call for pagination without page reload. The problem is that I get an error when I try to put some variables, such as: $order_id = $order->get_id(); or $items = $order->get_items();.

The error in google console: POST https://mywebsite.com/wp-admin/admin-ajax.php 500

As @Sadoo suggested, if I put $order_id = get_the_ID(); instead of $order_id = $loop->post->ID; the error in google console disappears.

At this point I should be able to see the details of the orders such as the ID for example, but I still don't get any results. I think the problem is the query because in with var_dump($loop); i get null. Why is this happening ?

functions.php

<?php

add_action( 'wp_ajax_demo_pagination_posts', 'demo_pagination_posts' );
add_action( 'wp_ajax_nopriv_demo_pagination_posts', 'demo_pagination_posts' ); 

function demo_pagination_posts() {
  global $wpdb, $wp_query;
  $msg = '';
  if(isset($_POST['page'])){
    // Sanitize the received page   
    $page = sanitize_text_field($_POST['page']);
    $cur_page = $page;
    $page -= 1;
    $per_page = 2; //set the per page limit
    $previous_btn = true;
    $next_btn = true;
    $first_btn = true;
    $last_btn = true;
    $start = $page * $per_page;
    
    // WP_Query Posts
    $args = array(
        'post_type'         => 'shop_order',
        'post_status '      => 'wc-completed',
        'posts_per_page'    => $per_page,
        'offset'            => $start
      );
    $loop = new WP_Query( $args );
    
    // At the same time, count the number of queried posts
    $count = new WP_Query(
      array(
        'post_type'         => 'post',
        'post_status '      => 'publish',
        'posts_per_page'    => -1
      )
    );

   $count = $count->post_count;
   
   // Loop through each order post object
   if ( $loop->have_posts() ) {
    while ( $loop->have_posts() ) {
      $loop->the_post(); 
         
      // The order ID
      $order_id = get_the_ID();

      // Get an instance of the WC_Order Object
      $order = wc_get_order($loop->post->ID);
   
      $orders_id = $order->get_id();
      echo '<span>#'. esc_attr($orders_id) .'</span>';
    }
  }
   
  // This is where the magic happens
    $no_of_paginations = ceil($count / $per_page);
    if ($cur_page >= 7) {
      $start_loop = $cur_page - 3;
      if ($no_of_paginations > $cur_page + 3)
        $end_loop = $cur_page + 3;
      else if ($cur_page <= $no_of_paginations && $cur_page > $no_of_paginations - 6) {
        $start_loop = $no_of_paginations - 6;
        $end_loop = $no_of_paginations;
      } else {
        $end_loop = $no_of_paginations;
      }
    } else {
      $start_loop = 1;
      if ($no_of_paginations > 7)
        $end_loop = 7;
      else
        $end_loop = $no_of_paginations;
    }
    // Pagination Buttons logic   
    $pag_container .= "
    <div class='pagination-link'>
      <ul>";
        if ($previous_btn && $cur_page > 1) {
          $pre = $cur_page - 1;
          $pag_container .= "<li p='$pre' class='active'>Previous</li>";
        } else if ($previous_btn) {
          $pag_container .= "<li class='inactive'>Previous</li>";
        }
        for ($i = $start_loop; $i <= $end_loop; $i++) {
          if ($cur_page == $i)
            $pag_container .= "<li p='$i' class = 'selected' >{$i}</li>";
          else
            $pag_container .= "<li p='$i' class='active'>{$i}</li>";
        }
        if ($next_btn && $cur_page < $no_of_paginations) {
          $nex = $cur_page + 1;
          $pag_container .= "<li p='$nex' class='active'>Next</li>";
        } else if ($next_btn) {
          $pag_container .= "<li class='inactive'>Next</li>";
        }
        $pag_container = $pag_container . "
      </ul>
    </div>";
    echo 
    '<div class = "pagination-content">' . $msg . '</div>' . 
    '<div class = "pagination-nav">' . $pag_container . '</div>';
  }
  die();
}

custom-template.php

<div class="wrap">
  <div id="primary" class="content-area">
    <div class="col-md-12 content">
      <div class = "inner-box content no-right-margin darkviolet">
        <script type="text/javascript">
          jQuery(document).ready(function($) {
            // This is required for AJAX to work on our page
            var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
            function load_all_posts(paged){
              var data = {
                page: paged,
                action: "demo_pagination_posts"
              };
              // Send the data
              $.post(ajaxurl, data, function(response) {
                $(".pagination_container").html(response);
              });
            }
            load_all_posts(1); // Load page 1 as the default
            $(document).on('click','.pagination-link ul li',function(){
              var paged = $(this).attr('p');
              load_all_posts(paged);
            });
          }); 
        </script>
        <div class = "pag_loading">
          <div class = "pagination_container">
            <div class="post-content"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

If instead of using a WP_Query I use a SQL Query everything works fine. However I am trying to use WP_Query as I am more familiar with it. Below is the working query that returns the results correctly.

//--SQL Query--//
// Set the table where we will be querying data
$table_name = $wpdb->prefix . "posts";
    
// Query the posts
$loop = $wpdb->get_results($wpdb->prepare("
  SELECT * FROM " . $table_name . " WHERE post_type = 'shop_order' AND post_status = 'wc-completed' ORDER BY post_date DESC LIMIT %d, %d", $start, $per_page ) );

// At the same time, count the number of queried posts
$count = $wpdb->get_var($wpdb->prepare("
  SELECT COUNT(ID) FROM " . $table_name . " WHERE post_type = 'post' AND post_status = 'publish'", array() ) );

// Loop through each order post object
foreach( $loop as $customer_order ){
 $order_id = $customer_order->ID; // The Order ID

 // Get an instance of the WC_Order Object
 $order = wc_get_order( $customer_order->ID );

 $orders_id = $order->get_id();

 echo '<span>#'. esc_attr($orders_id) .'</span>';

}
Snorlax
  • 183
  • 4
  • 27

2 Answers2

1

the_post() returns True when finished. as a result of calling setup_postdata(). go ahead and try $order_id = get_the_ID(); instead of $order_id = $loop->post->ID; and see if it works.

Update 1: I did some cleaning up on your code. hope this is more understandable:

add_action( 'wp_ajax_demo_pagination_posts', 'demo_pagination_posts' );
add_action( 'wp_ajax_nopriv_demo_pagination_posts', 'demo_pagination_posts' );
function demo_pagination_posts()
{
    global $wpdb;
    $msg = '';
    if ( isset( $_POST[ 'page' ] ) ) {

        # want this to be 1 or higher, so
        $page = max( intval( $_POST[ 'page' ] ), 1 );
        # how many orders in a page?
        $per_page = 4;

        // Okay, lets make a query including shop orders that are completed.
        $loop = new WP_Query( [
            'post_type'      => 'shop_order',
            'post_status'    => 'wc-completed',
            'orderby'        => 'post_date',
            'order'          => 'DESC',
            'posts_per_page' => $per_page,
            'paged'          => $page,
        ] );

        $count = $loop->found_posts;

        // Loop through each order post object
        if ( $loop->have_posts() ) {
            while ( $loop->have_posts() ) {
                $loop->the_post();

                // The order ID
                $order_id = $loop->post->ID;

                // Get an instance of the WC_Order Object
                $order = wc_get_order( $loop->post->ID );
                $items = $order->get_items();

                $orders_id      = $order->get_id();
                $status         = wc_get_order_status_name( $order->get_status() );
                $date_created   = $order->get_date_created()->date( 'd/m/Y' );
                $payment_method = $order->get_payment_method_title();
                $order_total    = $order->get_formatted_order_total();
                foreach ( $items as $item ) {
                    $product_name = $item->get_name();
                    $view_order   = $order->get_view_order_url();
                    $product      = $item->get_product();

                    if ( $product instanceof WC_Product ) {
                        $order_img       = $product->get_image();
                        $downloads       = $order->get_downloadable_items();
                        $download_button = '';

                        if ( is_array( $downloads ) ) {
                            foreach ( $downloads as $product ) {
                                $download_button = '<a href="' . $product[ 'download_url' ] . '" target="_blank">Download</a>';
                            }
                        }

                        $msg = '
                        <table class="table_orders" border="2">
                            <tr class="table_row_items">
                              <td class="product_number">
                               <span class="mobile title">Ordine</span>
                               <span>#' . esc_attr( $orders_id ) . '</span>
                              </td>
                
                              <td class="product_name">
                               <span class="mobile title">Prodotto</span>
                               <a href="' . wp_kses_post( $view_order ) . '">' . wp_kses_post( $product_name ) . '</a>
                              </td>
                
                              <td class="product_data">
                               <span class="mobile title">Data</span>
                               <span>' . wp_kses_post( $date_created ) . '</span>
                              </td>
                
                              <td class="product_price">
                               <span class="mobile title">Prezzo</span>
                               <span>' . wp_kses_post( $order_total ) . '</span>
                              </td>
                
                              <td class="product_status">
                               <span class="mobile title">Stato</span>
                               <span class="label ' . $order->get_status() . '">' . wp_kses_post( $status ) . '</span>
                              </td>
                
                              <td class="product_action">
                               <span class="mobile title">File</span>
                               <a target=”_blank” href="' . esc_url( $view_order ) . '">Visualizza<i class="fa-duotone fa-eye"></i></a>
                              </td>
                            </tr>    
                        </table> 
                    ';
                    }
                }

            }
        }

        // This is where the magic happens
        $pages_num     = intval( ceil( $count / $per_page ) );
        $is_last_page  = $pages_num == $page;
        $is_first_page = $pages_num === 1;

        if ( $page >= 7 ) {
            $start_loop = $page - 3;
            if ( $pages_num > $page + 3 )
                $end_loop = $page + 3;
            else if ( $page <= $pages_num && $page > $pages_num - 6 ) {
                $start_loop = $pages_num - 6;
                $end_loop   = $pages_num;
            } else {
                $end_loop = $pages_num;
            }
        } else {
            $start_loop = 1;
            if ( $pages_num > 7 )
                $end_loop = 7;
            else
                $end_loop = $pages_num;
        }

        $pagination_html = "<div class='pagination-link'>";
        $pagination_html .= "
          <ul>";
            if ( !$is_first_page ) {
                $pagination_html .= "<li data-pagenum='" . ( $page - 1 ) . "' class='active'>Previous</li>";
            } else {
                $pagination_html .= "<li class='inactive'>Previous</li>";
            }
            for ( $i = $start_loop; $i <= $end_loop; $i++ ) {
                if ( $page == $i )
                    $pagination_html .= "<li data-pagenum='$i' class = 'selected' >{$i}</li>";
                else
                    $pagination_html .= "<li data-pagenum='$i' class='active'>{$i}</li>";
            }
            if ( !$is_last_page ) {
                $pagination_html .= "<li data-pagenum='" . ( $page + 1 ) . "' class='active'>Next</li>";
            } else {
                $pagination_html .= "<li class='inactive'>Next</li>";
            }
            $pagination_html .= "
          </ul>";
        $pagination_html .= "</div>";
        echo
            '<div class = "pagination-content">' . $msg . '</div>' .
            '<div class = "pagination-nav">' . $pagination_html . '</div>';
    }
    die();
}

and the html:

    <div class="wrap">
        <div id="primary" class="content-area">
            <div class="col-md-12 content">
                <div class="inner-box content no-right-margin darkviolet">
                    <script type="text/javascript">
                        jQuery(document).ready(function ($) {
                            // This is required for AJAX to work on our page
                            var ajaxurl = '<?php echo admin_url( 'admin-ajax.php' ); ?>';

                            function load_all_posts(page) {
                                var data = {
                                    page: page,
                                    action: "demo_pagination_posts"
                                };
                                // Send the data
                                $.post(ajaxurl, data, function (response) {
                                    $(".pagination_container").html(response);
                                });
                            }

                            load_all_posts(1); // Load page 1 as the default
                            $(document).on('click', '.pagination-link ul li', function () {
                                var page = $(this).attr('data-pagenum');
                                load_all_posts(page);
                            });
                        });
                    </script>
                    <div class="pag_loading">
                        <div class="pagination_container">
                            <div class="post-content"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
Sadoo
  • 396
  • 3
  • 10
  • Thank you for the answer, the error seems to no longer exist but I will do other tests. However, I still can't see any posts. – Snorlax Jul 16 '22 at 17:44
  • 1
    To be honest, I still don't quite understand what you're trying to accomplish with this code and why you have the two WP_Query and what you're counting by getting the posts. can you elaborate a bit? – Sadoo Jul 17 '22 at 00:12
  • I updated the question by specifying the problem better, I hope this helps to understand better. – Snorlax Jul 17 '22 at 01:05
  • WP_Query shouldn't return null. there is something else going on. For example `$order = wc_get_order($loop->post->ID);` should be replaced by `$order = wc_get_order(get_the_ID());` and also to count all the posts matching the criteria you don't need to have another query. You could just use `$loop->found_posts`. Anyways, is this code available online somewhere so I can check it? – Sadoo Jul 17 '22 at 01:21
  • Thanks again for your time. I tried replacing with get_the_ID but I don't get any details. However there are several versions of the code on the internet, I am using this: https://tutsocean.com/wordpress/wordpress-ajax-numbered-pagination-5-minutes/ then I'm customizing the loop following this question https://stackoverflow.com/questions/51947198/how-to-query-woocommerce-orders-on-a-page From this question I am trying to take Wordpress WP_Query. – Snorlax Jul 17 '22 at 11:28
  • Here is another version of the code where wp_query is also included https://carlofontanos.com/wordpress-frontend-ajax-pagination/ – Snorlax Jul 17 '22 at 11:32
  • I am trying it but get an error. I copied and pasted the code. Parse error: syntax error, unexpected 'pagination' (T_STRING) on line 124. is This on line 124 `$pagination_html = ' – Snorlax Jul 18 '22 at 12:05
  • I only realized now that only 1 post per page is always displayed, even if 4 is set as a number in `$per_page` – Snorlax Jul 18 '22 at 12:18
  • @Snorlax My bad, taken care of. – Sadoo Jul 19 '22 at 00:43
0

After some testing I was able to find a solution. I haven't made many changes, added a few foreaches and was able to access order details without receiving errors. Below I leave the working code. It can come in handy to anyone who finds the same problem.

functions.php

<?php

add_action( 'wp_ajax_demo_pagination_posts', 'demo_pagination_posts' );
add_action( 'wp_ajax_nopriv_demo_pagination_posts', 'demo_pagination_posts' ); 
function demo_pagination_posts() {
  global $wpdb;
  $msg = '';
  if(isset($_POST['page'])) {
    $page = sanitize_text_field($_POST['page']);
    $cur_page = $page;
    $page -= 1;
    $per_page = 4;
    $previous_btn = true;
    $next_btn = true;
    $start = $page * $per_page;
    
    // Query Wordpress the posts
    $loop = new WP_Query( array(
      'post_type'         => 'shop_order',
      'post_status'       => 'wc-completed',
      'orderby'           => 'post_date',
      'order'             => 'DESC',
      'posts_per_page'    => $per_page,
      'offset'            => $start,
    ));
    
    // At the same time, count the number of queried posts
    $count = new WP_Query( array(
      'post_type'         => 'post',
      'post_status '      => 'publish',
      'posts_per_page'    => -1
    ));

    $count = $count->post_count;

    // Loop through each order post object
    if ( $loop->have_posts() ) {
      while ( $loop->have_posts() ) { 
       $loop->the_post();
  
       // The order ID
       $order_id = $loop->post->ID;
       
       // Get an instance of the WC_Order Object
       $order = wc_get_order($loop->post->ID);
       $items = $order->get_items();
    
       $orders_id = $order->get_id();
       $status =  wc_get_order_status_name( $order->get_status() );
       $date_created = $order->get_date_created()->date('d/m/Y');
       $payment_method = $order->get_payment_method_title();
       $order_total = $order->get_formatted_order_total();
       
        foreach ( $items as $item ) {
          $product_name = $item->get_name();
          $view_order = $order->get_view_order_url();

          // Get product image - https://www.businessbloomer.com/woocommerce-easily-get-product-info-title-sku-desc-product-object/
          $product = $item->get_product();
          if( $product instanceof WC_Product ){
            $order_img = $product->get_image();
          }
          //Get product download button 
          $downloads = $order->get_downloadable_items();
          if(is_array($downloads)) {
            foreach($downloads as $product){
             $download_button = '<a href="'. $product['download_url'] .'" target="_blank">Download</a>';
            } 
          }

          echo '
            <table class="table_orders">
            <tr class="table_row_items">
              <td class="product_number">
               <span class="mobile title">Ordine</span>
               <span>#'. esc_attr($orders_id) .'</span>
              </td>

              <td class="product_name">
               <span class="mobile title">Prodotto</span>
               <a href="'. wp_kses_post($view_order) .'">'. wp_kses_post($product_name) .'</a>
              </td>

              <td class="product_data">
               <span class="mobile title">Data</span>
               <span>'. wp_kses_post($date_created) .'</span>
              </td>

              <td class="product_price">
               <span class="mobile title">Prezzo</span>
               <span>'. wp_kses_post($order_total) .'</span>
              </td>

              <td class="product_status">
               <span class="mobile title">Stato</span>
               <span class="label ' . $order->get_status() . '">'. wp_kses_post($status) .'</span>
              </td>

              <td class="product_action">
               <span class="mobile title">File</span>
               <a target=”_blank” href="'. esc_url($view_order) .'">Visualizza<i class="fa-duotone fa-eye"></i></a>
              </td>
            </tr>    
            </table> 
          ';
        }  
      }
      wp_reset_postdata();
    }
        
    // This is where the magic happens
    $no_of_paginations = ceil($count / $per_page);
    if ($cur_page >= 7) {
      $start_loop = $cur_page - 3;
      if ($no_of_paginations > $cur_page + 3)
        $end_loop = $cur_page + 3;
      else if ($cur_page <= $no_of_paginations && $cur_page > $no_of_paginations - 6) {
        $start_loop = $no_of_paginations - 6;
        $end_loop = $no_of_paginations;
      } else {
        $end_loop = $no_of_paginations;
      }
    } else {
      $start_loop = 1;
      if ($no_of_paginations > 7)
        $end_loop = 7;
      else
        $end_loop = $no_of_paginations;
    }
    // Pagination Buttons     
    $pag_container .= "
    <div class='pagination-link'>
      <ul>";
        if ($previous_btn && $cur_page > 1) {
          $pre = $cur_page - 1;
          $pag_container .= "<li p='$pre' class='active'>Previous</li>";
        } else if ($previous_btn) {
          $pag_container .= "<li class='inactive'>Previous</li>";
        }
        for ($i = $start_loop; $i <= $end_loop; $i++) {
          if ($cur_page == $i)
            $pag_container .= "<li p='$i' class = 'selected' >{$i}</li>";
          else
            $pag_container .= "<li p='$i' class='active'>{$i}</li>";
        }
        if ($next_btn && $cur_page < $no_of_paginations) {
          $nex = $cur_page + 1;
          $pag_container .= "<li p='$nex' class='active'>Next</li>";
        } else if ($next_btn) {
          $pag_container .= "<li class='inactive'>Next</li>";
        }
        $pag_container = $pag_container . "
      </ul>
    </div>";
    echo 
    '<div class = "pagination-content">' . $msg . '</div>' . 
    '<div class = "pagination-nav">' . $pag_container . '</div>';
  }
  die();
}

custom-template.php

<div class="wrap">
  <div id="primary" class="content-area">
    <div class="col-md-12 content">
      <div class = "inner-box content no-right-margin darkviolet">
        <script type="text/javascript">
          jQuery(document).ready(function($) {
            // This is required for AJAX to work on our page
            var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
            function load_all_posts(page){
              var data = {
                page: page,
                action: "demo_pagination_posts"
              };
              // Send the data
              $.post(ajaxurl, data, function(response) {
                $(".pagination_container").html(response);
              });
            }
            load_all_posts(1); // Load page 1 as the default
            $(document).on('click','.pagination-link ul li',function(){
              var page = $(this).attr('p');
              load_all_posts(page);
            });
          }); 
        </script>
        <div class = "pag_loading">
          <div class = "pagination_container">
            <div class="post-content"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Snorlax
  • 183
  • 4
  • 27
  • @Sadoo Despite the solution I am wondering if there is a way to shorten this in any way. Can be made ? – Snorlax Jul 17 '22 at 15:45
  • Let me set up a new wordpress and try this. – Sadoo Jul 18 '22 at 00:43
  • 1
    added the clean code. Let me know how it goes. – Sadoo Jul 18 '22 at 02:00
  • Thank you so much for your time, I appreciate it. It works fine, I just had to do a very small correction, find the comment under your answer. A little doubt remains: do you think it is possible to move the js code into a js file (example custom.js)? So I leave the custom.php file free to build the template instead of doing it in functions.php. So in functions.php I would just leave what is needed to make everything work. – Snorlax Jul 18 '22 at 12:14
  • 1
    it is indeed possible. and you can even take your functions.php part and put it in its own file. however, i suggest you do it yourself and struggle with it a bit to get a better idea of how it works and ask me any questions you face while doing so. – Sadoo Jul 18 '22 at 18:28
  • Yes, thank you, that's what I'll do. Meanwhile, you could fix your answer which has some errors, as only 1 data is displayed. I will update the post as I do. – Snorlax Jul 18 '22 at 20:23