I have a wp_cron which I run every hour.
The cron calls a function which iterates through a custom post type. The title and some meta data is then used to scrape results from a remote server.
The problem is that the scraping takes a long because of the number of posts. I want to split the scraping into chunks by only iterating through 25 posts at a time. This is easy using the offset parameter in query_posts, but how do I dynamically add_action() and pass the offset variable?
In functions.php
if ( ! wp_next_scheduled( 'my_task_hook' ) ) {
wp_schedule_event( time(), 'hourly', 'my_task_hook' );
}
add_action( 'my_task_hook', 'rock_n_roll' );
My scraper.php looks something like this
function rock_n_roll($offset) {
query_posts(array(
'post_type' => 'wine',
'order' => 'ASC',
'posts_per_page' => -1,
'offset' => $offset
));
while (have_posts()) : the_post();
//compare values against scraped results
//write results to DB with update_post_meta
endwhile;
}
Basically I need a way to dynamically add_action(), incrementing the value of $offset by 25 each time.
You can pass a variable to your add_action():
add_action( $tag, $function_to_add, $arg );
But you can also use do_action() instead of adding action every time your cron runs:
do_action( $tag, $arg )
Anyway, is good to store your $offset somewhere, so I see two options:
Store your persistent values in WP_Object_Cache. Maybe reading this documentation, you can find another elegant solution for your performance with large query results.
Recording in the database your actual $offset value using add_option() and get_option().
If you store your $offset variable, your rock_and_roll function don't need to receive a parameter anymore, you just need to retrieve it inside the function.
function rock_n_roll() {
// Retrieve $offset value from WP_Object_Cache
// or from database with get_option()
query_posts(array(
'post_type' => 'wine',
'order' => 'ASC',
'posts_per_page' => -1,
'offset' => $offset
));
while (have_posts()) : the_post();
//compare values against scraped results
//write results to DB with update_post_meta
endwhile;
}
Your $Offset is passed to the function from another source.. So I could imagine, something like:
$Var = $Pre_definedoffset;
$Var = $Pre_definedoffset + 25;
rock_n_roll($var);
This is just assumptions from what I can see from your code.
You will need to modify the variable containing the integer which is passed through to your function, before the code pushes it through the function.
Related
I have the WordPress site below that displays a map of medical providers and a list below that of those same providers.
https://preview.scmamit.yourmark.com/?sfid=756&_sft_provider_type=primary-care
I need to show all of the results of a search on the map, but then the list should have pagination (only displaying 25 per page). I'm running through the loop twice, 1st to build the pins for the map, and 2nd to display the list.
If I turn off pagination to show all the pins on the map, how then would I display the list with pagination below the map?
Back in my Coldfusion days, I would have done a query of queries for the 2nd loop, and I've seen "pre_get_posts" and some other options that seem close to what I want, but nothing is quite getting me there.
Just run the loop a 2nd time:
First reset the 1st query at the end of it:
wp_reset_query();
And add this to your second query:
$count = get_option('posts_per_page', 10);
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$offset = ($paged - 1) * $count;
And add this args to the query:
'posts_per_page' => $count,
'paged' => $paged,
'offset' => $offset,
Regards Tom
Thought I would post what I did to get this work. Thanks to #tom-ukelove for getting me headed in the right direction.
I had the map, list and search filter on this page. The search filter is created with Search & Filter plugin.
https://scmamit.com/?sfid=756
In my Search & Filter settings, I set the results per page to 25, which is what I needed the list to do in loop #2.
To display all of the results on the map (loop #1), I used the following code to remove the 25 posts_per_page limit.
<?php
//get the search variables from URL
$this_keyword = $_GET['_sf_s'];
$this_provider_type = $_GET['_sft_provider_type'];
$this_city = $_GET['_sfm_city'];
//rebuild the query
$args = array(
'post_type' => 'providers',
'provider_type' => $this_provider_type,
's' => $this_keyword,
'meta_query' => array(
array(
'key' => 'city',
'value' => $this_city,
'compare' => 'LIKE'
)
),
//use -1 to remove the 25 results per page limit
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC'
);
$the_query = new WP_Query( $args );
global $wp_query;
// Put 25 limit query object in a temp variable
$tmp_query = $wp_query;
// Now purge the global query
$wp_query = null;
// Re-populate the global with the no-limit custom query
$wp_query = $the_query;
$count = $the_query->post_count;
//run the loop #1 and build map pins within.
while($the_query->have_posts()) : $the_query->the_post();
//echo out map pin code here, or whatever you need in the 1st loop.
endif;
endwhile;
//reset the query
wp_reset_query();
// Restore original 25 limit query object
$wp_query = null;
$wp_query = $tmp_query;
?>
<ul>
<?php
// run the 2nd loop with pagination
while(have_posts()) : the_post();
// some <ul> list here
endwhile;
?>
</ul>
<?php
//display pagination
$numeric_posts_nav();
?>
Hope that helps someone in the future. Lmk if there's a more efficient way to do it.
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!
I am trying to load a post by ID using query_posts, however it always returns an empty array. I get a post Id at random using SQL as follows;
$randomProdSql = "SELECT ID FROM `posts` WHERE post_status = 'publish' ORDER BY RAND() LIMIT 0,1";
I then load that into a variable using;
$randomPost = $wpdb->get_var($randomProdSql);
This works fine and if I print it out I get an Id. I then call query_posts like this;
$args = array(
'p' => $randomPost
);
$posts = query_posts($args);
I would now expect the $posts variable to contain the post.. however, if I call;
print_r($args);
print_r($posts);
I get:
Array
(
[p] => 778
)
Array
(
)
Can anyone see what I am doing wrong?
Update your code as below:
query_posts('p='.'"$randomPost"');
Also, rather using the query_posts() method to get a single post, you can use get_post() method.
$my_post = get_post($randomPost);
echo $my_post->post_title;
As per your code, you shared you want post id's in random manner. The following code will get the post id's for you in random manner.
By using post_per_page you can control the number of posts returned in result. Also, fields will force the query to return id's of posts. However, in case you want to retrieve any other field also please remove it from here. As, it only supports id field only.
For details please refer to this link:
<?php
$args = array(
'post_status' => 'publish',
'orderby' => 'rand',
'fields' => 'ids',
'posts_per_page' => '1'
);
$posts = query_posts($args);
?>
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();
?>
I'm using this code to show recent posts with a shortcode that I found at smashingmagazine site. It's not working the correct way, I mean when I specify the number of posts to show, it just shows one post with every number I specify.
Here's the code:
function recent_posts_function() {
query_posts(array('orderby' => 'date', 'order' => 'DESC' , 'showposts' => 1));
if (have_posts()) :
while (have_posts()) : the_post();
$return_string = ''.get_the_title().'';
endwhile;
endif;
wp_reset_query();
return $return_string;
}
function register_shortcodes(){
add_shortcode('recent-posts', 'recent_posts_function');
}
add_action( 'init', 'register_shortcodes');
I've changed the showposts number, but nothing happens. What's wrong?
Any suggestions?
Just before I start, never use query_posts to construct or modify any type of query. It outright fails in many scenarios, specially pagination, and breaks the main query, which you should never do.
If you need to construct custom queries, rather use WP_Query
Also, showposts have been deprerciated long time ago and have been replaced with posts_per_page
You should read the Shortcode API, this should give you an overview of what is happening and how shortcodes should be used and created. One important thing to remember here, shortcode content should be returned, not echo'ed. Here is also a tutorial that help me a lot.
Just a quick tip here, shortcodes should always go into a plugin. If you haven't yet created one, go and read MU-Plugin (must-use-plugin)
The correct way of constructing your shortcode would be as follows: (Your shortcode will be [my-shortcode]) This is untested though
add_shortcode( 'my-shortcode', 'my_custom_query_shortcode' );
function my_custom_query_shortcode( $atts ) {
ob_start();
$query = new WP_Query(array('orderby' => 'date', 'order' => 'DESC' , 'posts_per_page' => 1));
if ( $query->have_posts() ) :
while($query->have_posts()) : $query->the_post();
//YOUR LOOP ELEMENTS
<?php
endwhile;
$myvariable = ob_get_clean();
return $myvariable;
endif;
}
Just replace your code with mine, and make sure that you add your loop elements.
Just one more thing, remember, if you run any custom query on a page, and you have not reset that query, it will influence any other query on that page, even this shortcode, so always make sure that you reset all custom queries once you've done