Search code examples
phphtmlwordpressvariableswoocommerce

Error occurs when try to get woocommerce order details in a custom WP_Query


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>';

}

Solution

  • 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>