PHPMailer clearAllRecipients() not working in Wordpress - wordpress

I am creating a plugin for WordPress that sends out a periodic newsletter using WordPress's built-in PHPMailer class. I have everything working correctly, but I want to send individual emails out to a specified number of recipients per hour.
I am pulling a number of email addresses from my database and running them through a foreach loop to send out individual emails and I am attaching each one through the addAddress() function.
To ensure I only send one email per address, I am trying to use clearAllRecipients() at the beginning of the loop, but this is not working. If I have my "email addresses per hour" set at 3, all 3 each email addresses is receiving 3 separate emails.
I also tried to run the list through the foreach loop and just run addAddress for each and use one send statement, but I still get 3 separate emails for each of the three addresses.
Below is my foreach loop. I can't figure out how am doing it wrong. Please help.
foreach ( $list as $e ) {
$phpmailer->clearAllRecipients();
$phpmailer->addAddress($e['email']);
if ( $phpmailer->Send() ) {
// Update the member row in the db. update the "checked" column to 1 so it will be skipped next pass through
$wpdb->query( $wpdb->prepare( "UPDATE {$q_vars['members']} SET checked = %d WHERE id = %d", 1, $e['id'] ) );
}
}

If you’re getting multiple emails with that code, it means your script as a whole is being run multiple times, not that a single run of the script is sending duplicates. You can verify this by appending a random number to your subject line. This is commonly caused by browser plugins that resubmit requests unnecessarily, but it may be because your code is being called by Wordpress for other reasons - adding some logging would reveal that.

Okay, typical PEBCAK error. Sorry! I had inadvertently wrapped my if/else statement to see which mail method to use in an identical foreach loop. So, I was running a foreach from my list, then checking which mail method to use, THEN running an identical foreach within that. I am stupid. Problem solved.

Related

Resolve woocommerce hook woocommerce_email_footer function causing recursion

I'm using Woocommerce hook woocommerce_email_footer() and inside my function, I need to call $email->get_content() which causes recursion and PHP memory error and WordPress exits with system error
Tried to remove the hook before calling the $email->get_content() and adding the hook back right after this call. However, this may not be a foolproof solution since some other session which hits exactly at the time when my function has removed the action might totally miss the hook custom action
I've written the following code in functions.php of my theme to capture the mail contents (mail body) into a local file just before it is being sent whenever a new order is received
//
// Capture the contents of the Emails sent and save into local files
// These Local files are used for further messaging through different channels
//
function Save_Email_Contents_into_Local_File ( $email ) {
if ( $email->id == 'customer_processing_order' ) {
// Remove the action temporarily so as not to cause Recursion while we refer to $email functions
remove_action( 'woocommerce_email_footer', 'Save_Email_Contents_into_Local_File', 20, 1 );
$TargetFilename = '/home/users/....../Sent_Mail.html' ;
$html_message = $email->get_content();
$formatted_message = $email->style_inline($html_message);
file_put_contents($TargetFilename, $formatted_message);
}
// Put the action back to original state
add_action( 'woocommerce_email_footer', 'Save_Email_Contents_into_Local_File', 20, 1 );
};
// add the action
add_action( 'woocommerce_email_footer', 'Save_Email_Contents_into_Local_File', 20, 1 );
Please note in the above function, I'm referring the $email->get_content() public function.
If I do not do the remove_action( 'woocommerce_email_footer', 'Save_Email_Contents_into_Local_File', 20, 1 ); this function becomes recursive and fails with a PHP memory error.
Although this is a workable solution, Removing the action can potentially cause another instance of the customer_processing_order from another user to miss the action and not come to this function if that session hits exactly at the time when this current session has removed the action and before adding the action again.
I'm sure I'm not doing it right! Is there any better way to accomplish what I need - basically I need the exact formatted mail content to be stored in a local file whenever the order is received. Similarly, I will need local file stored for Order completion and order hold, etc. but at later point of time.
Want to achieve storing formatted email into a local file a) without causing recursion / PHP memory errors b) without having to miss some instances of the execution missing the custom code attached to the hook.

Extending twilio plugin to work with WordPress REST API

I've worked through the twilio tutorials regarding sending and receiving SMS with WordPress. I integrated them into a test install I have and then merged them into one. (The receive one is pretty short, although it's not a full "receive" more than a blind response).
Then I came across themebound's twilio-core and so I had a look at that and quickly I got a fatal error because they both use the twilio helper library. For testing, I just deactivated the first one and activated the second, which leads me into my first question:
Both of these use the same library, and have both used require_once. Each loaded it into their own plugin folder. The original name of the library is twilio-php-master, one renames it twilio the other twilio-php. Not that it matters at all, since they're in separate locations. The fatal error is as a result of the inner workings having the same function names.
How can I test for the existence of the other plugins helper library and use that in place of the one that I have installed?
What about the order of how WordPress loads the plugins? It's likely if mine loads first... Well, I can't even get that far because it crashes just trying to have both activated.
--- we're now leading into the next question ---
As a result, I'm probably going to go with the twilio-core version because it seems more featured and is available on github, even if the author isn't overly active (there's a pull request that's months old and no discussion about it).
I want to extend the functionality of one of the sending plugins (either one) with respect to the receipt of the message from twilio. At the moment, both examples use classes for the sending and the receive that I'm using is not. As such I have just added it to the end of the main plugin file (the one with the plugin metadata). (a quick note, this is not the cause of the above fatal error, this happened before I started merging the send and receive).
Because the receive is involved with the REST API and not initiated by a user action on the system (ie someone in the admin area accessing the class through the admin panel), I'm not sure if it's appropriate that a) I put it there, and b) use the send function inside the class when further processing the receipt. I have an end goal of analysing the incoming message and forwarding it back out through twilio or other application or even just recording it in wordpress itself.
Should I keep the receive functionality/plugin separate from the sending one?
And this leads on to the hardest question for me:
How would I extend either plugin to make the send function available to my receive plugin? (this is where part of my confusion comes from) -->> Because both plugins only operate in the admin area, and the REST API isn't an actual user operating in the front-end, how can I call those functions in the admin area? Will is "just be available"? Do I have to replicate them on the public side? and then if so, is it necessary to have it in the admin area as well?
edit: With respect to one of the comments below, I have tested and twl_send_sms is available once the helper is loaded. What I will do is determine a way to see if the helper is loaded (a function exists test will probably suffice) and if so, require or not require my version as appropriate.
From the receive message I am now able to craft a separate forward of a new message. But how can I pass the callback function the parameters of the initial inbound message? eg, how do I populate $sms_in with the POST data?
function register_receive_message_route() {
register_rest_route( 'sms/v1', '/receiver_sms', array(
'methods' => 'POST',
'callback' => 'trigger_receive_sms',
) );
}
function trigger_receive_sms($sms_in = '') {
/* we have three things to do:
* 1: send the reply to twilio,
* 2: craft a reply,
* 3: save the data message to the database
*/
echo header('content-type: text/xml');
echo ('<?xml version="1.0" encoding="UTF-8"?>');
echo ('<Response>');
echo (' <Message>Thanks, someone will be in contact shortly.</Message>');
echo ('</Response>');
$args = array(
'number_to' => '+xxxxxxxxxxx',
'message' => "Test Worked!\n$sms_in",
);
twl_send_sms( $args );
Twilio developer evangelist here.
It sounds to me as though your send functionality (whatever you can get out of twilio-core) is separate to your receive functionality. So I would likely split those up as two plugins and follow the instructions from the post you mentioned on how to write something that receives and responds to SMS messages. That way, twilio-core can use the Twilio library it bundles and your receive plugin won't need to use a library (it just needs to respond with TwiML, which is just XML).
I'm not sure I understand the last part of question 4 though, you can't really interact yourself with the receive endpoint of the plugin because all it will do is return XML to you. That's for Twilio to interact with.
Edit
In answer to your updated question, when your callback is triggered by a POST request it is passed a WP_REST_Request object. This object contains the POST body and the parameters can be accessed by array access.
function trigger_receive_sms($request) {
echo $request['Body'];
}
In good news, if you just plan to send two messages then you can do so entirely with TwiML. You just need to use two <Message>s:
echo ('<?xml version="1.0" encoding="UTF-8"?>');
echo ('<Response>');
echo (' <Message>Thanks, someone will be in contact shortly.</Message>');
echo (' <Message to="YOUR_OTHER_NUMBER">It worked!</Message>');
echo ('</Response>');
This way you don't need to worry about that other library.

Get WooCommerce Subscription Original (Initial) order number

I am working on a project where a user would purchase a subscription and when they do we send data to another server using API calls. Once the server receives the necessary information it creates a serial number and sends it back to the woocommerce site.
This all works just fine, I am successful in sending data and retrieving serial numbers and synchronizing most things on the server.
I am stuck at when Woo Subscriptions renews their order I need to update information on the other server regarding the serial number. I think I would be fine if I could get access to the original order number.
The other issue I am running into is determining if the order is in fact a renewal order, I have a trivial flag set up that checks if "subscription_interval" is inside of the order->get_items, if not then its a renewal order. Something is just fishy about this whole thing.
Basically I need a way to find out if it is a renewal order and if it is give me the initial order number.
Looking at the order screen on the very bottom of the metaboxes (advanced) there is a metabox that shows "Related Subscription Orders" and even shows the initial order. How can I access this data?
Thanks in advance!
Ok, so I found WC_Subscriptions_Renewal_Order and ran a get_class_methods on it. I found is_renewal and get_parent_order_id, life is good again :)
Maybe this can help someone else looking for a way to find out the original order ID by the subscription ID.
function my_get_original_order_id_by_subscription_id( $sub_id ){
$sub_post = get_post( $sub_id );
if( $sub_post && is_object( $sub_post ) && isset( $sub_post->post_parent ) && absint( $sub_post->post_parent ) > 0 ){
return $sub_post->post_parent;
}
return false;
}
The solution is very simple. You need just to get the object post related to the subscription ID ($sub_id), and then the post_parent is the ID of the original order that you were looking for.

Drupal module to control user post frequency?

We've been having a new type of spam-bot this week at PortableApps.com which posts at a rate of about 10 comments a minute and doesn't seem to stop - at least the first hour or so (we've always stopped it within that time so far). We've had them about a dozen times in the last week - sometimes stopping it at 50 or 60, sometimes up to 250 or 300. We're working to stop it and other spam bots as much as possible, but at the moment it's still a real pest.
I was wondering whether in the mean time whether there's any sort of module to control the frequency a user can post at to e.g. 50 an hour or something like 10 in an hour for new users. That at least would mean that instead of having to clear up 300 comments 50 at a time in admin/content/comment we'd have a smaller number to clear. (A module to add a page to delete all content by a user and block them would also be helpful!)
I believe that there's a plugin to do this available for WordPress, but can't find any such thing for Drupal.
For your second question, i would have a look at the code of the User Delete module (click).
The module also disables the user account and unpublished all nodes/comments from a certain user. By extending the code, you could easily create another possibility to unpublish + delete all nodes/comments from a certain user and blocking the account.
After the unpublish code in the module, you should just put delete code (in sql if the module is selecting by a sql-query or by using the drupal delete functions).
Another option would be so make a view (using the view module) only to be viewed by administrators, where you choose a certain user using the filters and then lists his/her posts. Then in the node-contenttype.tpl.php you place a button that calls a function which deletes all nodes/comments and the user.
First problem (post frequency)
I've been thinking about the comment post limit. If I remember correctly Drupal stores comments in a seperate table and has comment specific functions.
I'd create a new module and using the comment_nodeapi function i would check in the operation 'insert' how much comments the current user has already made within a certain timeframe.
To check this I would write a custom sql query on the database which takes the count of alle comments made by uid where the post_date is larger then NOW-1hour. If that count is larger then 10 or 15 or whatever post frequency you want then you give a message back to the user. You can retrieve the user id and name by using the global $user variable.
(example: print $user->name;)
You have to check on your own for the sql query but here's some code when you have the amount:
<?php
function comment_nodeapi(&$node, $op, $arg = 0) {
switch ($op) {
case 'insert':
//PLACE HERE THE SQL TO GET THE COUNT
if($count > 15){
$repeat = FALSE;
$type = 'status'
drupal_set_message("You have reached the comment limit for this time.", $type, $repeat);
break;
}else{
db_query('INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) VALUES (%d, %d, NULL, %d, 0)', $node->nid, $node->changed, $node->uid);
break;
}
}
}
?>
(this code has not been tested so no guarantees, but this should put you on the right track)
I would suggest something like Mollom (from the creator of Drupal). It scans the message for known spam pattern/keywords/... and if this scan fails, it displays a CAPTCHA to the user to make sure that it's a real human that wants to enter content that has the same properties like spam.
They offer a free service and some paid solutions. We are using it for some customers and it's worth the money. It also integrates very well in Drupal.
Comment Limit is probably what you need.
http://drupal.org/project/spam
http://drupal.org/project/antispam - with akismet support

WordPress Write Cache Issue with Multiple Sessions

I'm working on a content dripper custom plugin in WordPress that my client asked me to build. He says he wants it to catch a page view event, and if it's the right time of day (24 hours since last post), to pull from a resource file and output another post. He needed it to also raise a flag and prevent other sessions from firing that same snippet of code. So, raise some kind of flag saying, "I'm posting that post, go away other process," and then it makes that post and releases the flag again.
However, the strangest thing is occurring when placed under load with multiple sessions hitting the site with page views. It's firing instead of one post -- it's randomly doing like 1, 2, or 3 extra posts, with each one thinking that it was the right time to post because it was 24 hours past the time of the last post. Because it's somewhat random, I'm guessing that the problem is some kind of write caching where the other sessions don't see the raised flag just yet until a couple microseconds pass.
The plugin was raising the "flag" by simply writing to the wp_options table with the update_option() API in WordPress. The other user sessions were supposed to read that value with get_option() and see the flag, and then not run that piece of code that creates the post because a given session was already doing it. Then, when done, I lower the flag and the other sessions continue as normal.
But what it's doing is letting those other sessions in.
To make this work, I was using add_action('loop_start','checkToAddContent'). The odd thing about that function though is that it's called more than once on a page, and in fact some plugins may call it. I don't know if there's a better event to hook. Even still, even if I find an event to hook that only runs once on a page view, I still have multiple sessions to contend with (different users who may view the page at the same time) and I want only one given session to trigger the content post when the post is due on the schedule.
I'm wondering if there are any WordPress plugin devs out there who could suggest another event hook to latch on to, and to figure out another way to raise a flag that all sessions would see. I mean, I could use the shared memory API in PHP, but many hosting plans have that disabled. Can't use a cookie or session var because that's only one single session. About the only thing that might work across hosting plans would be to drop a file as a flag, instead. If the file is present, then one session has the flag. If the file is not present, then other sessions can attempt to get the flag. Sure, I could use the file route, but it's kind of immature in my opinion and I was wondering if there's something in WordPress I could do.
The key may be to create a semaphore record in the database for the "drip" event.
Warning - consider the following pseudocode - I'm not looking up the functions.
When the post is queried, use a SQL statement like
$ts = get_time_now(); // or whatever the function is
$sid = session_id();
INSERT INTO table (postcategory, timestamp, sessionid)
VALUES ("$category", $ts, "$sid")
WHERE NOT EXISTS (SELECT 1 FROM table WHERE postcategory = "$category"
AND timestamp < $ts - 24 hours)
Database integrity will make this atomic so only one record can be inserted.
and the insertion will only take place if the timespan has been exceeded.
Then immediately check to see if the current session_id() and timestamp are yours. If they are, drip.
SELECT sessionid FROM table
WHERE postcategory = "$postcategory"
AND timestamp = $ts
AND sessionid = "$sid"
The problem goes like this with page requests even from the same session (same visitor), but also can occur with page requests from separate visitors. It works like this:
If you are doing content dripping, then a page request is probably what you intercept with add_action('wp','myPageRequest'). From there, if a scheduled post is due, then you create the new post.
The post takes a little bit of time to write to the database. In that time, a query on get_posts() may not see that new record yet. It may actually trigger your piece of code to create a new post when one has already been placed.
The fix is to force WordPress to flush the write cache appears to be this:
try {
$asPosts = array();
$asPosts = # wp_get_recent_posts(1);
foreach($asPosts as $asPost) {break;}
# delete_post_meta($asPost['ID'], '_thwart');
# add_post_meta($asPost['ID'], '_thwart', '' . date('Y-m-d H:i:s'));
} catch (Exception $e) {}
$asPosts = array();
$asPosts = # wp_get_recent_posts(1);
foreach($asPosts as $asPost) {break;}
$sLastPostDate = '';
# $sLastPostDate = $asPost['post_date'];
$sLastPostDate = substr($sLastPostDate, 0, strpos($sLastPostDate, ' '));
$sNow = date('Y-m-d H:i:s');
$sNow = substr($sNow, 0, strpos($sNow, ' '));
if ($sLastPostDate != $sNow) {
// No post today, so go ahead and post your new blog post.
// Place that code here.
}
The first thing we do is get the most recent post. But we don't really care if it's not the most recent post or not. All we're getting it for is to get a single Post ID, and then we add a hidden custom field (thus the underscore it begins with) called
_thwart
...as in, thwart the write cache by posting some data to the database that's not too CPU heavy.
Once that is in place, we then also use wp_get_recent_posts(1) yet again so that we can see if the most recent post is not today's date. If not, then we are clear to drip some content in. (Or, if you want to only drip in like every 72 hours, etc., you can change this a little here.)

Resources