Wordpress hook to display latest pending posts instead of already published - php

I'm stuck on something that I'm sure must be pretty simple but is getting me nuts. I'm forced at work to use WordPress, which I have zero experience with, and I'm struggling so far to understand how it operates regarding hooks and filters.
What I want is pretty simple:I'm using the latest posts block to display posts written by users. Except that the page I'm working on would be the front end for the website's moderator who would have to see the posts with the 'pending' status, not the 'publish' one. I couldn't find any option to change that in the editor, so I'm trying to set a hook to change the query from 'post_status' => 'publish' to 'post_status' => 'pending', but it's not working, I get a 'Oops! That page can’t be found.'
Here's what I wrote in my functions.php:
function name_of_the_function( $query ) {
if( get_query_var('pagename') == 'name_of_the_page' && current_user_can('publish_posts') && $query->is_main_query() ) {
$query->set( 'post_status', 'pending' );
return $query;
}
}
add_filter( 'pre_get_posts', 'name_of_the_function' );
If I leave this function exactly like that but write 'publish' instead of 'pending' the page displays correctly the last published posts, but with 'pending' I get the message I mentioned before. And I tried with add_action instead of add_filter and got hte same results.
I'd like to add that I do have pending posts awaiting, and if I write the following in my page template, they are found:
$args = array (
'cat' => 5,
'post_status' => 'pending'
);
$query = new WP_Query( $args );
while ( $query->have_posts() ) {
$query->the_post();
echo get_the_title();
}
Just to check, directly in the wp-includes/latest-posts.php file, I changed :
$args = array(
'posts_per_page' => $attributes['postsToShow'],
'post_status' => 'publish',
'order' => $attributes['order'],
'orderby' => $attributes['orderBy'],
'suppress_filters' => false,
);
to :
$args = array(
'posts_per_page' => $attributes['postsToShow'],
'post_status' => 'pending',
'order' => $attributes['order'],
'orderby' => $attributes['orderBy'],
'suppress_filters' => false,
);
It works and displays the pending posts but of course I can't use that as the file would be erased at every WordPress update.
Sorry for the long post but I'm lost now and don't know what else to do, I've looked all other the intrnet but can't find an answer to this, I would really appreciate any help regarding that matter, thanks in advance.

By using the pre_get_posts with $query->is_main_query(), you apply this to the query that WordPress uses to find the page (the main query). Your code needs to be changed to:
function name_of_the_function( $query ) {
if ( is_admin() || $query->is_main_query() ) {
return $query;
}
if( get_query_var('pagename') == 'name_of_the_page' && current_user_can('publish_posts') ) {
$query->set( 'post_status', 'pending' );
}
return $query;
}
add_filter( 'pre_get_posts', 'name_of_the_function' );
So basically, don't run this on any query in the admin or any query that is the main query, but only run it on a specific page for people with specific capabilities.

Related

Is there any way to have a wordpress multi domain setup with shared post and templates and so on?

I wonder if there is any way to have only one wordpress instant which has 2 different domains (one main domain and one subdomain). The content of the domains should be different but also share pages and templates and posts. E.g. a page "employees" should be the same for both domains.
I have already set up a WordPress network and so the multi-domain setup works but unfortunately pages and posts and templates are separated. There are plugins which mirror e.g. posts also on the other domain but here is then again the problem that I have saved the post 2 times.
Maybe you already have a plugin which can do this, without any coding, but i'm not familiar with them.
An idea would be to hook onto the save_post action and push the newly created post to the different blogs.
if ( ! function_exists( 'post_to_multiple_sites' ) ) {
add_action( 'save_post', 'post_to_multiple_sites', 20, 2 );
function post_to_multiple_sites($original_id, $original_post) {
// To prevent publishing revisions
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $original_id;
}
// We only want to mess around with a post that has been published
if( 'publish' !== get_post_status( $original_post ) ) {
return $original_id;
}
// prevent "Fatal error: Maximum function nesting level reached"
remove_action( 'save_post', __FUNCTION__ );
/**
* If i'm correct, when creating a network, each site/blog receive an ID.
* You can set these hardcoded, or create a function that returns an array of the blog id's.
*
* If you only have a couple of sites, I would maintain this manually. Otherwise create a function to
* gather all the ID's and return it as an array (up to you).
*/
$blog_ids = [2, 3];
$post_data = [
'post_author' => $original_post->post_author,
'post_date' => $original_post->post_date,
'post_modified' => $original_post->post_modified,
'post_content' => $original_post->post_content,
'post_title' => $original_post->post_title,
'post_excerpt' => $original_post->post_excerpt,
'post_status' => 'publish', // new post will be set to published
'post_name' => $original_post->post_name,
'post_type' => $original_post->post_type,
];
// Gather the post meta & terms
$post_terms = wp_get_object_terms( $original_id, 'category', array( 'fields' => 'slugs' ) );
$post_meta = get_post_custom( $original_id );
foreach ($blog_ids as $blog_id) {
switch_to_blog($blog_id); // https://developer.wordpress.org/reference/functions/switch_to_blog/
// IN case a post with the same slug exists, don't do anything.
// Or maybe create a new post with slug-name-2...up to you.
if ( get_posts( [ 'name' => $post_data[ 'post_name' ], 'post_type' => $post_data[ 'post_type' ], 'post_status' => 'publish' ] ) ) {
restore_current_blog();
continue;
}
$inserted_post_id = wp_insert_post( $post_data );
wp_set_object_terms( $inserted_post_id, $post_terms, 'category', false );
foreach ( $post_meta as $meta_key => $meta_values) {
// we do not need these redirects
if( '_wp_old_slug' === $meta_key ) {
continue;
}
foreach ( $meta_values as $meta_value ) {
add_post_meta( $inserted_post_id, $meta_key, $meta_value );
}
}
restore_current_blog();
}
}
}
It became a bigger function than I expected and honestly don't know if you should go this route. Your safest bet is to try and find a plugin that handles this for you. But you can use this piece of code and extend it obviously to your needs
Make sure to read the comments I added. These are important!

Get processing status orders count in WooCommerce?

I want to get the processing order count in WooCommerce. I'm using the following code in the Code Snippet plugin but that is working.
if( !function_exists( 'wc_processing_order_count' ) ) {
require_once '../plugins/woocommerce/includes/wc-order-functions.php';
}
// NOTICE! Understand what this does before running.
$result = wc_processing_order_count();
It's returning nothing.
This custom function use a very light SQL query to get the orders count from a specific status:
function get_orders_count_from_status( $status ){
global $wpdb;
// We add 'wc-' prefix when is missing from order staus
$status = 'wc-' . str_replace('wc-', '', $status);
return $wpdb->get_var("
SELECT count(ID) FROM {$wpdb->prefix}posts WHERE post_status LIKE '$status' AND `post_type` LIKE 'shop_order'
");
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Usage example for "processing" orders count:
// Display "processing" orders count
echo get_orders_count_from_status( "processing" );
Both the answers above are way too complicated for something so simple.
Simplest way is this :)
$processing_orders_count = count(wc_get_orders( array(
'status' => 'processing',
'return' => 'ids',
'limit' => -1,
)));
This method could help you. The order is stored as post_type shop_order. So by creating query to get all posts of type shop_order and by passing arguments to get all processing order, you will be able to get those orders
$args = array(
'post_type' => 'shop_order',
'post_status' => 'publish',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'shop_order_status',
'field' => 'slug',
'terms' => array('processing')
)
)
);
$loop = new WP_Query( $args );
while ( $loop->have_posts() ){
$loop->the_post();
$order_id = $loop->post->ID;
$order = new WC_Order($order_id);
}
Take a look at: https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query
That reference really helped me in a similar situation.
Using the WC functions ensures your code is more future proof compared to using a hardcoded query or WP_Query as mentioned in other answers.

Weird Order of Wordpress Category Post

Does anyone have ever seen this?
When we're accessing one of wordpress category post here:
On the top item, it's not the latest posted article instead it's the oldest one.
Which part of the php code should be changed ? It's for wordpress version of 4.5 from this link.
function change_category_order( $query ) {
$category = get_queried_object();
$cat_id=$category->term_id;
if ( $query->is_category($cat_id) && $query->is_main_query() ) {
$query->set( 'order', 'DESC' );
}
}
add_action( 'pre_get_posts', 'change_category_order' );
If you use any custom query add this also in post loop 'order' => 'DESC'
$args = array(
'post_type' => 'post',
'order' => 'DESC', );
$q = new WP_Query($args);
or paste this in function.php
add_action( 'pre_get_posts', 'my_change_sort_order');
function my_change_sort_order($query){
if(is_archive()):
//If you wanted it for the archive of a custom post type use: is_post_type_archive( $post_type )
//Set the order ASC or DESC
$query->set( 'order', 'DESC' );
//Set the orderby
//$query->set( 'orderby', 'title' );
endif;
};

Jetpack Infinite Scroll ignore posts already displayed

I am using JetPack's Infinite Scroll on the homepage of our site and it is working fine but I also want to display certain posts on there.
If a post is displayed outside the infinite loop I want it to be removed from the so there is no duplication.
I have a global array set up using bm_ignoreposts and have added it to the infinite loop render but for some reason it is not working. Here is the code.
Functions.php
The infinite renderer.
add_filter( 'infinite_scroll_archive_supported', 'tweakjp_custom_is_support' );
function mm_infinite_scroll_render() {
global $post;
while ( have_posts() ) : the_post();
bm_ignorePost($post->ID);
get_template_part( 'content-inf' );
endwhile;
}
The query
function mm_infinite_scroll_query_args($args) {
$new_args = array(
'posts_per_page' => $args['posts_per_page'],
'paged' => $args['paged'],
'orderby' => 'date',
'order' => 'DESC',
'post_type' => array( 'post', 'features', 'it_hardware', 'videos' ),
'post_status' => 'publish',
);
return $new_args;
}
For reference here is the ignore posts code:
function bm_ignorePost ($id) {
if (!is_page()) {
global $bmIgnorePosts;
$bmIgnorePosts[] = $id;
}
}
I decided to not use JetPack anymore and go for a custom Javascript version which uses AJAX to load new posts running a new query.
After speaking to Jetpack support, they believe it is not possible based on how the plugin works.

Only return posts with comments in Wordpress

I'm surprised I cannot find much on this topic, perhaps I'm confused.
I am creating an archive page of comments. I want to get all posts with comments where I will list the post title followed by the all the comments for that post underneath using wp_list_comments or WP Comment Query.
My question is how can I filter WP_Query() so I can only return posts that have comments.
I've tried to modify this approach list posts with no comments - postpostmodern's answer but I want to do the exact opposite.
Here is the function:
function filter_comment_count( $sql ){
global $wpdb;
$comment_count = get_query_var( 'comment_count' );
if( is_numeric($comment_count) )
$sql .= $wpdb->prepare( " AND {$wpdb->posts}.comment_count != %d ", $comment_count);
return $sql;
}
add_filter( 'posts_where', 'filter_comment_count' );
And then I'm attempting to use it in my loop, here is an excerpt:
$args = array (
'comment_count' => '0'
'pagination' => true,
'posts_per_page' => '10',
);
$the_query = new WP_Query($args);
while($the_query->have_posts()) : $the_query->the_post();
get_template_part( 'content', get_post_format() );
endwhile;
wp_reset_postdata();
I guess the bit that is tripping me up is AND {$wpdb->posts}.comment_count != %d I want it to return comment_count not equal to 0 or whatever allows me to get only posts with comments in my WP_Query($args);
Also I'm not sure where to put remove_filter( 'posts_where', 'filter_comment_count' );?
I realise there is 'orderby' => 'comment_count' but that doesn't exactly help my situation as far as I understand.
Might not give the exact results you want, nor be efficient, but this is all I can think of:
Inside your loop, add:
$comments = get_comments(array('post_id' => $post->ID));
if ($comments !== '' && !empty($comments)) {
// The rest.
}
And that should output only the posts that have comments associated with them.
Edit:
There's also
if( 0 < $post->comment_count ){
// Output
}
Which I retrieved from here:
https://wordpress.stackexchange.com/questions/125577/only-display-posts-with-comments
Old question but if anyone stumbles on this as I did, WordPress 4.9 added 'comment_count' parameter to WP_Query.
The value can either be an integer of the number of comments you require or an array where the first argument is the 'value' and the second is a 'compare' search operator.
To only return posts with comments :
$args = array(
'comment_count' => array(
'value' => 0,
'compare' => '>',
),
'pagination' => true,
'posts_per_page' => 10,
);
$the_query = WP_Query( $args );
See https://developer.wordpress.org/reference/classes/wp_query/#comment-parameters.

Categories