I have an educational Wordpress site where students have the role 'child' and adults have the role 'subscriber'. I need to prevent emails being sent to the 'child' users (by Woocommerce - but I think they are sent via the mail function in Wordpress).
Is there a line I can add in functions.php to stop mail being sent to specific roles?
Thanks in advance
Maria
I think it might be possible to adjust the email recipients via a filter in the get_recipient() method.
/**
* get_recipient function.
*
* #return string
*/
public function get_recipient() {
return apply_filters( 'woocommerce_email_recipient_' . $this->id, $this->recipient, $this->object );
}
Let's take for example the new order email. Here's it's trigger() method:
/**
* trigger function.
*
* #access public
* #return void
*/
function trigger( $order_id ) {
if ( $order_id ) {
$this->object = wc_get_order( $order_id );
$this->find['order-date'] = '{order_date}';
$this->find['order-number'] = '{order_number}';
$this->replace['order-date'] = date_i18n( wc_date_format(), strtotime( $this->object->order_date ) );
$this->replace['order-number'] = $this->object->get_order_number();
}
if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
return;
}
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
Specifically
if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
which says if there is no recipient then the email won't send. Also $this->object = wc_get_order( $order_id ); tells us that the $order object is passed to the get_recipient_$id filter.
The id of the new order email is "customer_completed_order" as shown in the class constructor for the email.
SO, putting that all together we can filter the recipient for new order emails:
add_filter( 'so_29896856_block_emails', 'woocommerce_email_recipient_customer_completed_order', 10, 2 );
function so_29896856_block_emails( $recipient, $order ) {
if( isset( $order->customer_user ) ){
$user = new WP_User( $customer_user );
if ( in_array( 'child', (array) $user->roles ) ) {
$recipient = false;
}
}
return $recipient;
}
However, this assumes that the recipient is a single string (if an array it would kill all the recipients and not just the child... though by the default the new order email is sent to the billing email address.
Also, note that I didn't test this at all, so your mileage may vary.
Related
Does anyone know if with contact form 7 it is possible to have a checkbox that when it is activated by the visitor, this visitor is registered as a wordpress user, as a subscriber?
After the comment of Howard E, the question changes to...
How can be used wpcf7_before_send_mail for register a new user with the data of the form?
something like this, but I don't know if it is completely correct...
add_action( 'wpcf7_before_send_mail', 'register_user' );
function register_user($cf7) {
$form_id = $cf7->id();
if ($form_id == 300 || $form_id == 301 || $form_id == 302) {
$submission = WPCF7_Submission :: get_instance();
}
if ($submission) {
if (empty($posted_data)) { return; }
$accept = $posted_data['acceptance-register-yes']; //acceptance check to be registered
if (empty($accept)) { return; }
$email = $posted_data['your-email'];
$name1 = $posted_data['your-name'];
$name2 = $posted_data['your-last-name'];
$name = ''; //here will go function to delete spaces and generate user name from $name1 + $name2
$pass = ''; //here will go function to random password
function create_user($n,$p,$e){
if (!username_exists($n) && !email_exists($e)) {
$user_id = wp_create_user($n, $p, $e);
$user = new WP_User($user_id);
$user->set_role( 'subscriber' );
}
}
create_user($name,$pass,$email);
}
}
many thanks
You can create a user and hook into wpcf7_before_send_mail like this.
function wp_create_custom_account(){
// Get the WPCF7 Submission instance
$submission = WPCF7_Submission::get_instance();
if ($submission) {
$posted_data = $submission->get_posted_data();
// Get the posted variables
$username = isset($posted_data['username'])?$posted_data['username']:'';
$password = isset($posted_data['password'])?$posted_data['password']:'';
$eml = isset($posted_data['eml'])?$posted_data['eml']:'';
// This can be radio or checkbox. Adjust your code accordingly
$radio = isset($posted_data['radio'][0])?$posted_data['radio'][0]:'';
if ($radio) {
$user = $username;
$pass = $password;
$email = eml;
if ( !username_exists( $user ) && !email_exists( $email ) ) {
$user_id = wp_create_user( $user, $pass, $email );
$user = new WP_User( $user_id );
$user->set_role( 'subscriber' );
}
}
}
}
add_action('wpcf7_before_send_mail','wp_create_custom_account');
If i add a new customer to Woo using the REST API i need to avoid sending the new customer email.
The REST API docs don't talk about this and there's no parameter to set that can prevent the "WC_Email_Customer_New_Account" email
I've tried about 10 different things, I'll list the most recent ones
Editing the Woo source directly class-wc-emails.php. Not even that works, because when i collect the user meta it's still blank and only has the user ID and nice name
Creating a plugin that checks an external API and if a condition is met does remove_action('woocommerce_created_customer_notification', array($email_class->emails['WC_Email_Customer_New_Account'], 'trigger'));
Processing everything inside the plugin but i have the same problem as 1.
I think I managed to pull it off. My goal was to create a user (customer) via WooCommerce REST API (Customers endpoint) and not to trigger the New Account email.
The first suspect is the woocommerce_email_enabled_customer_new_account filter. It gives us the \WP_User and \WC_Email_Customer_Completed_Order objects. The first idea obviously is to just run get_user_meta() against the user.
add_filter( 'woocommerce_email_enabled_customer_new_account', function( $enabled, $user, $email ) {
/**
* #var bool $enabled
* #var \WP_User $user
* #var \WC_Email_Customer_Completed_Order $email
*/
$isOurGuy = 'foobar' === get_user_meta( $user->ID, 'meta_key_is_so_meta', true );
if ( $isOurGuy ) {
return false;
}
return $enabled;
}, 10, 3 );
As it turns out, the REST endpoint handler can only push metadata after the user is created, and email notification is triggered implicitly via a hook in \WC_Emails(). It means when our code is running during that email hook, no metadata is available yet.
Next thing to check was to go to the moment before the user is pushed anywhere at all. That would be woocommerce_before_data_object_save, an action this time. It gives us two objects, \WC_Customer and \WC_Customer_Data_Store. The \WC_Customer object has our metadata, yay! Let's enclose the existing code into another handler.
add_action( 'woocommerce_before_data_object_save', function( $customer, $store ) {
/**
* #var \WC_Customer $customer
* #var \WC_Customer_Data_Store $store
*/
if ( !( $customer instanceof \WC_Customer ) ) { // I guess other object types may end up here, let's make sure we only get to work with customers.
return;
}
$isOurGuy = 'foobar' === $customer->get_meta( 'meta_key_is_so_meta', true );
if ( !$isOurGuy ) {
return;
}
add_filter( 'woocommerce_email_enabled_customer_new_account', function( $enabled, $user, $email ) use ( $customer ) {
/**
* #var bool $enabled
* #var \WP_User $user
* #var \WC_Email_Customer_Completed_Order $email
*/
if ( $customer->get_id() !== $user->ID ) { // Is it our guy?
return $enabled;
}
return false;
}, 10, 3 );
}, 10, 2 );
It still does not work. Because this is before object save, the user did not exist at the moment when we captured $customer into our scope. So $customer->get_id() returns 0 (zero). It seems that we overshot in time a bit - need to roll forward. woocommerce_created_customer seems like a good candidate. It gives us among other things the new user ID.
Let's compile everything together.
add_action( 'woocommerce_before_data_object_save', function( $customer, $store ) {
/**
* #var \WC_Customer $customer
* #var \WC_Customer_Data_Store $store
*/
if ( !( $customer instanceof \WC_Customer ) ) { // I guess other object types may end up here, let's make sure we only get to work with customers.
return;
}
$isOurGuy = 'foobar' === $customer->get_meta( 'meta_key_is_so_meta', true );
if ( !$isOurGuy ) {
return;
}
/**
* Hook into the Customer Created event to capture the new customer ID.
*/
add_action( 'woocommerce_created_customer', function( $customerId ) {
add_filter( 'woocommerce_email_enabled_customer_new_account', function( $enabled, $user, $email ) use ( $customerId ) {
/**
* #var bool $enabled
* #var \WP_User $user
* #var \WC_Email_Customer_Completed_Order $email
*/
if ( $customerId !== $user->ID ) { // Is it our guy?
return $enabled;
}
return false;
}, 10, 3 );
}, 1 ); // NB: Email is also hooked here with priority 10.
}, 10, 2 );
Now let's recap. We hook into the data store and capture the moment a \WC_Customer object is saved. We perform custom metadata-based logic to decide whether to proceed. Then we skip to the moment when the user is created to retrieve their ID. Then we hop a little further in time during the "email enabled?" check to actually disable the notification for the given user.
Try this
Go to:
WooCommerce -> Settings -> Email tab
You can find the Options are "New account". Click the manage button.
Uncheck the "Enable this email notification".
I'm developing a custom wordpress widget. The widget needs some data from the user and needs to check this data server-side.
I wrote the code that checks the data inside the function 'update' of the widget. When I press the button save of the widget the function update got called correctly and my validation is executed.
public function update( $new_instance, $old_instance ) {
$instance = array();
foreach ($this->fields as $field) {
$fieldName = $field['name'];
$instance[$fieldName] =
(!empty($new_instance[$fieldName]) strip_tags($new_instance[$fieldName]) : '' );
}
$check = validate($new_instance);
return $instance;
}
What I need is to display a message to the user based on the result of the validation. How can I do this? For what I've seen the function update is called through ajax so I can't use an admin notice.
Is it possible?How can I do that?
Try below code
add_action('admin_notices', 'misha_custom_order_status_notices');
function misha_custom_order_status_notices() {
global $pagenow, $typenow;
if( get_transient( 'fx-admin-notice-panel' )){
echo "<div class=\"updated\"><p>Custom notification comes here</p></div>";
}
}
public function update( $new_instance, $old_instance ) {
$instance = array();
foreach ($this->fields as $field) {
$fieldName = $field['name'];
$instance[$fieldName] =
(!empty($new_instance[$fieldName])?
strip_tags($new_instance[$fieldName]) :
''
);
}
$check = validate($new_instance);
set_transient( 'fx-admin-notice-panel', true, 5 );
return $instance;
}
I'm trying to check if WooCommerce is active or not, I created a property with with a default value of false, then I created a method to check if WooCommerce is active using is_plugin_active() and admin_init hook, if active the value of the property must be updated to true: here is the code:
class MyClass{
public $woo_active = false;
public function __construct(){
add_action( 'admin_init', array( $this, 'check_if_woo_active' ) );
}
// check if WooCommerce is active
public function check_if_woo_active(){
if( is_plugin_active( 'woocommerce/woocommerce.php' ) ){
$this->woo_active = true;
}
}
// is_woo_active()
public function is_woo_active(){
return $this->woo_active;
}
}
$var = new MyClass();
var_dump( $var->is_woo_active() );
the issue is that var_dump returns false even if WooCommerce is active, BUT, if I use var_dump inside the function check_if_woo_active(), it returns true.
Why the property value is not updated? thanks
Updated:
The Second Solution as #helgatheviking sugested works fine, also this works very well and short
class MyClass{
// check if WooCommerce is active
public function is_woo_active(){
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
if( is_plugin_active( 'woocommerce/woocommerce.php' ) ){
return true;
}else{
return false;
}
}
}
$var = new MyClass();
var_dump( $var->is_woo_active() );
If I had to guess, then $var = new MyClass(); is run before admin_init so the check_if_woo_active() isn't run.
Couple things you could do. First, I will usually launch my plugin on the woocommerce_loaded hook. That way I am 100% sure WooCommerce is running.
class MyClass{
protected static $instance = null;
/**
* Main MyClass Instance
*
* Ensures only one instance of MyClass is loaded or can be loaded.
*
* #static
* #see MyClass()
* #return MyClass - Main instance
* #since 0.1.0
*/
public static function instance() {
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof MyClass ) ) {
self::$instance = new MyClass();
}
return self::$instance;
}
public function __construct(){
// Do what you want, WC is definitely active
}
}
/**
* Returns the main instance of class.
*
* #return MyClass
*/
function MyClass() {
return MyClass::instance();
}
// Launch the class if WooCommerce is loaded:
add_action( 'woocommerce_loaded', 'MyClass' );
You could also mimic what WooCommerce does with their premium plugins and check the option that stores the active plugins:
class MyClass{
private static $active_plugins;
public static function get_active_plugins() {
self::$active_plugins = (array) get_option( 'active_plugins', array() );
if ( is_multisite() ){
self::$active_plugins = array_merge( self::$active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
}
}
// check if WooCommerce is active
public static function check_if_woo_active() {
if ( ! self::$active_plugins ) self::get_active_plugins();
return in_array( 'woocommerce/woocommerce.php', self::$active_plugins ) || array_key_exists( 'woocommerce/woocommerce.php', self::$active_plugins );
}
}
var_dump( MyClass::check_if_woo_active() );
is it possbile to rate the new post (with admin account) after this?
$post_id = wp_insert_post( $my_post, $wp_error );
According to this post of the Wordpress support forum, what you should do is something like this:
function set_rating($post_id, $vote) { // $vote = 0..10
$admin = get_user_by('login', 'admin');
if ($admin !== false) {
$ip = $_SERVER['SERVER_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'];
gdsrBlgDB::save_vote($post_id, $admin->ID, $ip, $ua, $vote);
}
return $admin;
}
You need to add a hook after that happens. First write a function and then this:
add_action('wp_insert_post', 'set_star_rating');
function set_star_rating() {
global $post;
$post = ...
}
There is also save_posts hook which happens while you're saving the post and is better documented.
This may be useful for doing some custom development based on GD Star Rating Plugin. Find my functions to 'save post like', to get 'like count for a post' and to 'check whether current user liked a post'. This is working for custom Post Types as well.
/**
* Function to save post like
* #param type $post_id
* #param type $user_id
*/
function save_post_like($post_id, $user_id) {
$ip = $_SERVER['SERVER_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'];
if(has_user_liked_post($post_id) == 0)
gdsrBlgDB::save_vote_thumb($post_id, $user_id, $ip, $ua, 1);
}
/**
* Function to check if user like the post
* #global type $wpdb
* #global type $table_prefix
* #param type $post_id
* #return type
*/
function has_user_liked_post($post_id) {
global $wpdb, $table_prefix;
$userdata = wp_get_current_user();
$user_id = is_object($userdata) ? $userdata->ID : 0;
$sql = "SELECT * FROM " . $table_prefix . "gdsr_votes_log WHERE vote_type = 'artthumb' AND id = " . $post_id . " AND user_id = " . $user_id;
$results = $wpdb->get_row($sql, OBJECT);
if (count($results))
return 1;
else
return 0;
}
/**
* Function to get total Likes of a Post
* #global type $wpdb
* #global type $table_prefix
* #param type $post_id
* #return type
*/
function get_post_like_count($post_id) {
global $wpdb, $table_prefix;
$sql = "SELECT * FROM " . $table_prefix . "gdsr_data_article WHERE post_id = " . $post_id;
$results = $wpdb->get_row($sql, OBJECT);
if (count($results))
return $results->user_recc_plus;
else
return 0;
}