wpalchemy icon indicating copy to clipboard operation
wpalchemy copied to clipboard

Filtering a custom post type by 2 metabox fields (with 2 separate queries)

Open astewes opened this issue 8 years ago • 4 comments

I have a custom post type, "news", and am using two different metaboxes with it, defined in meta-setup-spec.php like this:

$news_mb = new WPAlchemy_MetaBox(array(
  'id' => 'news_meta',
  'title' => 'Item Details',
  'template' => get_stylesheet_directory() . '/metaboxes/news_meta.php',
  'types' => array('news'),
  'mode' => WPALCHEMY_MODE_EXTRACT
));

$date_meta = new WPAlchemy_MetaBox(array(
  'id' => 'date_meta',
  'title' => 'Date',
  'template' => get_stylesheet_directory() . '/metaboxes/date_meta.php',
  'priority' => 'high',
  'autosave' => TRUE,
  'mode' => WPALCHEMY_MODE_EXTRACT,
  'types' => array('news')
));

In news_meta.php, I've added an input group containing three radio inputs as follows:

<div class="input-group">
    <?php $mb->the_field('content_type'); ?>
    <input id="news_radio" type="radio" name="<?php $mb->the_name(); ?>" value="news"<?php $mb->the_radio_state('news')?' checked="checked"':''; ?>/><label>News</label>
    <input id="press_radio" type="radio" name="<?php $mb->the_name(); ?>" value="press"<?php $mb->the_radio_state('press')?' checked="checked"':''; ?>/><label>Press</label>
    <input id="event_radio" type="radio" name="<?php $mb->the_name(); ?>" value="event"<?php $mb->the_radio_state('event')?' checked="checked"':''; ?> /><label>Event</label>
</div>

$date_meta is using a field, sortdate, that saves dates as YYMMDD (ie, 20160518). In my page template, I have no trouble outputting posts with these args:

$args = array(
  'post_type' => 'news',
  'post_status' => 'publish',
  'meta_key' => 'sortdate',
  'orderby' => 'meta_value',
  'order' => 'DESC',
  'posts_per_page' => -1
);

I'm able to display when I'm filtering on the radio input value with no problems. For example:

<?php
  if($wp_query->have_posts()) :
  while ($wp_query->have_posts()) : $wp_query->the_post();
    global $news_mb;
    $news_mb-> the_meta();
    $description = $news_mb->get_the_value('description');
?>
  <?php if ( 'news' == $news_mb->get_the_value( 'content_type' ) ) : ?>
    <div class="flex-item item">
      <a target="_blank" href="<?php echo $news_mb->get_the_value('url'); ?>">
        <div class="image-container">
          <img class="news-logo img-responsive" src="<?php echo $news_mb->get_the_value('logo'); ?>" />
        </div>
        <h3><?php echo get_the_title(); ?></h3>
        <p><?php echo wp_trim_words( $description, $num_words = 30, $more = null ); ?></p>
      </a>
    </div>
  <?php endif; ?>
<?php
  endwhile;
  endif;
?>

But I'm running into trouble when I need to run two queries at different places in my template. This is the case for posts with the radio input value of "events" - I need to display the first 4 in one part of the template, and all the rest in another. I used the following for $args:

<?php
  global $news_mb, $date_meta;
  $news_mb->the_meta();
  $date_meta->the_meta();
  $args = array(
    'post_type' => 'news',
    'post_status' => 'publish',
    'orderby' => 'sortdate',
    'order' => 'DESC',
    'posts_per_page' => -1,
    'meta_query' => array(
      'relation' => 'AND',
      array(
        'key' => $date_meta->get_the_name('sortdate'),
        'value' => date("YYMMDD"),
        'type' => 'numeric',
        'compare' => '>='
      ),
      array(
        'key' => $news_mb->get_the_name('content_type'),
        'value' => 'event',
        'compare' => '='
      )
    )
  );
?>

It's also worth noting that I added another change above, which is to filter sortdate based on date values <= the current date.

For the two separate queries, I tried adding an increment, since this has worked for less complex scenarios in the past:

**QUERY 1:**
<?php
  $i = 0;
  if($wp_query->have_posts()) :
  while ($wp_query->have_posts()) :
    $wp_query->the_post();
    global $news_mb, $date_meta;
    $news_mb->the_meta();
    $date_meta->the_meta();
?>
<?php if($i < 4) : ?>

  .... the HTML markup/meta values to be used ...

<?php endif; ?>
<?php
  $i++;
  endwhile;
  endif;
?>

**QUERY 2:**
<?php
  $i = 0;
  if($wp_query->have_posts()) :
  while ($wp_query->have_posts()) :
    $wp_query->the_post();
    global $news_mb, $date_meta;
    $news_mb->the_meta();
    $date_meta->the_meta();
?>
<?php if($i >= 4) : ?>

  .... the HTML markup/meta values to be used ...

<?php endif; ?>
<?php
  $i++;
  endwhile;
  endif;
?>

But no luck. Perhaps I'm trying to change too much at once...but I know everything was working fine until I, a) added the meta_query array to my $args, b) attempted to beef up my sortdate filter by only displaying current/future events, c) adding the increment. Last thing I'll mention: I also tried using two different $args and $wp_query (ie, $args1 for $wp_query1, $args2 for $wp_query2), but to no avail.

What am I doing wrong?

astewes avatar May 18 '16 23:05 astewes

Definitely do incremental changes ...

Also check https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters

Your orderby should likely be 'orderby' => 'meta_value'

Are you getting output?

Promo: I assume you are adding press/news/event functionality .. I've written a plugin to do what you are likely attempting to do, and events can be added with minimal effort (in fact I have an extension in the works).

https://wordpress.org/plugins/nooz/

farinspace avatar May 19 '16 00:05 farinspace

I think I've narrowed down the issue, and it involves 'posts_per_page'.

  • When I set it to -1, I get output, although the increment i'm using in my loop doesn't work, and all of the posts appear
  • When I set it to 4 or remove 'posts_per_page' altogether from $args, I get no output
  • I also noticed that I only get output when I set 'order' to DESC. When I use ASC (which is what I need to use), I get no output

astewes avatar May 19 '16 20:05 astewes

Update: I'm getting the expected output, opting to use conditionals for the date and radio input values inside the loop rather than in $args. I still have one issue, though: this only appears to work when I set 'order' to DESC. Changing the value to ASC outputs nothing in my first loop (intended for posts 1-4), although the second loop (intended for posts 5 and greater) produces the expected output.

I'm now using the following:

<?php
  $date = date('Ymd');

  $args = array(
    'post_type' => 'news',
    'post_status' => 'publish',
    'meta_key' => 'sortdate',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'posts_per_page' => -1
  );

  global $wp_query;
  global $post;
  $wp_query= null;
  $wp_query = new WP_Query($args);
?>

First loop:

<?php
  if($wp_query->have_posts()) :
  while ($wp_query->have_posts()) : $wp_query->the_post();

    global $news_mb, $sortdate;
    global $sortdate;
    $news_mb->the_meta();
    $date_meta->the_meta();
    $description = $news_mb->get_the_value('description');
    $sortdate = $date_meta->get_the_value('sortdate');
    $index = $wp_query->current_post;
?>
  <?php if ( $news_mb->get_the_value('content_type') == 'event' && ($index < 4) && ($date <= $sortdate) ) : ?>
    <div class="inner-flex-item child-item">
      <a target="_blank" href="<?php echo $news_mb->get_the_value('url'); ?>">
        <div class="image-container text-center">
          <img class="center-block img-responsive" src="<?php echo $news_mb->get_the_value('logo'); ?>" />
        </div>
        <h3><?php echo get_the_title(); ?></h3>
        <p>
          <span>
            <?php if ($date_meta->get_the_value('date_range') != '') {
              echo $date_meta->get_the_value('date_range');
            } else {
              echo $date_meta->get_the_value('date');
              } ?>
          </span>
        </p>
      </a>
    </div>
  <?php endif; ?>
<?php
  endwhile;
  endif;
?>

Second loop:

<?php
  if($wp_query->have_posts()) :
  while ($wp_query->have_posts()) : $wp_query->the_post();

    global $news_mb, $date_meta, $sortdate;
    $news_mb->the_meta();
    $date_meta->the_meta();
    $sortdate = $date_meta->get_the_value('sortdate');
    $index = $wp_query->current_post;
?>
  <?php if ( $news_mb->get_the_value('content_type') == 'event' && ($index >= 4) && ($date <= $sortdate) ) : ?>
    <div class="flex-item item child-item">
      <a target="_blank" href="<?php echo $news_mb->get_the_value('url'); ?>">
        <div class="image-container text-center">
          <img class="center-block img-responsive" src="<?php echo $news_mb->get_the_value('logo'); ?>" />
        </div>
        <h3><?php echo get_the_title(); ?></h3>
        <p>
          <span>
            <?php if ($date_meta->get_the_value('date_range') != '') {
              echo $date_meta->get_the_value('date_range');
            } else {
              echo $date_meta->get_the_value('date');
              } ?>
          </span>
        </p>
      </a>
    </div>
  <?php endif; ?>
<?php
  endwhile;
  endif;
?>

Am I missing something as to why ASC order isn't working in the first loop? Is this a matter of needing to use wp_reset_postdata(), wp_reset_query(), or is it something else entirely?

astewes avatar May 20 '16 18:05 astewes

issue resolved, this can be marked as closed

astewes avatar May 21 '16 19:05 astewes