WP archives order by custom meta key - php

in Wordpress template's function.php following code is working well
// Function accepting current query
function my_change_order( $query ) {
// Check if the query is for an archive
if($query->is_archive())
// Query was for archive, then set order
$query->set( 'order' , 'asc' );
// Return the query (else there's no more query, oops!)
return $query;
}
// Runs before the posts are fetched
add_filter( 'pre_get_posts' , 'my_change_order' );
But i need to order articles by custom meta key like _my_meta_vip. Based on this answer i tried following lines, with half success, because only load articles with defined custom meta key, others are missing. How can i solve that?
function my_change_order( $query ) {
if($query->is_archive())
$query->set( 'orderby' , 'meta_value' );
$query->set( 'meta_key' , '_my_meta_vip' );
return $query;
}
add_filter( 'pre_get_posts' , 'my_change_order' );
How can i order my articles by custom meta key properly?

function my_change_order( $query ) {
// Check if the query is for an archive
if($query->is_archive())
// Query was for archive, then set order
$query->set( 'order' , 'asc' );
$query->set( 'meta_query', array(
array(
'key' => '_my_meta_vip'
)
));
// Return the query (else there's no more query, oops!)
return $query;
}
look at the following topic: https://wordpress.stackexchange.com/questions/20237/using-meta-query-how-can-i-filter-by-a-custom-field-and-order-by-another-one may give you a clear idea

Finally can't find any way to list all post with and without _my_meta_VIP defined.
In my solution all _my_meta_VIP was filled with enabled or disabled and the following code do the job:
// Function accepting current query
function my_change_order( $query ) {
// Check if the query is for an archive
if($query->is_archive()) {
// Query was for archive, then set order
$query->set( 'post_type', 'profile' );
$query->set( 'orderby' , 'meta_value' );
$query->set( 'meta_key' , '_my_meta_vip' );
$query->set( 'order', 'DESC' );
} else {
// Return the original query for non-archive pages
return $query;
}
// Return the query
return $query;
}
// Runs before the posts are fetched
add_filter( 'pre_get_posts' , 'my_change_order' );

It looks like the underlying issue here is that the query is doing an inner join on the posts and postmeta tables, which is why posts that don't have that particular post meta entry aren't being returned by the query. What you want is a left join. See this answer for an explanation of the difference.
You should be able to use the posts_join filter to replace the inner join with a left join:
add_filter('posts_join', function($join) {
global $wpdb;
// Replace inner join with left join
$search = 'INNER JOIN ' . $wpdb->postmeta;
$replace = 'LEFT JOIN ' . $wpdb->postmeta;
$join = str_ireplace($search, $replace, $join);
return $join;
});

Related

wordpress WP Query order by views count

hello I wanted to order articles post type by views count in wordpress. so I added a custom field to article post type which the name is view and it is a number field. I added it with PODS. I wrote this code in header.php so it it will incremenet automatically by each view:
<?php
if( get_post_type() == 'article' ) {
$postview = intval(get_post_field('views'));
if($postview > 0){
$postview = $postview+1;
}else{
$postview = 1;
}
$postID = $post->ID;
update_post_meta($postID,'views',$postview);
}
?>
it worked. but when I wanted to add a advanced query by elementor it does not work as expected. I added this to functions.php:
add_action( 'elementor/query/popular_articles', function( $query ) {
$query->set('post_type', 'article');
$query->set('meta_key', 'views');
$query->set('orderby', 'meta_value_num');
$query->set('order', 'DESC');
} );
I also tried this:
add_action( 'elementor/query/popular_articles', function( $query ) {
$query->set('orderby', 'views');
} );
none of those work as expected in elementor posts widget and the result is not sorted. when I set the popular_article query. the thing that I want to achieve with Wordpress WP_Query is something like this SQL query:
select post_title ,wp_z9gsc7_postmeta.meta_key,wp_z9gsc7_postmeta.meta_value from wp_z9gsc7_posts INNER JOIN wp_z9gsc7_postmeta ON wp_z9gsc7_posts.ID = wp_z9gsc7_postmeta.post_id where wp_z9gsc7_postmeta.meta_key = 'views' ORDER BY wp_z9gsc7_postmeta.meta_value DESC
thank you for your response in advance
this worked:
add_action( 'elementor/query/popular_articles', function( $query ) {
$query->set('post_type', 'article');
$query->set('meta_key', 'views');
$query->set('orderby', 'meta_value_num');
$query->set('order', 'DESC');
$query->set('offset', 0);
} );

wordpress custom query is too slow

I am trying to create a custom filter with the custom table in woocommerce. there is approx 24 000 products that makes the custom filter very slow. How to make it faster?
here is my code:
function custom_wpquery( $query ){
if(isset($_GET['min-price'])){
// the main query
global $wp_the_query;
global $wpdb;
if ( 'product' === $query->get( 'post_type' ) ) {
$rr = g($_GET['min-price'],$_GET['max-price']);
foreach($rr as $rrr){
$fabricc = $wpdb->get_results("SELECT * FROM CWF_posts WHERE post_title = '".$rrr."' AND post_type = 'product'");
foreach($fabricc as $fabriccc){
$cID[] = $fabriccc->ID;
}
}
//print_r();exit;
// foreach($cID as $cIDD){
// $cat= wp_get_post_terms( $dd->ID, 'product_cat' );
// }
//$dd = get_page_by_title( $rrr, OBJECT, 'product' );
// $include[]=$dd->ID;
//
// $c[] = $cat[0]->slug;
//$c2[] = $cat[1]->slug;
$query->set('post__in', $cID);
}
}
}
add_filter( 'pre_get_posts', 'custom_wpquery' );
Thanks
You can create a multiple-index on fields that you are querying... Since your one field is constant I advise that convert your SQL to
SELECT * FROM CWF_posts WHERE post_type = 'product' AND post_title = '".$rrr."'
and create an index on post_type and post_title with this command on MySQL
CREATE INDEX type_title_index on CWF_posts (post_type, post_title)
also you can check
Understanding multiple column indexes in MySQL query
https://dev.mysql.com/doc/refman/8.0/en/create-index.html

wp-job-manager show expired offers at end of list

I'm trying to figure this out with no luck, on the ajax list I want to sort the listings so that expired ones are at the end.
I've tried to use this filter
add_filter ( 'get_job_listings_query_args', 'sort_by_expired' );
function sort_by_expired( $query_args ) {
$today = date("Y-m-d", strtotime($date));
$query_args['orderby'] = 'meta_value_num';
$query_args['order'] = 'DESC';
// $query_args['meta_key'] = '_job_expires';
$query_args['meta_query'][] = array(
array(
'key' => '_job_expires',
// 'value' => date('Y-m-d'),
// 'compare' => '>='
)
);
return $query_args;
}
I've noticed that the code changes the order but not in the way I've would have wanted.
I tried to change different parameters (you can see the quoted out parts) changing:
mata_value_num to meta_value adding removing meta query parameters but with no luck.
From what i can understand you want to sort it by _job_expires ASC for the ones that are not expired and then display expired ones by DESC. this will have to be done in 2 separate queries. you can merge both arrays after that
edit: Merge 2 seperate queries' results as follows
//setup your queries as you already do
$query1 = new WP_Query($args_for_query1);
$query2 = new WP_Query($args_for_query2);
//create new empty query and populate it with the other two
$wp_query = new WP_Query();
$wp_query->posts = array_merge( $query1->posts, $query2->posts );
//populate post_count count for the loop to work correctly
$wp_query->post_count = $query1->post_count + $query2->post_count;
This is how I got it to work
public function depcore_custom_orderby( $query_args ) {
// Use meta_value_num for numeric sorting (if issues with meta_value)
$query_args[ 'orderby' ] = 'meta_value';
$query_args[ 'order' ] = 'DESC';
return $query_args;
}
public function depcore_custom_orderby_query_args( $query_args ) {
$query_args[ 'meta_key' ] = '_job_expires';
return $query_args;
}
Because I'm using the plugin boilerplate the filter call is used in the plugin public part
$this->loader->add_filter( 'job_manager_get_listings_args', $plugin_public, 'depcore_custom_orderby', 99 );
$this->loader->add_filter( 'get_job_listings_query_args', $plugin_public,'depcore_custom_orderby_query_args', 99 );

WooCommerce Custom Product Column Sortable Backed not working

I have a custom postmeta field which stores the post/product_id in a serialized way. Example _related_ids => a:4:{i:0;i:2462;i:1;i:2466;i:2;i:2469;i:3;i:2472;}
I'm showing the product_id count of _related_ids in WooCommerce Product Listing screen (Backed), which is working fine. Now I want to make that column sortable. So I write a function related_product_col_sort which is hooked into manage_edit-product_sortable_columns. Column Shorting is not working. (not working means it is not ordering the product_id count properly).
Here is my full code
//_related_ids => a:4:{i:0;i:2462;i:1;i:2466;i:2;i:2469;i:3;i:2472;}
//manage_product_posts_custom_column
add_filter('manage_edit-product_columns', 'related_product_col');
function related_product_col($columns) {
$new_columns = (is_array($columns)) ? $columns : array();
$new_columns['RELATED'] = 'Related Product';
return $new_columns;
}
add_action('manage_product_posts_custom_column', 'related_product_col_data', 2);
function related_product_col_data($column) {
global $post;
$related_product_ids = get_post_meta($post->ID, '_related_ids', true);
if ($column == 'RELATED') {
if (isset($related_product_ids) && !empty($related_product_ids)) {
echo count($related_product_ids);
} else {
echo "--";
}
}
}
add_filter("manage_edit-product_sortable_columns", 'related_product_col_sort');
function related_product_col_sort($columns) {
$custom = array(
'RELATED' => '_related_ids'
);
return wp_parse_args($custom, $columns);
}
Can anyone help me out with the correct logic/code with related_product_col_sort function.
Thanks.
Long Answer short - Basically, if you need to sort on a meta_value you can't store it serialized. Check https://wordpress.stackexchange.com/questions/87265/order-by-meta-value-serialized-array.
I think the best possible solution for you is to store the count of related products in a new meta_key and use that to sort the columns.
Below are the steps to sort your data if the column consists normal data instead of a serialized array.
There are actually 2 steps to make a custom column sortable
Register the column as sortable
Implement the sort logic
To register a column as sortable you use the manage_{YOUR_SCREEN_ID}_sortable_columns filter and add your column
You have already registered your column using the related_product_col_sort function, to implement the sort functionality you have couple ways depending on the type of data.
If the data is numeric or simple alphabets you can use the pre_get_posts action and set the meta_key and orderby values
add_action( 'pre_get_posts', 'manage_wp_posts_my_custom_pre_get_posts', 1 );
function manage_wp_posts_my_custom_pre_get_posts( $query ) {
/**
* We only want our code to run in the main WP query
* AND if an orderby query variable is designated.
*/
if ( $query->is_main_query() && ( $orderby = $query->get( 'orderby' ) ) ) {
switch( $orderby ) {
// If we're ordering by 'film_rating'
case 'RELATED':
// set our query's meta_key, which is used for custom fields
$query->set( 'meta_key', 'RELATED' );
/**
* Tell the query to order by our custom field/meta_key's
* This will only work is the meta_value for the RELATED key is either a number or a simple string
*/
$query->set( 'orderby', 'meta_value' );
break;
}
}
}
If your sorting value is more complicated like a date
add_filter( 'posts_clauses', 'manage_wp_posts_my_custom_posts_clauses', 1, 2 );
function manage_wp_posts_my_custom_posts_clauses( $pieces, $query ) {
global $wpdb;
/**
* We only want our code to run in the main WP query
* AND if an orderby query variable is designated.
*/
if ( $query->is_main_query() && ( $orderby = $query->get( 'orderby' ) ) ) {
// Get the order query variable - ASC or DESC
$order = strtoupper( $query->get( 'order' ) );
// Make sure the order setting qualifies. If not, set default as ASC
if ( ! in_array( $order, array( 'ASC', 'DESC' ) ) )
$order = 'ASC';
switch( $orderby ) {
// If we're ordering by release_date
case 'RELATED':
/**
* We have to join the postmeta table to
* include our release date in the query.
*/
$pieces[ 'join' ] .= " LEFT JOIN $wpdb->postmeta wp_rd ON wp_rd.post_id = {$wpdb->posts}.ID AND wp_rd.meta_key = '_related_ids'";
// This will only work if the meta_value is a date.
$pieces[ 'orderby' ] = "STR_TO_DATE( wp_rd.meta_value,'%m/%d/%Y' ) $order, " . $pieces[ 'orderby' ];
break;
}
}
return $pieces;
}

Wordpress Search with Multiple Post Meta Value Keywords (No Plugin)

I've searched everywhere for an answer to this and keep finding different suggestions, but none that seem to fit my particular needs. I currently have a website using a custom built search (no plugin). Website: GayBarsIn.com
The search functions I found work for searching custom post titles, post meta data (Advanced Custom Fields) and a combination of both title and post meta data, but only one post meta keyword works. I'm trying to find a way to search multiple post meta keywords.
For instance: The site shows bar listings.
If I search for a single keyword... say "Cleveland," it will return all listings with that keyword (whether in the title or post meta).
If I search for "Cleveland Ohio," it will return only those values found first in the title, then in the post meta, but just one instance of post meta. So if the title has Cleveland in it and the post meta has Ohio, it will return those results, but it will not show those that contain two instances of post meta data with keywords "Cleveland Ohio."
What I need for it to do is show results using multiple search terms for ALL post meta (custom fields). Example: "Cleveland and Ohio" or "Nightclub and Lounge and Houston"
Here is the code I found that works okay for a single keyword search:
/* ========================================
* SEARCH CUSTOM POST TYPES
* ======================================== */
function searchfilter($query) {
if ($query->is_search && !is_admin() ) {
$query->set('post_type', array('listing'));
}
return $query;
}
add_filter('pre_get_posts','searchfilter');
function cf_search_join( $join ) {
global $wpdb;
if ( is_search() ) {
$join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
}
return $join;
}
add_filter('posts_join', 'cf_search_join' );
/**
* Modify the search query with posts_where
*
* http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
*/
function cf_search_where( $where ) {
global $pagenow, $wpdb;
if ( is_search() ) {
$where = preg_replace(
"/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
}
return $where;
}
add_filter( 'posts_where', 'cf_search_where' );
/**
* Prevent duplicates
*
* http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
*/
function cf_search_distinct( $where ) {
global $wpdb;
if ( is_search() ) {
return "DISTINCT";
}
return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );
About half-way down the code, this section seems to be what should be edited, but I can't figure out how. I've tried switching 'OR' to 'AND' but that returns no results.
if ( is_search() ) {
$where = preg_replace(
"/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
}
I apologize if this has been asked before. I've looked for a few days and found others circling around what I'm trying to do, but not specifically enough for it to work for me. Any help or guidance would be much appreciated!
You should create your own form with input field for search, and catch data after post. You could split the words for example with explode() and put them into an array. You need to check if words exists as tag, so you need to loop through your array and check if it exists in get_tags($args). After that you should have an array with only useful tags. Now you can use get_posts()
$postargs = array(
'posts_per_page' => '-1',
'tag__and' => YOUR_ARRAY,
'orderby' => 'date',
'order' => 'DESC',
'post_type' => YOUR_CUSTOM_POST_TYPE,
'post_status' => 'publish',
'suppress_filters' => true
);
$posts_array = get_posts( $postargs );
You only need to loop (foreach) through your post-array and output results.

Categories