I have a wordpress website that allows a user to set up a reminder for a certain day, it stores it in a database where it can either be displayed when the user logs in, or send out an email to them.
I followed the example code given in http://codex.wordpress.org/Function_Reference/wp_cron and have placed the code below into the main .php file of a plugin I have written which functions perfectly in all other ways.
if ( ! wp_next_scheduled( 'checkReminderEmails' ) ) {
wp_schedule_event( 1411693200, 'daily', 'checkReminderEmails' );
} //1411693200 is the unix timestamp for 1am a couple of days ago
add_action( 'checkReminderEmails', 'sendReminderEmails' );
function sendReminderEmails()
{
$table_name = $wpdb->prefix."reminders";
$query = "SELECT * FROM $table_name WHERE sendReminder = 1 and reminderDate = CURRENT_DATE( )";
$appointments = $wpdb->get_results( $query);
foreach ( $appointments as $info )
{
$message = "Hello here is your reminder.";
$toAddress = $info->userEmail;
$subject = "This is your reminder.";
wp_mail( $toAddress, $subject, $message);
}
} // end sendReminderEmails()
I have checked the wp_options table in my PHP database and can see the following code there
{s:18:"sendReminderEmails";a:1:{s:32:"40cd750bba9870f18aada2478b24840a";a:3:{s:8:"schedule";s:5:"daily";s:4:"args";a:0:{}s:8:"interval";i:86400;}}}i:1411693200;a:1:
I can receive other emails from the website using wp_mail() so I know that the functionality is supported by the server, and I know that the wp_cron jobs aren't fired until the website is visited after the time has passed, but I have been unable to get this cron job to fire correctly. Am I missing something obvious?
Edit: For anybody wondering, I used the wp-cron-dashboard plugin (https://wordpress.org/plugins/wp-cron-dashboard/) despite the warning that it hasn't been updated in 2+ years to check that my cron job was scheduled properly.
I also had to add global $wpdb; to the top of my function, the reason it was failing to fire was because without declaring that I was unable to use the get_results() function.
I also discovered that if you go to wp-cron.php you will manually force any scheduled cron jobs to be fired, and all output will display there, so it is possible to debug a cron job by adding echo statements and going to that page.
I know this is old but one thing I see right away is you need global $wpdb; as the first line of the sendReminderEmails() function, otherwise it's going to bomb.
I often quickly test cron functions in my front-page.php by adding something like sendReminderEmails(); exit; to the top, just as a sanity check that the function works at all.
Related
Trying to add a cron job on Cpanel to run every 5 minutes. I added this to the command input (removed personal details from the url)
/usr/bin/php -q /home/my_name/public_html/staging/the_web_site/wp-content/themes/my_child_theme/functions.php updateproducts
Then on the functions.php, I have this:
if (!empty($argv[1])) {
switch ($argv[1]) {
case "updateproducts":
update_products();
break;
}
}
The update_products() function runs without any error manually if I trigger it with a button on admin page. But, no matter what I do on the cronjob tab, it doesn't run.
Any idea?
function update_products() {
global $wpdb;
$groups = get_groups_from_cron_jobs(100);
foreach ( $groups as $group ) {
$name = $group->group_name;
$sql = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}products WHERE name='%s'", $name);
$products = $wpdb->get_results($sql);
if ( !empty($products) ){
$post_id = get_post_id_from_products($products);
//if there isn't a parent_id then create a new product
if ( !$post_id && $name != '' ) {
$post_id = create_a_new_product($name);
}
// make sure that all products will have now a parent_id
add_parent_id_on_products($name, $post_id);
insert_product_attributes($post_id, $products);
insert_product_variations($post_id, $products);
delete_group_from_cron_jobs($name);
}
}
}
Edit: Based on the answers/comments, I made extra research and found that I can load the $wpdb on any script. What I did is this:
if (!empty($argv[1])) {
switch ($argv[1]) {
case "updateproducts":
$path = $_SERVER['DOCUMENT_ROOT'];
require( $path . '/staging/the_web_site/wp-load.php' );
update_products();
break;
}
}
However, I still get the error on email:
Status: 500 Internal Server Error
X-Powered-By: PHP/5.6.31
Content-type: text/html; charset=UTF-8
I'm afraid there's some misunderstanding about how inter-operable the web environment and console environment are here.
In short, your function expects WordPress to exist. It expects that the user has accessed the function through the WordPress application, and that global variables such as $wpdb exist (among other things). If you access this function via the admin page, then this is all true, and the function works.
But if you access this function via the console (command line), none of this is true. WordPress does not exist within the context of that request. global $wpdb does not exist, because the function has not been accessed through WordPress, but through a direct command.
If you want this function to work on the command line, you will need to rewrite it to work within that environment. Which means no WordPress-specific helpers or functionalities at all.
Alternatively, you can use WordPress Crons, which are not true Cron jobs, but instead run whenever the site is accessed (within their defined time range). So if you have a cron that must run every five minutes, but you will not reliably have a new visitor every few minutes, these will not suit your needs, but they are an option.
http://www.wpbeginner.com/plugins/how-to-view-and-control-wordpress-cron-jobs/
For a wordpress site I have to implement a reminder that will be send 30 days after the creation of a post in wordpress.
For example:
Author creates a post, 30 days after the creation of this post the author will get a mail on the email-address which he/she filled in at the admin profile dashboard.
The mail needs to contain a url to the original post.
Are there any available plugins that could help me or should I write a custom function ?
Thanks in advance.
The problem you're going to run into is that PHP runs when a user makes a request. So, if no one visits the site on the right day or at the right time, the code you want may not run. And even if they do, do you want to slow down a random users request for this functionality.
It's best if you look into a Scheduled Task (windows) or Cron Job (linux). These utilities can be used to run PHP scripts at specific times or with specific intervals (every hour, every day at midnight, etc.). Then you create a PHP script that does the work of finding the specific posts and sending emails.
If your hosting provider doesn't allow access to a scheduling utility. You could setup your own computer, or another computer with a scheduled task to call a specific PHP file that does this work.
You need Blog Update Reminder.
I have modified this plugin to suit my needs. I´m sure you will like it ;-)
http://wordpress.org/extend/plugins/blog-update-reminder/
For a temporary solution I did the following:
I downloaded the plugin 'crony cronjob manager'
This plugin let's you run custom php at a specific time-interval.
My custom php looks like this:
<?php
$query = "SELECT * FROM wp_posts
WHERE post_type = 'catalogus'
AND post_date BETWEEN '" . date('Y-m-d', strtotime('-30 days')) . "'
AND '" . date('Y-m-d', strtotime('-29 days')) . "'";
$allposts = $wpdb->get_results($query);
if($allposts){
foreach ($allposts as $post) {
// get post name for url
echo "http://xxxxxx.xxx/product/".$post->post_name;
// get author email to send mail to.
$to = get_the_author_meta('email',$post->post_author);
$subject = "XXXXXXXXXXX";
$headers = "From: XXXXX <noreply#XXXXXXX.nl>";
$message = "Dummy message";
wp_mail( $to, $subject, $message, $headers, $attachments );
}
}
else{
echo "No posts";
}
?>
This is still no perfect solution, because like Chris mentioned above, this cronjob will only run if a visitor makes a request, my next step is to write a real cron job or scheduled task that will execute the code above.
First Part:
I am trying to write a script to email us when a service call is not paid.
Heres' what I have got started:
$query = "SELECT * FROM service";
$result = mysql_query($query);
while($row = mysql_fetch_row($result)){
$id = $row[0];
$dateEntered = $row[1];
$type = $row[2];
$account = $row[3];
$dateCompleted = $row[4];
$notes = $row[5];
$status = $row[6];
foreach($status == 'Unpaid'){
mailBadAction($id, $account, $status);
}
}
I am not sure if I wrote the foreach right (probably didn't, and I'm not in environment where I can just try it because its hooked into everything else.)
But basically, it will load all of the service calls in my while statement. I want to check each records $status, and check if it is 'Unpaid', and if so, run the function mailBadAction() and pass the $id, $account, $status, $dateEntered to the function. I only want this to happen ONCE a day.
Second Part:
I need this to run everyday at a certain time, once a day. I have zero understanding of cron jobs so I think that is out unless someone wants to help me out with that. But what I have learned is if I just include this page on the index or login page, it will run when someone simply hits the login page. But this will run it for every single time someone hits the index page.
Can someone help out?
As you are already in a loop, going though the results, so you don't need a foreach, you just need if:
if($status == 'Unpaid'){
mailBadAction($id, $account, $status);
}
And if you are on a linux environment, you need cron to run something once a day.
The easiest thing to do (if your system has it...), is add the php script to /etc/cron.daily and make it executable. Your script would look something like (depending on the environment...):
#!/usr/local/bin/php
<?php
// your script
?>
And you really should test it...
Jeroen's answer is correct, you need an if statement.
You could get around setting up a cron job by adding a database check to make sure it's been at least 24 hours since it last sent out emails, and updating that timestamp. But that's honestly more trouble than it's worth. It would block and slow down immensely as it processed data and sent emails, and some poor sap would be sitting there wondering why the page is taking forever. Learning how to setup a cron job would be much more valuable.
I think you got the foreach syntax wrong:
foreach ($array as $value) {
//here you can use $value as the current array field
}
But like said before, you can either adjust your query only to give you the fields that are unpaid:
SELECT id,account,status FROM service WHERE status = 'Unpaid'
(i dont know how exactly your table looks like, but i imagine that structure)
Now every result coming from your DB is "Unpaid", so the testing if(status=='Unpaid') is unnecessary.
For the Cronjobs look on google after "cron php" and you may get :
http://www.thegeekstuff.com/2011/07/php-cron-job/
That means you pop the Script completely from the main site and run it as an stand-alone system, without acces from the web.
I am using a script that sync data betweens two databases (locally to an hosted domain). I made the sync occurs when someone log out from the CMS. Unfortunatly, I have seen cases when two logout happen close enough that the sync script is executed twice. It's not the part of the system I'm trying to change but I was expecting an easy way to makes that script (sync.php) not executing if it's already running.
I have came up with that test scripts:
$db = new DB_Mysql();
if ( $db->transactionBegun() == "0" )
{
$_Continue = true;
$_Continue = $_Continue && $db->squery( "START TRANSACTION" );
$_Continue = $_Continue && $db->squery( "SET #TransactionBegun = true" );
sleep( 10 );
$_Continue = $_Continue && $db->squery( "INSERT INTO tbConfiguration VALUES( NOW(), NOW() )" );
$_Continue = $_Continue && $db->squery( "SET #TransactionBegun = false" );
if ( $_Continue )
{
$db->query( "COMMIT" );
} else {
$db->query( "ROLLBACK" );
}
}
The transactionBegun method consist of:
function transactionBegun()
{
$_ResultSet = $this->query("SELECT #TransactionBegun AS TransactionBegun")->fetch_all(true);
return $_ResultSet[ 'TransactionBegun' ];
}
For some strange alien reason, I can run the script twice (in the same time) and both entry will be made.
Any ideas??
Edit:
I forgot to mention that I am using a mysql_pconnect() and that the server is hosted on a Windows machine. The whole system is a cash register machine using a tablet PC. The only client accessing the server is "localhost".
The variables are per-connection, not per-user. With two independent scripts, you'll have two seperate independent connections, each with its own variable space.
If you need to truly handle locking out parallel usage, you'll need to use a server-side lock acquired via GET_LOCK() or use a transaction mode that does exclusive locking on the resource.
Use file-based locks.
When the script begins, have it check for a file like "sync_db.lock". If it exists, another instance of the script is running. At this point, you can choose to sleep for a few seconds and begin again, or simply give up.
If it doesn't exist, create the file and complete the DB transaction. When the transaction is completed, simply delete the file.
To avoid issues with failed threads, write the current timestamp to the file. When the script checks for the file, read its contents and see if a given time period has passed. Don't forget to overwrite the timestamp if your script continues with the transaction.
A little psudo code:
check to see if a file (/var/tmp/.trans.lck) is there
if it is exit
create lock file if not
when finish remove lock file
I would like to automate the process of sending this email. I mean when a condition is met then the email should automatically be sent to the given email addresses which is already given as hard-coded values. So for an example in my case a Technician has to complete 40jobs a day and if he finished 35 at the end of the day an email should be sent to the supervisor(provided his email id is already given) with Subject name and the body should be like ” The Technician 1234 has completed only 35 jobs for the day instead of 40. I was wondering how can implement this as Im very new to the field of PHP. Please anyone help me out. If possible please provide me with an example.
Thanks
Dilip
You could run a cron that uses the php mail function to send a report about each programmer at a set time each day. The cron script would look something like:
<?php
$to = 'admin#mydomain.com';//the set up email to mail too
$result = mysql_query('select programmer_id, job_count, job_requirement from table'); //query the database
while($job = mysql_fetch_object($result)){
mail($to,'Job counts for ' . $job->programmer_id,"Completed $job->job_count out of $job->job_requirement jobs","FROM: jobcounter#mydomain.com");
}
Have a script check the conditions and send emails, and run it periodically: http://www.google.com/search?q=cronjob
I'm assuming here that your problem is the triggering of the event, rather than the sending of the email itself.
In the example you described, you would need to have a script run at a certain time of day that would check for any condition that would require an email sending, and then send the email. Under any unix-like system, cron is the ideal solution to this. If you are on some kind of basic shared hosting you may not be able to set this up. In that case you would need to set up a task to run on a machine that you do have control over that would call a URL that would run the PHP script. This could be a cronjob, or a Scheduled Task under Windows.
If your example was switched around so that, say, an email was to be sent as soon as a technician completed 40 jobs then you would be able to send the email as part of the script that handled the form submission from the technician whenever he completed a task.
Setup a Cron Job that runs at the "end of the day":
23 55 * * * /path/to/php /path/to/script.php
Have it run a PHP script that can query your Job Store for whatever condition you want to check. For example with Job Store being a database.
$db = new PDO(/* config */);
$result = $pdo->query(
'SELECT count(id) as "tasks_done"
FROM tasks WHERE engineer = "Tom"
AND finished_at = now()');
$result = $result->fetchAll();
if($result[0]['tasks_done'] < 40) {
mail( ... )
}
If the condition is met, send the mail. The above needs refining of course. Dont expect being able to copy/paste it.
Also see:
What is the best method for scheduled tasks in PHP
http://greenservr.com/projects/crontab/crontab.phps
you should use mail() function:
$technicianId = 1234;
$jobsNeeded = 40;
$jobsDone = getJobsDone($technicianId);
if ($jobsDone <= $jobsNeeded) {
mail('supervisor#yourcompany.com', 'Technician '.$technicianId.' slacking', 'The Technician '.$technicianId.' has completed only '.$jobsDone.' jobs for the day instead of '.$jobsNeeded);
}
Could have a cronjob that runs at the end of each day which checks what each technician has done and emails it to the manager.