1

I am trying to build a timetable to display classes by time. I have a taxonomy of Day, which I am looping over to create a column for each day of the week. In side the column is a WP_Query which filters using the day taxonomy and meta_key classes_entry_start_time to orderby meta_value_num. The timetable is then filtered using ajax.

$calendarDays = get_terms([
  'taxonomy' => 'calendar-day',
  'hide_empty' => false,
]);

$calendarDays_count = count( $calendarDays );

if ( $calendarDays_count > 0 && is_array( $calendarDays ) ) {

echo '<div class="classes-calendar">';

  // Display filter
  $classesFilter = array_map(function($class) { 
    return [
      'value' => $class->term_id, 
      'title' => $class->name
    ];
  }, get_terms('calendar-class-type'));

  get_part('classes-filter', [
    'id' => 'classes-filter',
    'title' => 'All',
    'items' => array_merge( $classesFilter )
  ]);

  // Loop over day taxonomy 
  echo '<div id="response" class="container classes-wrap">';
  foreach ( $calendarDays as $day ) {

    echo '<div class="classes-col">';
      echo '<strong>' . $day->name . '</strong>';

      $args = array(
        'post_type' => 'calendar',
        'meta_key' => 'classes_entry_start_time',
        'orderby' => 'meta_value_num',
        'order' => 'ASC',
        'posts_per_page' => '-1',
        'tax_query' => array(
          array(
            'taxonomy' => 'calendar-day',
            'field' => 'id',
            'terms' =>  $day->term_id,
          )
        ),
      );

      // echo '<div id="response" class="container">';
        echo '<ul id="" class="response">';

          $query = new WP_Query( $args );

          if( $query->have_posts() ):

            while( $query->have_posts() ):
            $query->the_post();

            get_part('classes-item', ['classesEntry' => get_field('classes_entry')]);

            endwhile;

          else:
            echo 'No data to show';
          endif;

          wp_reset_query();

        echo '</ul>';
      // echo '</div>'; // END response

    echo '</div>'; // END classes-col

  } // END foreach
  echo '</div>'; // END response


  echo '<div class="section container center">';
  echo '<a href="#" class="btn">Book class</a>';
  echo '</div>';

echo '</div>'; // END classes-calendar

} // END if 

The main query works as expected and the ajax request works as expected to return the correct values, but only when I am not using a foreach loop in the ajax handler.

Below is the ajax handler function which is getting the correct posts based on the chosen filter, but it displays the same result for all options.

The foreach loop is based on a taxonomy which displays columns representing each day of the week: Monday – Sunday.

For example, it's returning:

Monday: Post one Tuesday: Post one Wednesday: Post one ...

But really it should be returning:

Monday: Post one, Post two Tuesday: Post three Wednesday: Post four ...

Whats the best way to filter WP_Query based on the two taxonomies and also display the query inside foreach loops so that the filter only shows posts assigned to the filter types and displays them in the correct day column, without it updating all columns of the foreach loop?

Is using a foreach loop wrong for what I am trying to achieve?

Filtering query where the issue are

add_action('wp_ajax_classfilter', 'load_posts_by_ajax_callback');
add_action('wp_ajax_nopriv_classfilter', 'load_posts_by_ajax_callback');

function load_posts_by_ajax_callback() {

  check_ajax_referer('load_more_posts', 'security');

  $calendarDays = get_terms([
    'taxonomy' => 'calendar-day',
    'hide_empty' => false,
  ]);

  foreach($calendarDays as $day) {

$args = array(
  'post_type' => 'calendar',
  'post_status' => 'publish',
  'meta_key' => 'classes_entry_start_time',
  'orderby' => 'meta_value_num',
  'order' => 'ASC',
  'tax_query' => array(
    array(
      'taxonomy' => 'calendar-day',
      'field' => 'id',
      'terms' => $day->term_id
    )
  )
);

if( isset( $_POST['theClass'] ) )
$args['tax_query'] = array(
  array(
    'taxonomy' => 'calendar-class-type',
    'field' => 'id',
    'terms' => $_POST['theClass']
  )
);

$loop = new WP_Query($args);

if($loop->have_posts()) {
  echo '<div class="classes-col">';
  echo '<strong>' . $day->name . '</strong>';
  echo '<ul>';
  while($loop->have_posts()) : $loop->the_post();
    get_part('classes-item', ['classesEntry' => get_field('classes_entry')]);
  endwhile;
  wp_reset_postdata();
  echo '</ul>';
  echo '</div>';
} 
else {
  echo '<div class="classes-col">';
  echo '<strong>' . $day->name . '</strong>';
  echo '</div>';
}

  }

wp_die();
}

If anyone can point me in the right direction that would be great. I've spent days trying different options with no luck! The only way I can get it to work as it should is by removing the foreach loop completely which I can't do as I need the columns of the week.

For reference, here is the ajax request

import axios from 'axios';

const classesFilter = () => {

  const el = document.querySelector('#classes-filter');

  if (el) {

    el.addEventListener('change', e => {
      e.preventDefault();

      const formData = new FormData(el); 

      formData.append('action', 'classfilter');
      formData.append('security', WP.security);

      // Axios POST request
      axios({
        method: 'POST',
        url: WP.ajax,
        data: formData,
      })
        // handle success
        .then(function (response) {
          console.log(response.data);
          console.log(response.status);

          document.getElementById("response").innerHTML = response.data;
          // document.getElementsByClassName("response").innerHTML = response.data;
        },
          (error) => {
            console.log(error);
          });

    });

  }

};

export default classesFilter;```


1 Answer 1

0

If anyone is interested in how to achieve the result for the question I posted, I managed to work it out!

As the correct results we're being displayed, but for each iteration of the foreach loop rather than the specific day, I managed to get the results to display/hide by using if (is_object_in_term($class->ID, 'calendar-day', 'monday') && $day->term_id == 6) . is_object_in_term checks if the $taxonomy are checked against the object’s terms’ term_ids, names and slugs and $day->term_id for each of the days. If it doesn't then nothing is displayed.

I've had to hardcode each day of the week and the code to generate the result. I know this isn't the best D.R.Y approach, but at the moment i'm happy with the current win!

add_action('wp_ajax_classfilter', 'load_posts_by_ajax_callback');
add_action('wp_ajax_nopriv_classfilter', 'load_posts_by_ajax_callback');

function load_posts_by_ajax_callback() {

  check_ajax_referer('load_more_posts', 'security');

  $days = get_terms([
    'taxonomy' => 'calendar-day'
  ]);

  // Loop over days of the week
  foreach ($days as $day ) {

    $classesTable .= '<div class="response classes-col">';

    $classesTable .= '<strong>' . $day->name . '</strong>'; // Day name

    // Query arguments based on day of the week
    $args = array(
      'post_type' => 'calendar',
      'meta_key' => 'classes_entry_start_time',
      'orderby' => 'meta_value_num',
      'order' => 'ASC',
      'numberposts' => '-1',
      'tax_query' => array(
        array(
          'taxonomy' => 'calendar-day',
          'field' => 'id',
          'terms' =>  $day->term_id
          // 'terms' => array('6', '7', '8', '9', '10', '11', '12')
        )
      ),
    );

    if(isset( $_POST['theClass'])) {
      $args['tax_query'] = array(
        array(
          'taxonomy' => 'calendar-class-type',
          'field' => 'id',
          'terms' => $_POST['theClass']
        )
      );
    }

    $query_classes = get_posts( $args );
    $classesArray = array();

    // Loop over query classes posts
    foreach ($query_classes as $key => $class ) {

      // Check if object has term: Monday
      if (is_object_in_term($class->ID, 'calendar-day', 'monday') && $day->term_id == 6):
        // $classesArray[] .= 'YES';
        $start_time = get_field('classes_entry_start_time', $class);
        $end_time = get_field('classes_entry_end_time', $class);
        $classesEntry = get_field('classes_entry', $class);
        // Create class item
        $classesArray[] .= '<li>';
        $classesArray[] .= '<a href="' . $classesEntry['booking_app_link'] . '" target="_blank" class="classes-item">';
        $classesArray[] .= '<span>' . $classesEntry['start_time'] . '</span>';
        $classesArray[] .= '<span>' . $class->post_title . '</span>';
        $classesArray[] .= '<span>' . $classesEntry['duration'] . '</span>';
        $terms = get_the_terms( $class->ID , 'calendar-class-type' );
        if ($terms): foreach ( $terms as $term ):
        $classesArray[] .= '<span>' . $term->name . '</span>';
        endforeach; endif; 
        $classesArray[] .= '</a>';
        $classesArray[] .= '</li>';
      else: 
        // Show nothing
        // $classesArray[] .= 'NO';
      endif;

      // Check if object has term: Tuesday
      if (is_object_in_term($class->ID, 'calendar-day', 'tuesday') && $day->term_id == 7):
        // $classesArray[] .= 'YES';
        $start_time = get_field('classes_entry_start_time', $class);
        $end_time = get_field('classes_entry_end_time', $class);
        $classesEntry = get_field('classes_entry', $class);
        // Create class item
        $classesArray[] .= '<li>';
        $classesArray[] .= '<a href="' . $classesEntry['booking_app_link'] . '" target="_blank" class="classes-item">';
        $classesArray[] .= '<span>' . $classesEntry['start_time'] . '</span>';
        $classesArray[] .= '<span>' . $class->post_title . '</span>';
        $classesArray[] .= '<span>' . $classesEntry['duration'] . '</span>';
        $terms = get_the_terms( $class->ID , 'calendar-class-type' );
        if ($terms): foreach ( $terms as $term ):
        $classesArray[] .= '<span>' . $term->name . '</span>';
        endforeach; endif; 
        $classesArray[] .= '</a>';
        $classesArray[] .= '</li>';
      else :
        // Show nothing
        // $classesArray[] .= 'NO';
      endif;

      // Check if object has term: Wednesday
      if (is_object_in_term($class->ID, 'calendar-day', 'wednesday') && $day->term_id == 8):
        // $classesArray[] .= 'YES';
        $start_time = get_field('classes_entry_start_time', $class);
        $end_time = get_field('classes_entry_end_time', $class);
        $classesEntry = get_field('classes_entry', $class);
        // Create class item
        $classesArray[] .= '<li>';
        $classesArray[] .= '<a href="' . $classesEntry['booking_app_link'] . '" target="_blank" class="classes-item">';
        $classesArray[] .= '<span>' . $classesEntry['start_time'] . '</span>';
        $classesArray[] .= '<span>' . $class->post_title . '</span>';
        $classesArray[] .= '<span>' . $classesEntry['duration'] . '</span>';
        $terms = get_the_terms( $class->ID , 'calendar-class-type' );
        if ($terms): foreach ( $terms as $term ):
        $classesArray[] .= '<span>' . $term->name . '</span>';
        endforeach; endif; 
        $classesArray[] .= '</a>';
        $classesArray[] .= '</li>';
      else :
        // Show nothing
        // $classesArray[] .= 'NO';
      endif;

      // Check if object has term: Thursday
      if (is_object_in_term($class->ID, 'calendar-day', 'thursday') && $day->term_id == 9):
        // $classesArray[] .= 'YES';
        $start_time = get_field('classes_entry_start_time', $class);
        $end_time = get_field('classes_entry_end_time', $class);
        $classesEntry = get_field('classes_entry', $class);
        // Create class item
        $classesArray[] .= '<li>';
        $classesArray[] .= '<a href="' . $classesEntry['booking_app_link'] . '" target="_blank" class="classes-item">';
        $classesArray[] .= '<span>' . $classesEntry['start_time'] . '</span>';
        $classesArray[] .= '<span>' . $class->post_title . '</span>';
        $classesArray[] .= '<span>' . $classesEntry['duration'] . '</span>';
        $terms = get_the_terms( $class->ID , 'calendar-class-type' );
        if ($terms): foreach ( $terms as $term ):
        $classesArray[] .= '<span>' . $term->name . '</span>';
        endforeach; endif; 
        $classesArray[] .= '</a>';
        $classesArray[] .= '</li>';
      else :
        // Show nothing
        // $classesArray[] .= 'NO';
      endif;

      // Check if object has term: Friday
      if (is_object_in_term($class->ID, 'calendar-day', 'friday') && $day->term_id == 10):
        // $classesArray[] .= 'YES';
        $start_time = get_field('classes_entry_start_time', $class);
        $end_time = get_field('classes_entry_end_time', $class);
        $classesEntry = get_field('classes_entry', $class);
        // Create class item
        $classesArray[] .= '<li>';
        $classesArray[] .= '<a href="' . $classesEntry['booking_app_link'] . '" target="_blank" class="classes-item">';
        $classesArray[] .= '<span>' . $classesEntry['start_time'] . '</span>';
        $classesArray[] .= '<span>' . $class->post_title . '</span>';
        $classesArray[] .= '<span>' . $classesEntry['duration'] . '</span>';
        $terms = get_the_terms( $class->ID , 'calendar-class-type' );
        if ($terms): foreach ( $terms as $term ):
        $classesArray[] .= '<span>' . $term->name . '</span>';
        endforeach; endif; 
        $classesArray[] .= '</a>';
        $classesArray[] .= '</li>';
      else :
        // Show nothing
        // $classesArray[] .= 'NO';
      endif;

      // Check if object has term: Saturday
      if (is_object_in_term($class->ID, 'calendar-day', 'saturday') && $day->term_id == 11):
        // $classesArray[] .= 'YES';
        $start_time = get_field('classes_entry_start_time', $class);
        $end_time = get_field('classes_entry_end_time', $class);
        $classesEntry = get_field('classes_entry', $class);
        // Create class item
        $classesArray[] .= '<li>';
        $classesArray[] .= '<a href="' . $classesEntry['booking_app_link'] . '" target="_blank" class="classes-item">';
        $classesArray[] .= '<span>' . $classesEntry['start_time'] . '</span>';
        $classesArray[] .= '<span>' . $class->post_title . '</span>';
        $classesArray[] .= '<span>' . $classesEntry['duration'] . '</span>';
        $terms = get_the_terms( $class->ID , 'calendar-class-type' );
        if ($terms): foreach ( $terms as $term ):
        $classesArray[] .= '<span>' . $term->name . '</span>';
        endforeach; endif; 
        $classesArray[] .= '</a>';
        $classesArray[] .= '</li>';
      else :
        // Show nothing
        // $classesArray[] .= 'NO';
      endif;

      // Check if object has term: Sunday
      if (is_object_in_term($class->ID, 'calendar-day', 'sunday') && $day->term_id == 12):
        // $classesArray[] .= 'YES';
        $start_time = get_field('classes_entry_start_time', $class);
        $end_time = get_field('classes_entry_end_time', $class);
        $classesEntry = get_field('classes_entry', $class);
        // Create class item
        $classesArray[] .= '<li>';
        $classesArray[] .= '<a href="' . $classesEntry['booking_app_link'] . '" target="_blank" class="classes-item">';
        $classesArray[] .= '<span>' . $classesEntry['start_time'] . '</span>';
        $classesArray[] .= '<span>' . $class->post_title . '</span>';
        $classesArray[] .= '<span>' . $classesEntry['duration'] . '</span>';
        $terms = get_the_terms( $class->ID , 'calendar-class-type' );
        if ($terms): foreach ( $terms as $term ):
        $classesArray[] .= '<span>' . $term->name . '</span>';
        endforeach; endif; 
        $classesArray[] .= '</a>';
        $classesArray[] .= '</li>';
      else :
        // Show nothing
        // $classesArray[] .= 'NO';
      endif;


    }

    // Display all queried class results
    $classesTable .= '<ul>' . implode(' ', $classesArray) . '</ul>';

    $classesTable .= '</div>'; // END classes-col
  }

  echo $classesTable;

    wp_die();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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