I was wondering to know if it is possible to run a WordPress function with a delay of some seconds or minutes.
I use the following snippet to send an email to admin after a new user is registered on my website
add_action( 'user_register', 'registration_email_to_admin', 10, 1 );
function registration_email_to_admin( $user_id ) {
wp_new_user_notification( $user_id );
}
Then I use the following code to filter the email's content
//Filters the contents of the new user notification email sent to the site admin.
add_filter( 'wp_new_user_notification_email_admin', 'custom_wp_new_user_notification_admin_email', 10, 3 );
function custom_wp_new_user_notification_admin_email( $wp_new_user_notification_email, $user, $blogname ) {
//pass user id into a variable
$user_id = $user->id;
//get teams for that user
$teams = wc_memberships_for_teams_get_teams( $user_id );
$teamNames = [];
foreach($teams as $teamName){
array_push($teamNames, $teamName->get_name());
}
$teamNamesString = implode (',' , $teamNames);
$wp_new_user_notification_email['subject'] = sprintf( '[%s] New user registered. User ID = %s', $blogname, $user->id );
$wp_new_user_notification_email['message'] = sprintf( "%s ( %s ) has registered to the website %s.", $user->user_login, $user->user_email, $blogname ) . "\r\n\r\n";
$wp_new_user_notification_email['message'] .= sprintf(__('Username: %s'), $user->user_login) . "\r\n";
$wp_new_user_notification_email['message'] .= sprintf(__('Email: %s'), $user->user_email) . "\r\n";
$wp_new_user_notification_email['message'] .= sprintf(__('ID: %s'), $user->id) . "\r\n";
$wp_new_user_notification_email['message'] .= sprintf(__('Team Name: %s'), $teamNamesString) . "\r\n";
$wp_new_user_notification_email['headers'] = "From: Members Website <info#test.com> \n\r cc: GeorgeFR <test#yahoo.com>";
return $wp_new_user_notification_email;
}
On all the above, everything works well except the last append to the message
$wp_new_user_notification_email['message'] .= sprintf(__('Team Name: %s'), $teamNamesString) . "\r\n";
Using the WooCommerce Memberships for Teams plugin, it seems that the new user is being assigned to the team that has been invited to after his/her registration. That being said, the variable $teamNamesString is always empty on my email content.
So, is it possible to run all the above with some delay, making sure that the team has been assigned to the new user before I send the email? It is important for me to include the team's name to the email for business management purposes.
I was finally able to find the fix here.
Using the Woo Memberships and Woo Teams for Memberships plugins, we have 3 different team roles on our website. Owners, Managers, and Members. Also, we are using Woo Subscriptions in combination with Woo Memberships. So, every time a new subscription purchase comes, the purchaser will create a team and become the owner of that team.
The codes that worked are the following:
For Owners (used the woocommerce_subscription_status_active action from Woo Subscriptions):
//fires after purchases
function send_admin_email_with_owner_data_after_purchase( $subscription ) {
// Get the user in the order
$user_id = $subscription->get_user_id();
// Get the products in the order
$items = $subscription->get_items();
foreach( $items as $item ) {
$product = $item->get_product();
$product_id = $product->get_id();
if ($product_id == "8865") {
wp_new_user_notification( $user_id );
}
}
}
add_action( 'woocommerce_subscription_status_active', 'send_admin_email_with_owner_data_after_purchase', 10 );
For Managers and Members (used the wc_memberships_user_membership_created action from Woo Memberships):
//fires after acceptance of invitations to teams (in my case)
function send_admin_email_with_member_data( $plan, $args ) {
$user_id = $args['user_id'];
$memberArgs = array (
$status => "any",
$role => "manager,member"
);
//get teams for that user
$teams = wc_memberships_for_teams_get_teams( $user_id, $memberArgs );
if ( $args['is_update'] = true && ! empty( $teams ) ) {
wp_new_user_notification( $user_id );
}
}
add_action( 'wc_memberships_user_membership_created', 'send_admin_email_with_member_data', 20, 2 );
I am glad I found a way here. Thank you all for your help!
Related
I'm building a plugin where a customer(s) is attached to a shop manager. The shop manager can only see orders of customers that are attached to him. The plugin has two parts :
The first one, i already built it, hide all orders that aren't attached to a shop manager. Here's the code in case you want to see how it works :
function before_checkout_create_order($order, $data) {
$store_manager_id = '';
switch ($order->get_user_id()) {
case 34:
$store_manager_id = 18;
break;
case 33:
$store_manager_id = 20;
break;
}
$order->update_meta_data('_store_manager_id', $store_manager_id);
}
add_action('woocommerce_checkout_create_order', 'before_checkout_create_order', 20, 2);
function custom_admin_shop_manager_orders($query) {
global $pagenow;
$qv = &$query->query_vars;
$currentUserRoles = wp_get_current_user()->roles;
$user_id = get_current_user_id();
if (in_array('shop_manager', $currentUserRoles)) {
if ( $pagenow == 'edit.php' &&
isset($qv['post_type']) && $qv['post_type'] == 'shop_order' ) {
// I use the meta key from step 1 as a second parameter here
$query->set('meta_key', '_store_manager_id');
// The value we want to find is the $user_id defined above
$query->set('meta_value', $user_id);
}
}
return $query;
}
add_filter('pre_get_posts', 'custom_admin_shop_manager_orders');
?>
The second part where i need help : I'm trying to have emails only for the shop manager concerned.
Eg : A customer order some products, the shop manager attached to him receives an email about his order but all others shop managers dont receive anything.
If you have any ideas feel free !
Place the following function in your functions.php
Using woocommerce_thankyou hook
function notify_store_manager($order_get_id) {
//Get current order
$order = wc_get_order( $order_get_id );
//Get the manager id for this order
$manager_id = $order->get_meta('_store_manager_id');
//Get manager data
$manager = get_userdata($manager_id);
//Get manager email address
$manager_email = $manager->user_email;
//Build your email info
$order_id = $order->get_id();
$to = $manager_email;
$subject = 'You have new order'.$order_id.'';
$body = 'You have new order with id '.$order_id.'';
$headers = array('Content-Type: text/html; charset=UTF-8');
wp_mail( $to, $subject, $body, $headers );
}
add_action('woocommerce_thankyou', 'notify_store_manager', 10);
I am trying to find a way on how to add the customer phone and email below the name on the WooCommerce order view. See picture for reference where I need to add this information.
Any ideas, tips or pointers on how to make this happen?
The following code will add the billing phone and email under the order number in backend orders list (for Woocommerce 3.3+ only):
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 50, 2 );
function custom_orders_list_column_content( $column, $post_id ) {
if ( $column == 'order_number' )
{
global $the_order;
if( $phone = $the_order->get_billing_phone() ){
$phone_wp_dashicon = '<span class="dashicons dashicons-phone"></span> ';
echo '<br>' . $phone_wp_dashicon . $phone.'</strong>';
}
if( $email = $the_order->get_billing_email() ){
echo '<br><strong>' . $email . '</strong>';
}
}
}
Code goes in function.php file of your active child theme (active theme). Tested and works.
Thank you, worked perfectly.
I had modifed based on my need, adding the code here for others.
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 50, 2 );
function custom_orders_list_column_content( $column, $post_id ) {
if ( $column == 'order_number' )
{
global $the_order;
if( $phone = $the_order->get_billing_phone() ){
$phone_wp_dashicon = '<span class="dashicons dashicons-phone"></span> ';
echo '<br>Mobile: '.'' . $phone.'</strong>';
}
if( $email = $the_order->get_billing_email() ){
echo '<br>Email: '.'' . $email . '';
}
}
}
I need help with a custom email hook for woocommerce.
I am trying to send a different email depending on product ID whenever a product is completed.
My code, which is not working, is as follows:
/**************
DIFFERENT MESSAGES FOR DIFFERENT PRODUCTS
****************/
//hook our function to the new order email
add_action('woocommerce_email_order_details', 'uiwc_email_order_details_products', 1, 4);
function uiwc_email_order_details_products($order, $admin, $plain, $email) {
$status = $order->get_status();
// checking if it's the order status we want
if ( $status == "completed" ) {
$items = $order->get_items();
if ( $item['product_id'] == "3181") {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>To get started, please follow this link to complete the Policies form.<br><br>This is a really important first step, and only takes about 5 minutes. After completeing the Policies form, you will receive additional instructions on next steps.<br><br>Congratulations! Let your journey begin.<br><br>', 'uiwc' );
}
elseif ( $item['product_id'] == "3223") {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>Differnet product so differenct email....<br><br>', 'uiwc' );
}
}
}
Any suggestions is greatly appreciated
There is some mistakes in your code, instead try the following
//hook our function to the new order email
add_action( 'woocommerce_email_order_details', 'custom_email_order_details', 4, 4 );
function custom_email_order_details( $order, $admin, $plain, $email ) {
$domain = 'woocommerce';
// checking if it's the order status we want
if ( $order->has_status('completed') ) {
foreach( $order->get_items() as $item ){
if ( $item->get_product_id() == '3181' ) {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>To get started, please follow this link to complete the Policies form.<br><br>This is a really important first step, and only takes about 5 minutes. After completeing the Policies form, you will receive additional instructions on next steps.<br><br>Congratulations! Let your journey begin.<br><br>', $domain );
break;
}
elseif ( $item->get_product_id() == '3223' ) {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>Differnet product so differenct email....<br><br>', $domain );
break;
}
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
In Woocommerce, I have a Course product that uses WC Fields to collect student[s] names and email addresses, and custom email template that sends an email when this course product is purchased. As of now, based on the answer in this thread, I am able to collect the email addresses added to those custom fields and send one email to each student as a BCC recipient.
I am now trying to have the emails include the student's name and email address in the body of the email, but I do not want all of the names to appear in the same email. For example, if Student A (studenta#example.com) and Student B (studentb#example.com) are both enrolled in the same purchase, the email received by Student A should just contain in the body something like "Dear Student A, Thank you for enrolling. Use your email address studenta#example.com to login." and the email received by Student B should say the same but with Student B's info, and they should not see the other one's.
So I would have to send multiple emails, based on the number of students being enrolled in that purchase (which is set in the order meta, added from the purchased product's meta).
I tried adding a while() outside of the for() to continue checking through the items until it had gone through all of the items, and sending again for each time it found, but I think the foreach($items as $item) ends up starting through the first item again, since that sends two emails to only the first recipient.
***UPDATED****
I changed the custom email code (which I've stored in my plugins) to:
$order = wc_get_order( $order_id );
$items = $order->get_items();
$course_ordered = false;
$cqt = 1;
$emailnum = 0;
foreach ( $items as $item ) {
$product_id = $item['product_id'];
if ( $item['product_id']== 1164 ) {
$course_ordered = true;
$emailnum++;
continue;
}
}
if ( ! $course_ordered )
return;
while( $cqt <= $emailnum ){
// replace variables in the subject/headings
$this->find[] = '{order_date}';
$this->replace[] = date_i18n( woocommerce_date_format(), strtotime( $this->object->order_date ) );
$this->find[] = '{order_number}';
$this->replace[] = $this->object->get_order_number();
if ( ! $this->is_enabled() || ! $this->get_recipient() )
return;
// woohoo, send the email!
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
$cqt++;
}
And the code in my functions.php file, which was from this answer, is:
add_filter( 'woocommerce_email_headers', 'student_email_notification', 20, 3 );
function student_email_notification( $header, $email_id, $order ) {
// Only for 'wc_course_order' notification
if( 'wc_course_order' != $email_id ) return $header;
$student_emails = array();
//$enroll_num = 0;
// Loop though Order IDs
foreach( $order->get_items() as $item_id => $item_data ){
/*$course_qty = $item_data->get_quantity();
$q = 1;
while ( $q <= $course_qty){
$enroll_num++;
// Get the student full Name
$full_name = wc_get_order_item_meta( $item_id, 'First Name - '.$enroll_num, true );
$full_name .= ' ' . wc_get_order_item_meta( $item_id, 'Last Name - '.$enroll_num, true );
// Get the student email
$student_email = wc_get_order_item_meta( $item_id, 'Student Email - '.$enroll_num, true );
if( ! empty($student_email) && $full_name != ' ' )
// Format the name and the email and set it in an array
$student_emails[] = utf8_decode($full_name . ' <' . $student_email . '>'); // Add name + email to the array
$q++;
}*/
// Get the student full Name
$full_name = wc_get_order_item_meta( $item_id, 'First Name - 1', true );
$full_name .= ' ' . wc_get_order_item_meta( $item_id, 'Last Name - 1', true );
// Get the student email
$student_email = wc_get_order_item_meta( $item_id, 'Student Email - 1', true );
if( ! empty($student_email) && $full_name != ' ' )
// Format the name and the email and set it in an array
$student_emails[] = utf8_decode($full_name . ' <' . $student_email . '>'); // Add name + email to the array
}
// If any student email exist we add it
if( count($student_emails) > 0 ){
// Remove duplicates (if there is any)
$student_emails = array_unique($student_emails);
// Add the emails to existing recipients
$headers .= 'Cc: ' . implode(',', $student_emails) . "\r\n";
}
return $headers;
}
(If the section that is commented out is uncommented, it only sends to the first recipient, and not the second, if it is entered as two separate products, if I remove the while() and use the part below it instead, it sends one email to all recipients)
It sends to all recipients (i.e. gets all of the emails from all of the custom fields and uses those as CC or BCC, however I set it) twice, ie sends the same email twice to everyone. How can I get it to send twice but each time to only one of the recipients? Thank you for any suggestions!
I found a solution for the first half of my question - adding the user's names and emails from the product meta to the body of the email - though still have not been able to get it to send a unique email to each email address (email addresses are coming from this meta):
I updated my custom email template (this is only the email template, not the custom function that creates/sends the email) to the following:
<?php
$student_emails = array();
// Loop though Order IDs
foreach( $order->get_items() as $item_id => $item_data ){
// Get the student full Name
$full_name = wc_get_order_item_meta( $item_id, 'First Name - 1', true );
$full_name .= ' ' . wc_get_order_item_meta( $item_id, 'Last Name - 1', true );
// Get the student email
$student_email = wc_get_order_item_meta( $item_id, 'Student Email - 1', true );
print_r('Name: ' . $full_name . ', Login Email: ');
print_r($student_email . '<br/>');
}
?>
This prints the various users and their emails in the email body.
I've searched around here and some posts helped me almost nailing this problem:
My parcel company adds an order note to the order including text and a tracking url for the package. And after that they put the order on completed.
This URL needs to be added to the order completed mail to the customer.
This code is working but only if I send the order completed mail manually:
add_action( 'woocommerce_email_before_order_table', 'woo_add_order_notes_to_email' );
function woo_add_order_notes_to_email() {
global $woocommerce, $post;
$args = array(
'post_id' => $post->ID,
'status' => 'approve',
'type' => 'order_note'
);
$notes = get_comments( $args );
if ( $notes ) {
foreach( $notes as $note ) {
$notecontent = $note->comment_content;
if( preg_match('/[a-zA-Z]+:\/\/[0-9a-zA-Z;.\/?:#=_#&%~,+$-]+/', $notecontent, $matches) != 0 ) {
echo '<p>You can follow your order via this link: ' . $matches[0] . '</p>';
}
}
}
}
I hope you guys can help me out.
I think you are using wrong hook.
You can do the same thing with this hook 'woocommerce_email_order_meta'. It will resolve your issue.
here is the code example
add_action( 'woocommerce_email_order_meta', 'woo_add_order_notes_to_email' );
function woo_add_order_notes_to_email( $order, $sent_to_admin = false, $plain_text = false ) {
/*Do something here to add with order completion email */
}