• Resolved Johan F00

    (@justrunlah)


    Hello,
    I will try to explain my issue here as much as I can, please let me know if it makes sense. I have searched for an answer to this but couldn’t get it.

    So, I have a custom post type called “race”. Every race has custom fields, let’s call them “A”, “B”, “C”.

    “A” can be an image field, and “B” a checkbox list.

    What I want to do is to query and get / list only “races” that have a value on “A”. So if “A” is an image, I can show a list of “races that have image”. And if “B” can take values “HM”, “FM”, “5km”, I can show only “races which are HM”.

    I have managed to do that by <?php if( get_field('A'): ?> and if( in_array( 'FM', get_field('race_category') ) or 'FM' == get_field('race_category') ): ?> respectively, the display works BUT, the query still gets all “race” posts, even if it only displays the ones which satisfy the criterion. I know this because of pagination.

    For example, I have a total of 16 “race” entries, but only one with “FM” category. As you see at the link, I manage to get it, but it is displayed on the 4th page (current pagination is 5 posts / page, and this is alphabetically the last entry, so pagination works). https://www.justrunlah.com/blog/sg-races-db-full-marathon-events/

    Also, I know how to use args arrays for simple stuff, for example I use the following to get entries that are within 2014 only, but I don’t know how to implement the more complicated statements needed into the args code.

    <?php
    		global $paged;
    		$curpage = $paged ? $paged : 1;
    		$today = date('Ymd');
    		$args = array(
    		    'post_type' => 'race',
    		    'orderby'	=> 'race_date',
    		    'meta_key' 	=> 'race_date',
    		    'order'	=> 'DES',
    		    'posts_per_page' => 50,
    		    'paged' => $paged,
    		    'meta_query' => array(
    		    'relation' => 'AND',
    				array(
    				'key'		=> 'race_date',
    				'compare'	=> '<=',
    				'value'		=> 20141231,
    			    ),
    				array(
    				'key'		=> 'race_date',
    				'compare'	=> '>=',
    				'value'		=> 20140101,
    			    )
    				),
    				);
    
    		?>

    In the following PasteBin I am giving you the code that gives that issue: https://pastebin.com/8hwdw0us

    Thanks in advance

Viewing 7 replies - 1 through 7 (of 7 total)
  • Moderator bcworkz

    (@bcworkz)

    You have the right idea, use the ‘meta_query’ array. You should be able to create fairly complex queries this way, though sometimes you need to get creative to work around some inherent limitations. For example, you can only specify an AND or OR relation, no combinations, but you can achieve an OR amongst an AND query by negating the one array’s logic. It may take some trial and error to get things dialed in.

    Another possibility if WP_Query is too restrictive is modify the actual SQL query string directly by using ‘posts_where_paged’ and related filters. If all else fails, write your own query and use $wpdb methods to get the desired results, though this does mean you would have to also manage pagination yourself.

    Thread Starter Johan F00

    (@justrunlah)

    hi bcworkz,
    thanks for the reply, however I am very new to this and not sure how to syntax such queries (I guess I will stick with the first option as the rest sound even more complicated).

    If I understand correctly, the statement should be inside the $args array, right?

    But how should the statement be to declare this?

    To get posts which have an image, I am thinking of something like:

    'relation' => 'AND',
    				array(
    				'key'		=> 'THE_FIELD_NAME_OF_THE_IMAGE',
    				'compare'	=> ' NOT EQUAL  ',
    				'value'	=> ' BLANK ' ,

    and to get the posts where “FM” is ticked as a checkbox:

    'relation' => 'AND',
    				array(
    				'key'		=> 'FM',
    				'compare'	=> ' ==  ',
    				'value'	=> ' get_field('A') ,
      ),
      relation' => 'OR',
    				array(
    				'key'		=> 'FM',
    				'compare'	=> 'IN_ARRAY',
    				'value'		=> get_field('A'),
    			    )

    Does it make sense?

    Could you help me with the syntax a bit? More specifically:
    – can I use “==” for text fields?
    – can I use get_field(”) command in value?
    – can I use “In_array” as compare?

    thanks

    Moderator bcworkz

    (@bcworkz)

    Yeah, the options are progressively more flexible and more difficult to implement, so one always tries to use the easiest until it becomes impossible to use.

    Right, part of the $args array, be sure the arrays are properly nested, even single arguments need to be nested to the correct levels. My examples will focus on meta_query arguments, you will still need to add in other arguments like post_type, etc. Also be sure your string parameters do not have leading or trailing spaces inside of the quotes.

    Like I said, some trial and error may be involved, but of course you need to ensure the syntax is not causing the query to fail. If you’re not sure about a particular syntax, try it out on a query where you know the arguments will yield a certain result. If the query fails, your syntax was wrong. It’s a pain, but correct syntax only comes with experience. Experience means lots of failures learning what not to do ??

    To get posts with any image in a particular field, your approach, corrected for syntax might work, but I would try this:

    $args = array(
      'meta_query' => array(
         array(
           'key' => 'image_path_field_name',
           'value' => '%',  // % is SQL wildcard character used with LIKE
           'compare' => 'LIKE',
         ),
      ),
    );

    Note how array declarations can have trailing commas — handy for future code maintenance. Don’t do this with function parameters though.

    I’m not sure I’m following your checkbox logic, I take it as you want all ‘race’ posts that have any image AND the FM box checked. The exact query depends on how you are storing the checkbox states. Expand the previous example to something like this:

    $args = array(
      'meta_query' => array(
        'relation' => 'AND',
         array(
           'key' => 'image_path_field_name',
           'value' => '%',  // % is SQL wildcard character used with LIKE
           'compare' => 'LIKE',
         ),
         array(
           'key' => 'checkbox_field_name',
           'value' => 'FM',
           'compare' => '==',
         ),
      ),
    );

    – can I use “==” for text fields?
    Yes, works for any field type for that matter.

    – can I use get_field(”) command in value?
    You can use functions in array declarations like this:
    'value' => get_post_meta( get_the_ID(), 'field_name'),
    but I’m not familiar with get_field(), so that particular function may not work.

    – can I use “In_array” as compare?
    Not exactly. You may use ‘IN’, which is the meta_query equivalent of in_array(). Be careful with character case, ‘IN’ works, ‘In’ does not.

    Thread Starter Johan F00

    (@justrunlah)

    Hi,

    First, thanks so much for the precious help, I think I got a better understanding now.

    However, I didn’t manage to get everything to work, even after lots of trial and error. Could you have a look below?

    What worked for displaying posts with image:

    $args = array(
    		    'numberposts' => -1,
    		    'post_type' => 'race',
    		    'orderby'	=> 'race_date',
    		    'meta_key' => 'race_date',
    		    'order'	=> 'DES',
    		    'posts_per_page' => 15,
    		    'paged' => $paged,
    		    'meta_query' => array(
    					array(
    					  'key' => 'medal_photo_1',
    					  'value' => '',
    					  'compare' => '!=',
    					),
    				),
    			);

    What didn’t work (no output):

    $args = array(
    		    'numberposts' => -1,
    		    'post_type' => 'race',
    		    'orderby'	=> 'race_date',
    		    'meta_key' => 'race_date',
    		    'order'	=> 'DES',
    		    'posts_per_page' => 15,
    		    'paged' => $paged,
    		    'meta_query' => array(
    
    					array(
    					  'key' => 'medal_photo_1',
    					  'value' => '%',
    					  'compare' => 'LIKE',
    					),
    				),
    			);

    Could it be because my image is an Object? Anyway, since I got it to do what I want it is OK for me.

    For the check-box, perhaps I didn’t make it clear. On my custom field, I have a multiple-case check box. Basically, I am listing event and one even can have either (or both) “FM” and “HM”.

    What I want is to get events that have ‘FM’, either if it is the only one, or part of an array. I think if only one option is checked it is a string and if more than one selected it becomes an array.

    I have tried both the following with no luck:

    array(
    					  'key' => 'race_category',
    					  'value' => '==',
    					  'compare' => 'FM',
    					),

    and

    array(
    					  'key' => 'race_category',
    					  'value' => 'IN',
    					  'compare' => 'FM',

    but it didn’t work ??

    I also tried to see how the field value looks like by <?php echo get_field('race_category') ?> but all it outputs is “Array”.

    Any ideas?

    One last thing, even for the case that works for the image (the first code snipet), when I try to combine with OR, it doesn’t work anymore… My code for combining them looks like this:

    'meta_query' => array(
                                 'relation' => 'OR',
    					array(
    					  'key' => 'medal_photo_1',
    					  'value' => '',
    					  'compare' => '!=',
    					),
    	                         array(
    					  'key' => 'medal_photo_2',
    					  'value' => '',
    					  'compare' => '!=',
    					),
    	                      array(
    					  'key' => 'medal_photo_2',
    					  'value' => '',
    					  'compare' => '!=',
    					),
    				),

    Moderator bcworkz

    (@bcworkz)

    Sorry, I don’t have any magic answers for you. Even my initial idea didn’t work ?? At least it illustrated the right approach for you, you obviously got that straight.

    I think I know why the multiple OR conditions don’t work though. It’s a common error when using negated operators. You actually want to relate with AND even though you think you want any one condition to be true. I’m not sure I can explain the logic adequately, try thinking through the the logic very carefully. Consider these two boolean operations are equivalent:

    ( $a == $b || $a == $c )
    ! ( $a != $b && $a != $c )

    Or save the brain power and just test it out ??

    All I can really offer is some debugging tips. First, to analyze the returned checkbox states array, don’t echo, either print_r() or var_dump(). The only difference is print_r() does not include type information. Type information can be useful, but it makes for a more cluttered array display. Either view the output in source mode (normal browser display ignores the array structure) or also echo <pre> </pre> tags so the browser honors the structure.

    Possibly you best tool for debugging meta queries is hooking the ‘posts_request’ filter and echoing out the passed query string. This is the actual query passed to mySQL constructed from your $args array. You can often see exactly why the query is not working and take measures to fix it.

    For a while I was puzzled why the query included WHERE (1=1). It has to do with how the query string is built. In addition, an error in parsing the query will result in WHERE (1=0), guaranteed failure.

    I think part of the problem may be the presence of ‘meta_key’ in the main array to make the ‘orderby’ work. You may find you may need to progress to the more complex approaches to get all the elements working together. Or maybe sort the returned array with PHP instead of SQL. Less efficient, but maybe easier on the brain.

    If you do find the need for a raw SQL query and aren’t a SQL master, you can at least start with the query from the ‘posts_request’ filter. Edit out the cruft like (1=1) and modify as needed. You may also find it more convenient to test such queries in myPhpAdmin instead of running through the WP process.

    Sorry I don’t have a better answer, but I hope I’ve given you some good tools. Best of luck to you!

    Thread Starter Johan F00

    (@justrunlah)

    hi,

    thanks a lot for the help and the tips!

    I got to make it work, for the record and for future reference, this was the winning one:

    'meta_query' => array(
    					array(
    					'key'		=> 'race_category',
    					'compare'	=> 'LIKE',
    					'value'		=> 'Full Marathon',
    				    )
    			    ),
    			);

    for value, either ‘Full’ or ‘Full Marathon’ (or ‘ull’ etc) will return the race posts that have the “Full Marathon” checkbox checked.

    All the best ??

    Moderator bcworkz

    (@bcworkz)

    You’re welcome!

    It’s funny how coding solutions often turn out to be stupid simple, if we could only see it to start with without all the in-between faffing about!

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘Custom post query but get only posts with IF statement’ is closed to new replies.