Delete posts older than 2 years in wordpress site - php

I want to delete all that posts programmatically which are older than two years on my WordPress site. there are around 37000 posts. need help to delete it in bulk. how it is possible.? what will be the easiest way to delete.?

Try with this code.. Please read my comments in the code for more understanding. Function will go into your functions.php
function get_delete_old_post() {
// WP_Query arguments
$args = array(
'fields' => 'ids', // Only get post ID's to improve performance
'post_type' => array( 'post' ), //post type if you are using default than it will be post
'posts_per_page' => '-1',//fetch all posts,
'date_query' => array(
'column' => 'post_date',
'before' => '-2 years'
)//date query for before 2 years you can set date as well here
);
// The Query
$query = new WP_Query( $args );
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
//delete post code
//wp_trash_post( get_the_ID() ); use this function if you have custom post type
wp_delete_post(get_the_ID(),true); //use this function if you are working with default posts
}
} else {
// no posts found
return false;
}
die();
// Restore original Post Data
wp_reset_postdata();
}
add_action('init','get_delete_old_post');

The direct bulk method might be to speak some raw SQL (DELETE FROM ...), but unless you have taken the time to learn WordPress internals, I would not suggest this route. Instead -- as with many tasks WordPress -- look for a plugin. Consider this search, which presents Bulk Delete as the top options.
Indeed, Bulk Delete is a plugin we have used in office for just such an occurrence.
Good luck!

Run this sql query
DELETE FROM `wp_posts` WHERE YEAR(CURDATE()) - YEAR(`post_date`) >= 2;

You might just like this plugin (which I wrote) Auto Prune Posts, it will delete posts after , say 2 years, based on taxonomy + age. https://wordpress.org/plugins/auto-prune-posts/
When you just "DELETE FROM .. " you WILL end up with orphaned data in at least the postmeta table. I think you do not want that.

Related

Function to auto-delete wordpress media after period of time

I'm writing what I thought was a simple series of functions to assign a "deletion date" to media, then auto-delete those expired media when the site is visited.
The post_meta for deletion date is set for the images via an online form when the images are uploaded (using formidable pro forms and the "after_create_entry" hook. I can confirm that the meta field is created successfully, and the deletion date is assigned properly (called 'mtp_deletiondate'. To test, I did a wp_query on a custom page and each image has a properly set deletion date.
Next, I wanted to run a function that checked for expired images (set to be 21 days after date of upload), and if they are expired, to delete them. I want to trigger this function whenever I access the admin, because I figure I get in there at least once a month to run updates, and it's a good time to clean out the old images. For this situation, I decided not to do a cron job since I can reliably visit the site once a month anyway.
The issue is the function doesn't seem to be triggering, and I don't know if it's because the function is broken or because I'm using the wrong action, or both. Some research tells me to use the admin_init, but I've also tried "wp", and "wp-footer". It might be that I'm just misunderstanding the process. My function (in my theme's functions.php):
function drick_delete_expired_uploads() {
// WP_Query arguments
$args = array (
'post_status' => 'any',
'post_type' => array( 'Attachment' ),
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'mtp_deletiondate',
),
),
);
// The Query
$mediaquery = new WP_Query( $args );
// The Loop
if ( $mediaquery->have_posts() ) {
while ( $mediaquery->have_posts() ) {
$mediaquery->the_post();
date_default_timezone_set('America/Denver');
$CurrentDate = date('Y-m-d h:i');
$CurrentDateStr = strtotime($CurrentDate);
$DeletionDate = get_post_meta( $post->ID, 'mtp_deletiondate', true );
$DeletionDateStr = strtotime($DeletionDate);
if ( isset($DeletionDateStr) ) {
if ( $DeletionDateStr < $CurrentDateStr ) {
wp_delete_attachment( $post->ID, true );
}
}
}
} else {
// no posts found
} // IF HAVE POSTS
// Restore original Post Data
wp_reset_postdata();
}
add_action('admin_init', 'drick_delete_expired_uploads');
If I save my functions.php, then reload the Wordpress dashboard, then check my media, the expired images are still there. HOWEVER, if I add this function to an actual page then visit the page, it does work. So I believe the function is doing what it's supposed to, it's just not getting triggered properly? I also added a quick wp_mail() to the function in my functions.php, and when I visited the admin it did trigger the email, so I guess the function is firing.
I would appreciate any insight, thank you!
So I think I figured it out, but I don't know that I have an explanation as to why it works. Essentially it looks like wp_delete_attachment wasn't working, but wp_delete_post DOES work. I've tested and confirmed with three additional images that the function auto delete is triggered when accessing the admin dashboard. I also changed the way the query arguments are structured by only querying the expired images, rather than querying ALL images that have a mtp_deletiondate meta then running a conditional statement within the query. Don't know if that's related or not. The final working function:
function drick_delete_expired_uploads() {
// WP_Query arguments
date_default_timezone_set('America/Denver');
$CurrentDate = date('Y-m-d h:i');
$args = array (
'post_status' => 'any',
'post_type' => array( 'Attachment' ),
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'mtp_deletiondate',
'value' => $CurrentDate,
'compare' => '<',
'type' => 'DATE',
),
),
);
// The Query
$mediaquery = new WP_Query( $args );
// The Loop
if ( $mediaquery->have_posts() ) {
while ( $mediaquery->have_posts() ) {
$mediaquery->the_post();
wp_delete_post(get_the_ID());
}
} else {
// no posts found
} // IF HAVE POSTS
// Restore original Post Data
wp_reset_postdata();
}
add_action('admin_init', 'drick_delete_expired_uploads');
Still look forward to any feedback from someone in the know that can tell me why the previous version wasn't working (looking to learn here). Thanks!

Wordpress: Different post from custom post type everyday

I have a custom post type to display a single quote. Right now I have it set to random, but is it possible to have a WordPress loop that displays a random post but only changes once per day? So basically having a quote of the day post type. I see plugins for a quote of the day but these all pull from an external feed.
Found a post scheduling plugin that let me recycle my quotes posts so that they can be randomized daily:
Auto Post Scheduler
Basically, I set the post schedule to 24 hours, set the post type to my custom post type, changed the eligible posts to published, checked randomize, and set the minimum age to 48 hours which I think should prevent the same post from being used two days in a row.
You can create your own. The only thing you need is a plugin that displays posts (like this one), then to make a formula to pick a random post each day and you can set this script to run once per day (usually those type of automations are triggered from visitors).
Useful links:
Function: get_posts
Function: wp_cron
Try to use following code:-
if ( false === ( $quotes = get_transient( 'random_quote' ) ) ) {
// It wasn't there, so regenerate the data and save the transient
$args = array(
'post_type' => 'School',
'orderby' => 'rand',
'limit' => 1,
'posts_per_page' => '1');
$quotes = get_posts( $args );
set_transient( 'random_quote', $quotes, DAY_IN_SECONDS);
foreach ( $quotes as $post ) {
setup_postdata( $post );
<h1><?php the_title(); ?></h1>
<?php
echo $post->post_content;
?>
<?php
}
wp_reset_postdata();
?>

WP-Query : check if the post content is empty

I'm trying to check if my post has content, in the loop. Currently, i added a condition in the loop :
if ( $post->post_content )
and putted argument in the
wp query ('posts_per_page' => 8).
I thought it worked, but actually, WP query go find last 8 posts, and check the content of those 8 lasts. So it renders 2 or 3 posts.
The thing I want is a way to show last 8 posts that has content.
See what I mean ?
I really appreciate some help :)
Best regards.
This isn't possible with a standard WP query, and you'll have to leverage the use of posts_where before the WP_Query is called.
function filter_where($where = ''){
return $where .= "AND trim(coalesce(post_content, '')) <>''";
}
In the above, we're simply only selecting posts where the column post_content isn't empty.
Then add the filter.
add_filter('posts_where', 'filter_where');
Now perform the query.
$query = new WP_Query(array('post_type' => 'post', 'posts_per_page' => 8));
And then when you're done, remove the filter from the query so it doesn't interfere.
remove_filter('posts_where', 'filter_where');

Query all wordpress post titles

I am using Wordpress auto suggests using this snippet of code
and currently it is searching all tags, I want it to search only post titles. Any help is appreciated.
This is sql query calling all the tags which needs to be modified for all posts.
<?php global $wpdb;
$search_tags = $wpdb->get_results("SELECT name from wp_terms WHERE name LIKE '$search%'");
foreach ($search_tags as $mytag)
{
echo $mytag->name. " ";
}
?>
These days i had to do some request in a wordpress theme.
In your case ( getting title can be done easier than getting tags, as in your example link ) the stuff can be done easier (i guess).
Firstly you have to make a php page to get posts. As you maybe know you won't be able to use wp stuff in standalone php files, so your file ( let call it get_posts.php ) will look like
<?php
// Include the file above for being able to use php stuff
// In my case this file was in a folder inside my theme ( my_theme/custom_stuff/get_posts.php ).
// According to this file position you can modify below path to achieve wp-blog-header.php from wp root folder
include( '../../../../wp-blog-header.php' );
// Get all published posts.
$list_posts = get_posts( array( 'numberposts' => -1 ) );
// Get "q" parameter from plugin
$typing = strtolower( $_GET["q"] );
//Save all titles
$list_titles = array();
foreach( $list_posts as $post ) { $list_titles[] = $post->post_title; }
// To see more about this part check search.php from example
foreach( $list_titles as $title ) {
if( strpos( strtolower( $title ), $typing ) ){
echo $title;
}
}
?>
I added some comments trying to help you better.
Now stuff get easy, you only have to call your page through jQuery plugin like
$('#yourInput').autocomplete( "path_to/get_posts.php" );
You can directly use wordpress in-build feature to get all post titles
// The Query
query_posts( 'posts_per_page=-1' );
// The Loop
while ( have_posts() ) : the_post();
echo '<li>';
the_title();
echo '</li>';
endwhile;
None of the answers here answer your real question:
How to query JUST post titles
The "raw SQL" way:
Few important things:
escape search for SQL! (also do that for the tags search!) use $GLOBALS['wpdb']->esc_like()
if you only need 1 column, you can use $GLOBALS['wpdb']->get_col()$GLOBALS['wpdb']->get_results() is if you want to fetch more columns in one row
use $GLOBALS['wpdb']->tableBaseName to make your code portable - takes care of the prefixe.g. $GLOBALS['wpdb']->posts
When querying posts you must also think about which post_type and post_status you want to query=> usually the post_status you want ispublish, but post_type may vary based on what you want
WordPress table "posts" contains ALL post types - post, page, custom, but also navigation, contact forms etc. could be there! => I strongly advice to use explicit post_type condition(s) in WHERE ! :)
...$GLOBALS is same as globalizing variabl -today performance difference is little
<?php
// to get ALL published post titles of ALL post types (posts, pages, custom post types, ...
$search_post_titles = $GLOBALS['wpdb']->get_col(
"SELECT post_title from {$GLOBALS['wpdb']->posts}
WHERE (
(post_status = 'publish')
AND
(post_title LIKE '{$GLOBALS['wpdb']->esc_like($search)}%')
)
ORDER BY post_title ASC
"); // I also added ordering by title (ascending)
// to only get post titles of Posts(Blog)
// you would add this to conditions inside the WHERE()
// AND (post_type = 'post')
// for Posts&Pages
// AND ((post_type = 'post') OR (post_type = 'page'))
// test output:
foreach ($search_post_titles as $my_title) {
echo $my_title . " ";
}
?>
The WP_Query way
This is more wordpress but has a little overhead, because although there is a fields param for new WP_Query()/get_posts(), it only has options:
'all' - all fields (also default), 'ids' - just ids, 'id=>parent' - ... if you pass anything else, you still get all, so you still need to add "all" BUT - WP however has filters for altering fields in SELECT.
I tried to make it the same as the raw SQL version, but it depends on how does WP does it's "search" - which I think is %search% for 1 word + some more logic if there are more words. You could leverage the $clauses filter used for fields to also add your custom where INSTEAD of adding the 's' into $args (remember to append to not-lose existing WHEREs $clauses['where' .= "AND ...;). Also post_type => 'any' does not produce always the same results as the raw query in cases like Navigation, Contact forms etc...
Also WP_Query sanitizes the input variables so actually don't escape $args!
<?php
$args = [
'fields' => 'all', // must give all here and filter SELECT(fields) clause later!
'posts_per_page' => -1, // -1 == get all
'post_status' => 'publish',
's' => $search,
// I also added ordering by title (ascending):
'orderby' => 'title',
'order' => 'ASC',
'post_type' => 'any', // all "normal" post types
// 'post_type' => 'post', // only "blog" Posts
// 'post_type' => ['post', 'page'], // only blog Posts & Pages
];
$onlyTitlesFilter = function($clauses, $query) {
// "fields" overrides the column list after "SELECT" in query
$clauses['fields'] = "{$GLOBALS['wpdb']->posts}.post_title";
return $clauses; // !FILTER! MUST RETURN!
};
$onlyTitlesFilterPriority = 999;
// add filter only for this query
add_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority, 2);
// Pro-tip: don't use variable names like $post, $posts - they conflict with WP globals!
$my_posts = (new WP_Query($args))->get_posts();
// !IMPORTANT!
// !remove the filter right after so we don't affect other queries!
remove_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority);
// test output:
// note that I used "my"_post NOT just $post (that's a global!)
foreach($my_posts as $my_post) {
echo $my_post->post_title . " ";
}
?>
Don't be confused - you will still get the array of WP_Posts - WP will throw some default properties&values into it, but in reality it will only query and fill-in with real values the fields you specify in the filter.
PS: I've tested these - they are working codes (at least on WP 5.4 and PHP7 :) )

Ordering Wordpress posts based on parent category

UPDATE: I have tried using the following code:
<?php if (is_category(events)) {
$posts = query_posts($query_string . '&orderby=event_date&order=desc');
} else {
$posts = query_posts($query_string . '&orderby=title&order=asc');
}
?>
Is there any reason why that wouldnt work? It seems to work fine organising posts in alphabetical order, but still no luck on the date order within 'events'.
--
After searching through various existing questions I can't quite find a solution to what I am trying to do.
Currently all posts on my site are ordered alphabetically, which is fine except for one new category that I have added. For this category I want to order all posts by a value that I enter into a custom field. The field is called 'event_date' - so I want to order the posts by date essentially, but not the date the post was created, the date the user manually enters into this field.
I managed to get it working by using:
<?php if (is_category($events)) { $posts = query_posts($query_string . '&orderby=$event_date&order=asc'); } ?>
However this overrides the aphabetical order for all other pages.
For alphabetical order I am using:
<?php if (is_category()) { $posts = query_posts( $query_string . '&orderby=title&order=asc' ); } ?>
Essentially I want a statement that tells the page to order all posts in aphabetical order, unless the category is 'events', where I want to order them by the custom event date.
As you can probably tell I'm very much front end, not back end so a lot of this is fairly new to me, so any help or advice is appreciated.
To order posts by a custom field value, you need add the custom meta field to the query itself. orderby=meta_value in addition to meta_key=metafieldid will allow ordering in this fashion.
I would use the pre_get_posts hook and modify the query object if get_query_var( "cat" ) (or a similar query var) returns the desired post category.
add_action( "pre_get_posts", "custom_event_post_order" );
function custom_event_post_order( $query )
{
$queried_category = $query -> get_query_var( "cat" );
/*
* If the query in question is the template's main query and
* the category ID matches. You can remove the "is_main_query()"
* check if you need to have every single query overridden on
* a page (e.g. secondary queries, internal queries, etc.).
*/
if ( $query -> is_main_query() && $queried_category == 123 )
{
$query -> set( "meta_key", "event_date" ); // Your custom field ID.
$query -> set( "orderby", "meta_value" ); // Or "meta_value_num".
$query -> set( "order", "ASC" ); // Or "DESC".
}
}
Remember that this approach overrides all queries that are using the category in question. You can build custom WP_Query objects that use their own parameters for constructing loops.
You also should standardize the way you save the custom field data to the database. For dates I prefer using UNIX-timestamp formatted times that are easy to move around and manipulate. This way no accidents happen when querying and some data is formatted in another way that the rest is.
Disclaimer: I did not have the time to test the above code in action, but the general idea should work properly.
EDIT: of course the above code should be inserted to functions.php or a similar generic functions file.
What about:
<?php $posts = query_posts($query_string . (is_category($events)?'&orderby='.$event_date:'&orderby=title') . '&order=asc'); ?>
<?php
$recent = new WP_Query(“cat=ID&showposts=x”);
while($recent->have_posts()) : $recent->the_post();
?>
Hopefully I understood your question, use the WP_Query and within the orderby add a space between your order by columns:
$args = array(
'posts_per_page' => 100,
'orderby' => 'title',
'order' => 'ASC',
);
if(is_category($events)){
$args['orderby'] .= " meta_value_num";
$args['meta_key'] = 'event_date';
}
$posts = (array) new WP_Query( $args );

Categories