The following code runs inside of the Facebook Instant Articles plugin by Automattic. It is the query used to generate the RSS feed that facebook pulls for instant articles.
function instant_articles_query( $query ) {
if ( $query->is_main_query() && $query->is_feed( INSTANT_ARTICLES_SLUG ) ) {
$query->set( 'orderby', 'modified' );
$query->set( 'posts_per_page', 100 );
$query->set( 'posts_per_rss', 100 );
$settings_categories = Instant_Articles_Option_Categories::get_option_decoded();
if($settings_categories['categories'] !== '') {
$query->set( 'cat', $settings_categories['categories'] );
}
/**
* If the constant INSTANT_ARTICLES_LIMIT_POSTS is set to true, we will limit the feed
* to only include posts which are modified within the last 24 hours.
* Facebook will initially need 100 posts to pass the review, but will only update
* already imported articles if they are modified within the last 24 hours.
*/
if ( defined( 'INSTANT_ARTICLES_LIMIT_POSTS' ) && INSTANT_ARTICLES_LIMIT_POSTS ) {
$query->set( 'date_query', array(
array(
'column' => 'post_modified',
'after' => '1 day ago',
),
) );
}
}
}
add_action( 'pre_get_posts', 'instant_articles_query', 10, 1 );
I need to modify the query that this runs to take a meta query but I need to do so outside of the plugin file. I know that hooks are the way to go but is it possible or correct to do the following?
function mod_ia_query( $query ) {
$query->set( 'meta_query', array(
array(
'key' => 'is_instant_article',
'value' => true
),
);
}
add_action('instant_articles_query','mod_ia_query', 10, 1);
I'm coming back to update this but essentially what I did was create a subdirectory in my theme with the name of the facebook instant articles plugin and create a class that extends the Instant_Articles Class.
I unhooked the add_action( 'pre_get_posts', 'instant_articles_query', 10, 1 );
And added my own method to the hook, this performs my functionality within the context of the plugin but without directly editing core plugin files.
Related
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.
I am trying to exclude a specific category ID from showing in WordPress search results. I have tried with this code which I have found several places on the internet, but it does not seem to work. I have changed the ID to the correct ID.
function my_search_filter( $query ) {
if ( $query->is_search && !is_admin() )
$query->set( 'cat','-21' );
return $query;
}
add_filter( 'pre_get_posts', 'my_search_filter' );
Right now my solution is using the code below, where I have to manually insert every page ID. It is working, but not a good solution.
add_action('pre_get_posts','exclude_posts_from_search');
function exclude_posts_from_search( $query ){
if( $query->is_main_query() && is_search() ){
//Exclude posts by ID
$post_ids = array(52384,52366,52058,52392,52374);
$query->set('post__not_in', $post_ids);
}
}
Would it be possible to use my current code with categories instead of every page ID? Or is the first code example the way to go, but with some changes?
Place the following function in your active theme functions.php file
function exclude_categories_from_search($query) {
// run query only if we are searching
if ( !$query->is_search )
return $query;
$term_ids = array( 19, 18, 214, 226, 20 ); add category/term ids
$taxquery = array(
array(
'taxonomy' => 'category', //Here add your taxonomy eg: category
'field' => 'id',
'terms' => $term_ids,
'operator'=> 'NOT IN'
)
);
$query->set( 'tax_query', $taxquery );
}
add_action( 'pre_get_posts', 'exclude_categories_from_search' );
I have a WordPress site with 1000s of posts. I'd like to set all posts older than 30 days to draft automatically when it reaches the specified date.
Been staring myself blind at the following code - triggering the CRON manually has now effect:
<?php
/**
* Function that will draft specific posts on specific conditions
*
* #param \WP_Post $_post
*/
function tgs_maybe_draft_the_post( $_post ) {
$publish_date = get_the_date( 'd M Y', $_post->ID);
// Bail if no publish date set for some reason.
if ( ! $publish_date ) {
return;
}
// Set status to draft if older than 30 days.
if (strtotime($publish_date) < strtotime('-30 days')) {
wp_update_post( array(
'ID' => $_post->ID,
'post_status' => 'draft'
) );
}
}
/**
* Register cron event on init action
*/
function tgs_cron_schedule_draft_posts() {
$timestamp = wp_next_scheduled( 'tgs_draft_posts' );
if ( $timestamp == false ) {
wp_schedule_event( time(), 'hourly', 'tgs_draft_posts' );
}
}
add_action( 'init', 'tgs_cron_schedule_draft_posts' );
/**
* Handle deletion of posts periodically.
* - Loop through the posts and call the tgs_maybe_draft_the_post function.
*/
function tgs_draft_posts_handler() {
$posts = get_posts( array(
'posts_per_page' => - 1,
'post_type' => 'post',
'post_status' => 'publish',
'suppress_filters' => true,
) );
foreach ( $posts as $_post ) {
tgs_maybe_draft_the_post( $_post );
}
}
add_action( 'tgs_draft_posts', 'tgs_draft_posts_handler' );
What am I doing wrong?
You can troubleshoot your logic (change status to draft) by running that logic directly during a page view rather than from cron. Try using the wp_footer action, something like this.
add_action( 'wp_footer', 'tgs_draft_posts_handler')
You can then include print_r(); debugging code and it will show up on your rendered page: ugly but useful. You could do print_r('about to do get_posts'); for example.
You can search for posts with date criteria. That way you don't need a separate check for the posts' age. With thousands of posts this is a significant time saver.
$posts = get_posts( array(
'posts_per_page' => - 1,
'post_type' => 'post',
'post_status' => 'publish',
'suppress_filters' => true,
'date_query' => array(
array(
'column' => 'post_date_gmt',
'before' => '30 days ago'
)
),
) );
Once your basic logic works, you can get it working under cron.
And, turn on the WordPress debugging stuff. It helps a lot.
When it all works, don't forget to remove the print_r() statements (duh, obviously).
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;
};
I want to trash (not force delete) a Custom Post Type after 30 days.
To do this, I've found a nice solution from #pieter-goosen to delete posts after a number of days: https://wordpress.stackexchange.com/questions/209046/delete-expired-posts-after-a-number-of-days-after-they-expired
My problem is, that the function deletes all the posts of this Custom Post Type and doesn't use the trash.
My code looks like this:
function get_exired_posts_to_delete()
{
/**
* If you need posts that expired more than a week ago, we would need to
* get the unix time stamp of the day a week ago. You can adjust the relative
* date and time formats as needed.
* #see http://php.net/manual/en/function.strtotime.php
* #see http://php.net/manual/en/datetime.formats.php
*/
// As example, we need to get posts that has expired more than 7days ago
$past = strtotime( "- 1 week" );
// Set our query arguments
$args = [
'fields' => 'ids', // Only get post ID's to improve performance
'post_type' => 'job',
'post_status' => 'publish',
'posts_per_page' => -1,
'date_query' => array(
'column' => 'post_date_gmt',
'before' => '30 days'
)
];
$q = get_posts( $args );
// Check if we have posts to delete, if not, return false
if ( !$q )
return false;
// OK, we have posts to delete, lets delete them
foreach ( $q as $id )
wp_delete_post( $id );
}
// expired_post_delete hook fires when the Cron is executed
add_action( 'expired_post_delete', 'get_exired_posts_to_delete' );
// Add function to register event to wp
add_action( 'wp', 'register_daily_post_delete_event');
function register_daily_post_delete_event() {
// Make sure this event hasn't been scheduled
if( !wp_next_scheduled( 'expired_post_delete' ) ) {
// Schedule the event
wp_schedule_event( time(), 'daily', 'expired_post_delete' );
}
}
Is there anythin wrong with the date query?
And is there a better solution to use the server cron instead the WP cron?
I found a solution for my question.
For the problem with the trash, I've changed the argument wp_delete_post() to wp_trash_post() because wp_delete_post() only applies to native posts, pages, and attachments. Great answer from #rarst here: https://wordpress.stackexchange.com/questions/281877/error-after-deleting-custom-post-type-with-a-function-no-trash-used/281888#281888
Here is my code:
function get_delete_old_jobs() {
// Set our query arguments
$args = [
'fields' => 'ids', // Only get post ID's to improve performance
'post_type' => 'job',
'post_status' => 'publish',
'posts_per_page' => -1,
'date_query' => array(
'before' => date('Y-m-d', strtotime('-30 days'))
)
];
$q = get_posts( $args );
// Check if we have posts to delete, if not, return false
if ( !$q )
return false;
// OK, we have posts to delete, lets delete them
foreach ( $q as $id )
wp_trash_post( $id );
}
// expired_post_delete hook fires when the Cron is executed
add_action( 'old_job_delete', 'get_delete_old_jobs' );
// Add function to register event to wp
add_action( 'wp', 'register_daily_jobs_delete_event');
function register_daily_jobs_delete_event() {
// Make sure this event hasn't been scheduled
if( !wp_next_scheduled( 'old_job_delete' ) ) {
// Schedule the event
wp_schedule_event( time(), 'hourly', 'old_job_delete' );
}
}