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!
Related
The problem
I'm making a plugin. I have a function which goal is to loop throught every post of a given post_type, and store a given metafield value in a different table, along with the ID of the post and the date of the day. To give you some context, it's to keep tracks of products prices.
The function works perfectly when called "manually" with the admin_menu hook, I got my table populated with all the data.
Now I want this function to run once every day so I set up a CRON JOB with wp_schedule_events. WP controls shows the schedule CRON JOB, but the callback function is never executed, and there's no errors, no log whatsoever :/
The Code
The way I scheduled the CRON JOB
function schedule_price_curve_update( $args ) {
if ( ! wp_next_scheduled( 'update_product_price_curve') ) {
$time=time();
$time=$time+60;
wp_schedule_event($time, 'daily', 'update_product_price_curve', $args );
}
}
My callback function to insert data to the dedicated table, and the hook for the CRON Job.
function bulk_update_product_price_curve( $setup_table_name) {
$args = array(
'post_type' => 'bons-plans',
'posts_per_page' => -1,
'post_status' => 'publish',
);
$posts_array = get_posts( $args );
global $wpdb;
$table_name = $wpdb->prefix . $setup_table_name;
$date = date('Y/d/m');
foreach( $posts_array as $post_array ){
$price = get_post_meta( $post_array->ID, 'prix-promo', true);
$wpdb->insert($table_name, array('product_id' => $post_array->ID, 'date' => $date, 'product_price' => $price));;
}
}
add_action( 'update_product_price_curve', 'bulk_update_product_price_curve' );
The $table_name will be setup by user in the admin setting page of the plugin. As of now I set the $arg of the schedule_price_curve_update( $args ) manually. No probleme on this part. Again, WP Control assure me the job is scheduled with the right arguments.
If anyone have any idea of why my callback function is not firing ? That's kind of frustrating as there's no error or nothing to give me any hint on why this isn't working... So there's also that : how can I debug this ?
I have made my first plugin and it all works on the front end but I am having some weird backend conflict with the gutenberg. I have done two things, made my plugin automatically add the pages / overwrite them when they've checked off, and made the plugin shortcode.
Here is the problem on my gutenberg:
As you can see there are random red diamonds on the page. When I use the inspector I can see it has code from my plugin I created...
Here is how I created my plugin
First inside my functions page I registered a new short code.
add_shortcode('parts_listing_portal', 'portal_parts_list');
function portal_parts_list(){
include "shortcodes/parts_listing_shortcode.php";
return ;
}
Then I made content for inside the shortcode using JS, PHP, and HTML.(this is a big file with includes and API calls)
After the page looked the way I would like, I created a new function to work on my option submit. This function creates the page with the shortcode inside.
//Add parts
if ( get_option( 'parts' ) === "checked") {
$parts_list = array(
'post_title' => 'Parts',
'post_type' => 'page',
'post_name' => 'Parts',
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => '[parts_listing_portal]',
'post_status' => 'publish',
'post_author' => get_user_by( 'id', 1 )->user_id,
'menu_order' => 0
);
// PARTS LIST
if(get_page_by_title('Parts') == null) {
wp_insert_post($parts_list);
}else{
$post_exists = get_page_by_title("Parts" );
$update_post = array('ID' => $post_exists->ID);
$post_update = wp_parse_args($parts_list, $update_post);
wp_update_post($post_update);
}
When my function adds to the page & you go to the gutenberg editor it shows the full page for a split second then goes away. I feel I missed a statement somewhere to only show on "page" but I have no idea where to look. I've spent a lot of time researching it but couldn't find it.
Thank you
Whenever adding a shortcode make sure to check iif in admin area. If in admin area return nothing
function portal_parts_list(){
if ( is_admin()){
return;
}else {
include "shortcodes/parts_listing_shortcode.php";
return ;
}
}
add_shortcode('part_description_portal', 'portal_parts_list');
I think I'm either misinterpreting the WP Codex's definition of the wp_safe_redirect() function, or I'm being a womble and not using it correctly. (I didn't even know WP had a function like this, but hey learning every day right?)
So some scenario, I have a new instance of WP_Query that loops through a specific post type then pulls a single result based upon a ACF field meta_key. I simply want to redirect the user to the first and only found result.
Here's my attempt;
$args = array(
'post_type' => array( 'locale' ),
'post_status' => array( 'published' ),
'nopaging' => true,
'posts_per_page' => '1',
'meta_key' => 'postal_town',
'meta_value' => $postal_town_result
);
$postcodeSearch = new WP_Query( $args );
if($postcodeSearch->have_posts()) :
while($postcodeSearch->have_posts()) : $postcodeSearch->the_post();
$perma_url = the_permalink();
wp_safe_redirect( $perma_url ); // just prints the url?
exit;
endwhile;
else:
echo 'Oops, there are no posts.'
endif;
Any advice would be greatly appreciated.
From WordPress the_permalink:
the_permalink Displays the permalink for the current post.
So that actually displays it, and after output the header redirect fails as headers have already been sent.
You want get_permalink that returns the permalink instead of displaying it:
$perma_url = get_permalink();
wp_safe_redirect( $perma_url );
exit;
Also, with the following, or whatever WordPress's equivalent setting is would show you:
error_reporting(E_ALL);
ini_set('display_errors', '1');
function when_a_review_gets_submitted ($review, $post_id) {
// Do something
}
add_action('rwp_after_saving_review', 'when_a_review_gets_submitted', 11, 2);
I have this WP_Query and loop to update a custom field of every childpage of the parentpage were somebody has left a review.
// Set up the objects needed
$hosting_provider_query = new WP_Query();
global $post;
$hosting_pagina_titel = $post->post_title;
$search_all_pages = $hosting_provider_query->query(array(
'post_type' => 'page',
'post_status' => 'publish',
//Only get pages where custom field 'name_hosting_provider' equals Page title
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'naam_hosting_provivder',
'value' => $hosting_pagina_titel,
'compare' => '='
),
),
));
// Loop through all pages and find Page's children
$loop_through_all_child_pages = get_page_children( get_the_ID(), $search_all_pages );
// Loop through everything we got back
if(!empty($loop_through_all_child_pages)){
foreach($loop_through_all_child_pages as $child_page){
// get the ID of each childpage
$get_child_page_ID = $child_page->ID;
// get the ID of each parent page of the child pages
$get_parent_page_ID = get_queried_object_id();
// Get the average score from post_meta of the parent page
$get_average_score = get_post_meta( $get_parent_page_ID, 'rwp_user_score', true );
// update each custom field of the childs with the average score data from the post meta of parent page
update_field('gemiddelde_score_hosting_provider', $get_average_score, $get_child_page_ID);
}
}
How can I correctly execute this code within the above function?
EDIT
Ok I figured this out, the function is working properly when I remove the parameters $review and $post_id. And when I remove the add action:
add_action('rwp_after_saving_review', 'when_a_review_gets_submitted', 11, 2);
and replace it with:
add_action( 'template_redirect', 'when_a_review_gets_submitted' );
but I think this is a bit overkill for what I am trying to achieve. If I understand template_redirect it executes the function everytime a page is visited with that template? Am I correct?
So when I have 900 child pages it updates every custom field "gemiddelde_score_hosting_provider" when a page with that template is visited? So 900 times every single time a page with that template is visited? Am I correct in this one?
Is there a way to only update the custom field of the childs from the parent page where the review is submitted?
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.