PHP/MySQL query find string in field - php

Ive written a query that searches for all posts that have X as a meta/custom field value.
// PSV National Query
if ($_POST['vehicleType'] == 'psv' && $_POST['coverageRegion'] == 'national' ) {
$customkey = 'vehicleType';
$customvalue = $_POST['vehicleType'];
$customkey1 = 'coverageRegion';
$customvalue1 = $_POST['coverageRegion'];
$customkey2 = 'locationType';
$customvalue2 = $_POST['locationType'];
global $wpdb;
$my_posts = $wpdb->get_results("
SELECT $wpdb->posts.*
FROM $wpdb->posts, $wpdb->postmeta, $wpdb->postmeta AS mt1
WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
AND $wpdb->postmeta.meta_key = '$customkey'
AND $wpdb->postmeta.meta_value = '$customvalue'
AND mt1.meta_key = '$customkey1'
AND mt1.meta_value = '$customvalue1'
AND mt2.meta_key = '$customkey2'
AND mt2.meta_value = '$customvalue2'
AND $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_type = 'post'
ORDER BY $wpdb->posts.post_date DESC
");
$args = array(
'meta_query' => array(
array(
'key' => $customkey,
'value' => $customvalue,
'compare' => '='
),
array(
'key' => $customkey1,
'value' => $customvalue1,
'compare' => '='
),
array(
'key' => $customkey2,
'value' => $customvalue2,
'compare' => '='
)
)
);
$query = new WP_Query( $args );
foreach ($query as $post) :
setup_postdata($post);
echo '<div><a href="';
the_permalink();
echo '"></div>';
the_title();
endforeach;
}
Now for my post I have 1 value for each meta key and this works fine, I want to however have multiple values.
For example...
"gas, electricity, water"
When I add multiple values however the query returns null, I presumer its because im saying if...
postmeta.meta_value = '$customvalue'
Can anybody give me advice on where im going wrong?

Why don't you use the built in WP QUERY, it supports meta field array operators.
for example:
$query = new WP_Query( array(
'meta_key' => 'color',
'meta_value' => 'blue',
'meta_compare' => '!='
));
Ref: http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters

If you are using multiple matches in a query's where clause you should use the IN variant istead of the =.
The only row I see in your query where you use $customvalue is here
AND $wpdb->postmeta.meta_value = '$customvalue'
You should change the = to IN and seperate the values with a , and quotes ' ' like this for example
AND $wpdb->postmeta.meta_value IN ('gas','electricity','water')
I ditched the $customvalue in the above code to make the point of the seperator of the IN value.
Hopefully this puts you on the right track.

Related

WP_query repeater "NOT LIKE" dosen't working

I have very annoying problem with WP_query and repeater . I try display something if $_GET is not equal to value in my DB. But when compare => NOT LIKE it now working correctly.
Here is my code:
function wyszukiwanie_trasy()
{
echo '<form action="" method="get">';
echo '<input type="text" name="od" placeholder="Stacja początkowa">';
echo '<input type="text" name="do" placeholder="Stacja końcowa">';
echo '<input type="date" name="data">';
echo '<input type="submit" value="Wyszukaj">';
echo '</form>';
$loop = new WP_Query(array('meta_query' => array(
'relation' => 'AND',
array(
'key' => 'date_%_daty_wykluczone',
'value' => str_replace("-","",$_GET['data'],$i),
'compare' => 'NOT LIKE'),
),
array(
'value' => $_GET['od'],
),
array(
'value' => $_GET['do'],
),'post_type' => 'trasy', 'posts_per_page' => -1));
while ($loop->have_posts()) : $loop->the_post();
$id = get_the_ID();
if($_GET['od'] && $_GET['do'] && $_GET['data'] && $_GET['od']!=$_GET['do'])
{
if( have_rows('location') ):
// loop through the rows of data
while ( have_rows('location') ) : the_row();
// display a sub field value
?>
<span style="font-weight: bold"><?php the_sub_field('lokacja');?></span>
<?php
echo ' ';
endwhile;
echo '<br />';
else :
echo 'Brak połączeń';
endif;
}
echo $loop->request;
endwhile; wp_reset_query();
}
Here is my SQL request:
SELECT wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key LIKE 'date_%_daty_wykluczone' AND wp_postmeta.meta_value LIKE '%20180715%' ) ) AND wp_posts.post_type = 'trasy' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'acf-disabled' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC
Imo is is something wrong with 'key' => 'date_%_daty_wykluczone', in my DB that meta keys looks like: date_0_daty_wykluczone date_1_daty_wykluczone, cause when i change this 'key' => 'date_%_daty_wykluczone', to 'key' => 'date_1_daty_wykluczone', 'NOT LIKE' works correctly
Thanks in advance :)
Try this code structure,
Using the "Relation" for the Meta Query, you can select multiple Meta Keys. You can change the "Compare" to any of the operations available for that function. (From the Codex) compare (string) - Operator to test. Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' and 'NOT EXISTS'. Default value is '='.
// WP_Query arguments
$args = array (
'post_type' => 'your-post-type',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'color',
'value' => 'Red',
'compare' => 'LIKE',
),
array(
'key' => 'color',
'value' => 'Plain',
'compare' => 'Like'
),
),
);
// The Query
$query = new WP_Query( $args );
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
// do something
}
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
Meta_query compare operator explanation
The first several work about like you would expect:
= equals
!= does not equal
> greater than
>= greater than or equal to
< less than
<= less than or equal to
LIKE and NOT LIKE are SQL operators that let you add in wild-card symbols, so you could have a meta query that looks like this:
array(
'key' => 'name',
'value' => 'Pat',
'compare' => 'LIKE'
)
This would return all posts where the meta value "name" has the string "Pat". In this case, "Pat" "Patricia" and "Patrick" would all be returned back to you. There's a non-WordPress tutorial explanation here

Exclude Featured Post from Custom Query WordPress

This is the custom query I'm running to display post from 2 categories.
I have installed WordPress Plugin "Featured Post" but the featured post is not excluding from the displayed list.
<?php
$category_id = get_cat_ID($strReports || $strInsights);
$custom_query = new WP_Query( 'cat=' .$category_id. '&featured=no&posts_per_page=6&order=desc' );
while($custom_query->have_posts()) : $custom_query->the_post();
?>
HTML Content Here
<?php endwhile; ?>
<?php wp_reset_query(); // reset the query ?>
Looking through "Featured Post" you can see that it just test against yes value. What feature=yes does is just check a meta field, so I think you can do the reverse way to achieve what you want, like this:
$args = array(
'cat' => $category_id,
'posts_per_page' => 6,
'order' => 'DESC', // since order default value is already DESC you can remove this line
'meta_query' => array(
'relation' => 'OR',
array(
'key' => '_is_featured',
'value' => 'yes',
'compare' => '!=',
),
array(
'key' => '_is_featured',
'value' => 'foo', // Prior to WP 3.9 we have to provide any non-empty string here
'compare' => 'NOT EXISTS',
),
) ,
);
$custom_query = new WP_Query($args);
Hope it helps!
your'e running an invalid argument on get_cat_ID.
should be something like this:
<?php
$cat_names = array('Cat_Name1', 'Cat_Name2');
$category_Name = implode(',', $cat_names);
$args = array(
'category_name' => $category_Name,
'posts_per_page' => 6,
'meta_query' => array(
array(
'key' => 'featured',
'value' => true,
'compare' => '!=',
),
),
);
$custom_query = new WP_Query( $args );
while($custom_query->have_posts()) : $custom_query->the_post();
?>
<?php the_title();?>
<?php endwhile; ?>
<?php wp_reset_query(); // reset the query ?>
create your custom query and add filter.
function SearchFilter($query){
$query=" SELECT Distinct SQL_CALC_FOUND_ROWS p.* FROM `$wpdb->posts` as p left join `$wpdb->postmeta` as m on m.post_id=p.ID "
." left join `$wpdb->term_relationships` as r ON (p.ID = r.object_id) "
." left join `$wpdb->term_taxonomy` as x ON (x.term_taxonomy_id = r.term_taxonomy_id) "
." left join `$wpdb->terms` as t ON (t.term_id = x.term_id AND x.taxonomy='category') "
." WHERE p.post_type = 'post' AND p.post_status = 'publish' "
." AND t.term_id='$idcategorie' "
return $query;
}
add_filter( 'posts_request', 'SearchFilter' );

Filtering WordPress children posts by parents taxonomy using WP_Query?

I have a custom events post type in WordPress (with recurring events being saved as children to the main event) I have a few custom taxonomies set up which only saves the custom taxonomy data to the parent event post,
but what I am trying to figure out is how to filter the results (including the recurring children posts) by the custom taxonomies.
At current I have something similar to:
$args = array(
'post_type' => 'incsub_event',
'posts_per_page' => 50,
'post_status' => array( 'recurrent', 'publish'),
'meta_query' => array(
array(
'key' => 'incsub_event_start',
'value' => array( $date_1, $date_2 ),
'type' => 'DATETIME',
'compare' => 'BETWEEN'
),
array(
'key' => 'incsub_event_fee',
'value' => array( '10', '1000' ),
'type' => 'NUMERIC',
'compare' => 'BETWEEN'
),
array(
'key' => 'incsub_event_status',
'value' => 'open',
'type' => 'BINARY',
'compare' => '='
),
),
'tax_query' => array(
array(
'taxonomy' => 'location',
'field' => 'slug',
'terms' => 'uk',
),
),
'order' => 'ASC',
'orderby' => 'meta_value',
'meta_key' => 'incsub_event_start'
);
But it will only return the parent posts not the children, I would be grateful to anyone who could shed some help on the matter?
I had this issue a while ago and the solution isn't pretty. As far as I know, Wordpress's get_posts function doesn't support nested queries where 'parent has x-attribute'. To access the child posts you're going to have to roll your own get_posts-style function, using $wpdb to access the database. I've created a function for you that will work as the basis for this kind of query. There are probably some improvements and additions that need to be made to include other common search variables, but for your current query it will get the job done.
function customGetPosts($args) {
global $wpdb;
$wpdb->show_errors();
extract($args);
$limit = isset($posts_per_page) ? $posts_per_page : 50;
$post_type = isset($post_type) ? $post_type : "post";
$post_status = isset($post_status) ? $post_status : "publish";
$post_status = is_array($post_status) ? "IN ('" . implode("' ,'", $post_status) . "')" : "= '$post_status'";
$order = isset($order) && in_array($order, ["ASC", "DESC"]) ? $order : "DESC";
$order = isset($orderby) && isset($meta_key) ? "ORDER BY $meta_key $order" : "";
if (isset($meta_query) && is_array($meta_query) && count($meta_query) > 0) {
$meta_query_string = ", ";
$meta_query_where_string = "";
$is_first = true;
foreach($meta_query as $query) {
if ($is_first) {
$is_first = false;
$meta_query_where_string .= "WHERE ";
} else {
$meta_query_where_string .= "AND ";
}
$meta_query_string .= "MAX(IF(wpm.meta_key = '{$query['key']}', wpm.meta_value, NULL)) AS {$query['key']}, ";
switch($query['type']) {
case("NUMERIC"):
$delimiter = "";
break;
default:
$delimiter = "'";
}
switch ($query['compare']) {
case("BETWEEN"):
$meta_query_where_string .= "{$query['key']} {$query['compare']} $delimiter{$query['value'][0]}$delimiter AND $delimiter{$query['value'][1]}$delimiter ";
break;
default:
$meta_query_where_string .= "{$query['key']} {$query['compare']} $delimiter{$query['value']}$delimiter ";
}
}
$meta_query_where_string = substr($meta_query_where_string, 0, strlen($meta_query_where_string) - 1);
$meta_query_string = substr($meta_query_string, 0, strlen($meta_query_string) - 2);
}
if (isset($tax_query) && is_array($tax_query) && count($tax_query) > 0) {
foreach($tax_query as $query) {
$terms = is_array($query['terms']) ? "'" . implode("', '", $query['terms']) . "'" : "'{$query['terms']}'";
$tax_query_string .= "AND wtt.taxonomy = '{$query['taxonomy']}' AND wt.{$query['field']} IN ({$terms}) ";
}
}
return $wpdb->get_results("
SELECT * FROM
(
SELECT wp.*$meta_query_string
FROM wp_posts wp
JOIN wp_term_relationships wtr ON wp.ID = wtr.object_id
JOIN wp_term_taxonomy wtt ON wtt.term_taxonomy_id = wtr.term_taxonomy_id
JOIN wp_terms wt ON wtt.term_id = wt.term_id
JOIN wp_postmeta wpm ON wpm.post_id = wp.ID
WHERE wp.post_status $post_status
$tax_query_string
AND wp.post_type = '$post_type'
GROUP BY wp.ID
UNION ALL
SELECT wp.*$meta_query_string
FROM wp_posts wp
JOIN wp_postmeta wpm ON wpm.post_id = wp.post_parent
WHERE wp.post_parent IN (
SELECT wp.ID FROM wp_posts wp
JOIN wp_term_relationships wtr ON wp.ID = wtr.object_id
JOIN wp_term_taxonomy wtt ON wtt.term_taxonomy_id = wtr.term_taxonomy_id
JOIN wp_terms wt ON wtt.term_id = wt.term_id
JOIN wp_postmeta wpm ON wpm.post_id = wp.ID
WHERE wp.post_status $post_status
$tax_query_string
AND wp.post_type = '$post_type'
)
GROUP BY wp.ID
) as main
$meta_query_where_string
$order
LIMIT $limit"
);
}
As a sidenote, your metavalues can be accessed through their metakey in the getCustomPosts output, e.g.: while iterating through the results, $post->incsub_event_start

Search with post_meta

I write my own query to wordpress database and I'm stuck. I have many (5) custom fields like:
town
price
size
... etc
and in search.php I have:
$querystr = "
SELECT wposts.*
FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta
WHERE wposts.ID = wpostmeta.post_id ";
$town = addslashes($_GET['town']);
if($town!=''){
$querystr .= " AND wpostmeta.meta_key = 'town' AND wpostmeta.meta_value = '".$town."'";
}
$mo = addslashes($_GET['mo']);
if($mo!='' && preg_match("/^\d+$/", $mo)){
$querystr .= " AND wpostmeta.meta_key = 'price' AND wpostmeta.meta_value > '".$mo."'";
}
$md = addslashes($_GET['md']);
if($md!='' && preg_match("/^\d+$/", $md)){
$querystr .= " AND wpostmeta.meta_key = 'price' AND wpostmeta.meta_value < '".$md."'";
}
$querystr .= " AND wposts.post_status = 'publish' AND wposts.post_type = 'post'";
$pageposts = $wpdb->get_results($querystr, OBJECT);
but this does not work. If I use only one condition:
$querystr = "SELECT wposts.* FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta WHERE wposts.ID = wpostmeta.post_id ";
$town = addslashes($_GET['town']);
if($town!=''){
$querystr .= " AND wpostmeta.meta_key = 'town' AND wpostmeta.meta_value = '".$town."'";
}
$querystr .= " AND wposts.post_status = 'publish' AND wposts.post_type = 'post'";
$pageposts = $wpdb->get_results($querystr, OBJECT);
then it will work. What I'm doing wrong?
The select expression doesn't make sense as a whole because you have contradictive where conditions. It also doesn't make sense in relation to how relational databases work. You want to match two unique rows that share the same column names in one query, this is not possible without using techniques like subqueries.
Consider that all expression parts must be true and you got something like this:
SELECT wposts.*
FROM wp_posts wposts, wp_postmeta wpostmeta
WHERE wposts.ID = wpostmeta.post_id
AND wpostmeta.meta_key = 'town' AND wpostmeta.meta_value = 'My town'
AND wpostmeta.meta_key = 'price' AND wpostmeta.meta_value > 500
Here you say meta_key equals "town" AND meta_value equals "My town". That makes sense, but when you also say meta_key also equals "price" AND meta_value is also greater than 500. The expression will never be true and regardless the parser also has no way of grouping together the two different condition sets.
WP_Query
If possible I suggest that you use the WP_Query class instead of directly querying the database. This wrapper greatly simplifies your code and makes it easier to maintain. Note that the code requires WordPress >=3.1 as it uses the meta_query option.
Your query can be written like this:
<?php
// The arguments that defines the query
$args = array(
'post_status' => 'publish',
'post_type' => 'post'
);
// We define the meta/custom field conditions
$meta_query = array();
// PS: No need to slash the values, WordPress will do that for us
$town = $_GET['town'];
$mo = (int) $_GET['mo']; // Simple sanitizment, implement your own as see fit
$md = (int) $_GET['md']; // Simple sanitizment, implement your own as see fit
if ( $town ) {
$meta_query[] = array(
'key' => 'town',
'value' => $town
);
}
if ( $mo ) {
$meta_query[] = array(
'key' => 'price',
'value' => $mo,
'type' => 'NUMERIC',
'compare' => '>'
);
}
if ( $md ) {
$meta_query[] = array(
'key' => 'price',
'value' => $md,
'type' => 'NUMERIC',
'compare' => '<'
);
}
if ( $meta_query ) {
// Add the meta_query conditions to the arguments array
$meta_query['relation'] = 'AND';
$args['meta_query'] = $meta_query;
}
// Create WP_Query object with the arguments
$query = new WP_Query( $args );
// Fetch the posts
$posts = $query->get_posts();
// Voila!
?>

Filter query_posts by two custom fields?

I'm trying to filter my posts to only show the ones with that have a custom value for the field "Model" while sorting the posts by another custom field called "Price."
Here's the function I'm using (not working):
<?php
global $query_string;
query_posts( $query_string . "&meta_value=Model&orderby=meta_value&meta_key=Price&order=ASC");
?>
This function only shows Models, yet doesn't sort the posts by Price. If i add &meta_value=Model after order=ASC it sorts by Price but shows all posts, and not just Models.
Have you looked at http://codex.wordpress.org/Class_Reference/WP_Query
Specifically this section:
Multiple Custom Field Handling:
Display posts from several custom field:
$args = array(
'post_type' => 'product',
'meta_query' => array(
array(
'key' => 'color',
'value' => 'blue',
'compare' => 'NOT LIKE'
),
array(
'key' => 'price',
'value' => array( 20, 100 ),
'type' => 'numeric',
'compare' => 'BETWEEN'
)
)
);
$query = new WP_Query( $args );
did you try and array?
$args = array(
'meta_value' => array('Model','Price')
);
query_posts($args);
I know this is an old question, but I needed the answer today and couldn't find it anywhere. I found the question and then created an answer (shown below):
<?php
$sql = "
SELECT ID, meta1.meta_value, meta2.meta_value from $wpdb->posts p
JOIN $wpdb->postmeta meta1 ON meta1.post_id = p.ID
JOIN $wpdb->postmeta meta2 ON meta2.post_id = p.ID
WHERE p.post_status = 'publish'
AND p.post_type = 'post'
AND meta1.meta_key = 'Model'
AND meta2.meta_key = 'Price'
ORDER BY meta2.meta_value DESC
";
$posts_with_meta = $wpdb->get_col($sql);
$my_query = new WP_Query();
foreach ($posts_with_meta as $p) {
$post = get_post(intval($p));
setup_postdata($post);
print_r($post);
}
?>

Categories