We have a script to notify admins by email when a new page or post is created by a contributor and is therefore 'pending' but the notifications are duplicating. The pages/posts are using gutenberg editor which I think is whats causing this (see here: https://github.com/WordPress/gutenberg/issues/15094) but I dont know what the solution is.
add_action( 'transition_post_status', 'pending_submission_notifications_send_email', 10, 3 );
function pending_submission_notifications_send_email( $new_status, $old_status, $post ) {
// Notify Admin that Contributor has written a post.
if ( 'pending' === $new_status && user_can( $post->post_author, 'edit_posts' ) && ! user_can( $post->post_author, 'publish_posts' ) ) {
$pending_submission_email = 'example#email.com';
$admins = ( empty( $pending_submission_email ) ) ? get_option( 'admin_email' ) : $pending_submission_email;
$edit_link = get_edit_post_link( $post->ID, '' );
$preview_link = get_permalink( $post->ID ) . '&preview=true';
$username = get_userdata( $post->post_author );
$username_last_edit = get_the_modified_author();
$subject = __( 'New post or page pending review', 'pending-submission-notifications' ) . ': "' . $post->post_title . '"';
$message = __( 'A new post or page is pending review.', 'pending-submission-notifications' );
$message .= "\r\n\r\n";
$message .= __( 'Author', 'pending-submission-notifications' ) . ': ' . $username->user_login . "\r\n";
$message .= __( 'Title', 'pending-submission-notifications' ) . ': ' . $post->post_title . "\r\n";
$message .= "\r\n\r\n";
$message .= __( 'Edit the submission', 'pending-submission-notifications' ) . ': ' . $edit_link . "\r\n";
$message .= __( 'Preview the submission', 'pending-submission-notifications' ) . ': ' . $preview_link;
$result = wp_mail( $admins, $subject, $message );
} // Notify Contributor that Admin has published their post.
elseif ( 'pending' === $old_status && 'publish' === $new_status && user_can( $post->post_author, 'edit_posts' ) && ! user_can( $post->post_author, 'publish_posts' ) ) {
$username = get_userdata( $post->post_author );
$url = get_permalink( $post->ID );
$subject = __( 'Your submission is now live! ', 'pending-submission-notifications' );
$message = '"' . $post->post_title . '" ' . __( 'was just published ', 'pending-submission-notifications' ) . "! \r\n\r\n";
$message .= $url;
$result = wp_mail( $username->user_email, $subject, $message );
}
}
You're correct, it does seem to be directly linked to the Gutenberg issue you linked to. (The reason why was answered in that thread here https://github.com/WordPress/gutenberg/issues/15094#issuecomment-558986406).
Essentially, if you use a plugin that adds custom meta data to a Gutenberg enabled post, the hook is fired twice for backwards compatibility to ensure that plugins that can't use the Gutenberg REST calls can still save their data.
To get your case working, you'll have to add a conditional check to your script to make sure you're running it on the correct pass (ie the non Rest call)
add_action( 'transition_post_status', 'pending_submission_notifications_send_email', 10, 3 );
function pending_submission_notifications_send_email( $new_status, $old_status, $post ) {
// If this is running in the Gutenberg REST call, ignore it
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { return false; }
// Notify Admin that Contributor has written a post.
if ( 'pending' === $new_status && user_can( $post->post_author, 'edit_posts' ) && ! user_can( $post->post_author, 'publish_posts' ) ) {
$pending_submission_email = 'example#email.com';
$admins = ( empty( $pending_submission_email ) ) ? get_option( 'admin_email' ) : $pending_submission_email;
$edit_link = get_edit_post_link( $post->ID, '' );
$preview_link = get_permalink( $post->ID ) . '&preview=true';
$username = get_userdata( $post->post_author );
$username_last_edit = get_the_modified_author();
$subject = __( 'New post or page pending review', 'pending-submission-notifications' ) . ': "' . $post->post_title . '"';
$message = __( 'A new post or page is pending review.', 'pending-submission-notifications' );
$message .= "\r\n\r\n";
$message .= __( 'Author', 'pending-submission-notifications' ) . ': ' . $username->user_login . "\r\n";
$message .= __( 'Title', 'pending-submission-notifications' ) . ': ' . $post->post_title . "\r\n";
$message .= "\r\n\r\n";
$message .= __( 'Edit the submission', 'pending-submission-notifications' ) . ': ' . $edit_link . "\r\n";
$message .= __( 'Preview the submission', 'pending-submission-notifications' ) . ': ' . $preview_link;
$result = wp_mail( $admins, $subject, $message );
} // Notify Contributor that Admin has published their post.
elseif ( 'pending' === $old_status && 'publish' === $new_status && user_can( $post->post_author, 'edit_posts' ) && ! user_can( $post->post_author, 'publish_posts' ) ) {
$username = get_userdata( $post->post_author );
$url = get_permalink( $post->ID );
$subject = __( 'Your submission is now live! ', 'pending-submission-notifications' );
$message = '"' . $post->post_title . '" ' . __( 'was just published ', 'pending-submission-notifications' ) . "! \r\n\r\n";
$message .= $url;
$result = wp_mail( $username->user_email, $subject, $message );
}
}
Bear in mind this is untested, but according to the issue report linked above, this should ignore the first pass through the Gutenberg editor and only pass in the version with the correct post data.
Related
I use the One User Avatar plugin, Inside the settings, there is a check box with the title "Always use the browser file uploader to upload avatars". I tick it. But when I try to change the default avatar, it still uses WordPress media, I came across the following code in the file below :
path : /plugins/one-user-avatar/includes/class-wp-user-avatar-admin.php
public function wpua_add_default_avatar() {
global $avatar_default, $mustache_admin, $mustache_medium, $wpua_avatar_default, $wpua_disable_gravatar, $wpua_functions;
// Remove get_avatar filter
remove_filter( 'get_avatar', array( $wpua_functions, 'wpua_get_avatar_filter' ) );
// Set avatar_list variable
$avatar_list = '';
// Set avatar defaults
$avatar_defaults = array(
'mystery' => __( 'Mystery Man', 'one-user-avatar'),
'blank' => __( 'Blank', 'one-user-avatar'),
'gravatar_default' => __( 'Gravatar Logo', 'one-user-avatar'),
'identicon' => __( 'Identicon (Generated)', 'one-user-avatar'),
'wavatar' => __( 'Wavatar (Generated)', 'one-user-avatar'),
'monsterid' => __( 'MonsterID (Generated)', 'one-user-avatar'),
'retro' => __( 'Retro (Generated)', 'one-user-avatar')
);
$avatar_defaults = apply_filters( 'avatar_defaults', $avatar_defaults );
// No Default Avatar, set to Mystery Man
if ( empty( $avatar_default ) ) {
$avatar_default = 'mystery';
}
// Take avatar_defaults and get examples for unknown#gravatar.com
foreach ( $avatar_defaults as $default_key => $default_name ) {
$avatar = get_avatar( 'unknown#gravatar.com', 32, $default_key );
$selected = ( $avatar_default == $default_key ) ? ' checked="checked" ' : '';
$avatar_list .= sprintf(
'<label><input type="radio" name="avatar_default" id="avatar_%1$s" value="%1$s" %2$s/> ',
esc_attr( $default_key ),
$selected
);
$avatar_list .= preg_replace( "/src='(.+?)'/", "src='\$1&forcedefault=1'", $avatar );
$avatar_list .= ' ' . $default_name . '</label>';
$avatar_list .= '<br />';
}
// Show remove link if custom Default Avatar is set
if ( ! empty( $wpua_avatar_default ) && $wpua_functions->wpua_attachment_is_image( $wpua_avatar_default ) ) {
$avatar_thumb_src = $wpua_functions->wpua_get_attachment_image_src( $wpua_avatar_default, array( 32, 32 ) );
$avatar_thumb = $avatar_thumb_src[0];
$hide_remove = '';
} else {
$avatar_thumb = $mustache_admin;
$hide_remove = ' class="wpua-hide"';
}
// Default Avatar is wp_user_avatar, check the radio button next to it
$selected_avatar = ( 1 == (bool) $wpua_disable_gravatar || 'wp_user_avatar' == $avatar_default ) ? ' checked="checked" ' : '';
// Wrap WPUA in div
$avatar_thumb_img = sprintf( '<div id="wpua-preview"><img src="%s" width="32" /></div>', esc_url( $avatar_thumb ) );
// Add WPUA to list
$wpua_list = sprintf(
'<label><input type="radio" name="avatar_default" id="wp_user_avatar_radio" value="wp_user_avatar" %s /> ',
$selected_avatar
);
$wpua_list .= preg_replace( "/src='(.+?)'/", "src='\$1'", $avatar_thumb_img );
$wpua_list .= ' ' . __( 'One User Avatar', 'one-user-avatar' ) . '</label>';
$wpua_list .= '<p id="wpua-edit"><button type="button" class="button" id="wpua-add" name="wpua-add" data-avatar_default="true" data-title="' . __( 'Choose Image', 'one-user-avatar' ) . ': ' . __( 'Default Avatar', 'one-user-avatar' ) . '">' . __( 'Choose Image', 'one-user-avatar' ) . '</button>';
$wpua_list .= '<span id="wpua-remove-button"' . $hide_remove . '>' . __( 'Remove', 'one-user-avatar' ) . '</span><span id="wpua-undo-button">' . __( 'Undo', 'one-user-avatar' ) . '</span></p>';
$wpua_list .= '<input type="hidden" id="wp-user-avatar" name="avatar_default_wp_user_avatar" value="' . $wpua_avatar_default . '">';
$wpua_list .= '<div id="wpua-modal"></div>';
if ( 1 != (bool) $wpua_disable_gravatar ) {
return $wpua_list . '<div id="wp-avatars">' . $avatar_list . '</div>';
} else {
return $wpua_list . '<div id="wp-avatars" style="display:none;">' . $avatar_list . '</div>';
}
}
How can I disable WordPress media and choose and upload a file from my computer?
I found the following code :
$wpua_list .= '<p id="wpua-edit"><button type="button" class="button" id="wpua-add" name="wpua-add" data-avatar_default="true" data-title="' . __( 'Choose Image', 'one-user-avatar' ) . ': ' . __( 'Default Avatar', 'one-user-avatar' ) . '">' . __( 'Choose Image', 'one-user-avatar' ) . '</button>';
I replaced it with the following code :
$wpua_list .= '<p id="wpua-edit"><input name="wpua-file" id="wpua-file" type="file"><button type="submit" class="button" id="wpua-upload" name="wpua-upload" data-avatar_default="true" data-title="' . __( 'Upload', 'one-user-avatar' ) . ': ' . __( 'Default Avatar', 'one-user-avatar' ) . '">' . __( 'Upload', 'one-user-avatar' ) . '</button>';
But when I go to wp-admin/options-discussion.php address and select and upload a photo from the computer, nothing is uploaded.
Where am I doing wrong? Thank you for taking the time to read my question.
I am using the following code which works fine.
function send_comment_email_notification( $comment_ID, $commentdata ) {
$comment = get_comment( $comment_id );
$postid = $comment->comment_post_ID;
$master_email = 'email#gmail.com';
var_dump($commentdata);
if( isset( $master_email ) && is_email( $master_email ) ) {
$message = 'New comment on ' . get_the_title( $postid ) . '';
add_filter( 'wp_mail_content_type', create_function( '', 'return "text/html";' ) );
wp_mail( $master_email, 'New Comment', $message );
}
}
add_action( 'comment_post', 'send_comment_email_notification', 11, 2 );
However, I would like to send an email to the user who just reviewed on a product page so I can offer them a coupon and a thank you for giving a review.
The problem is the $master_email variable, that is "hard coded". I need to capture the email entered by the user after he/she submitted the product review
Any advice?
To get the email entered by the user after he/she submitted the product review, you can use $commentdata['comment_author_email']
So you get:
function action_comment_post( $comment_ID, $comment_approved, $commentdata ) {
// Isset
if ( isset ( $commentdata['comment_author_email'] ) ) {
// Get author email
$author_email = $commentdata['comment_author_email'];
if ( is_email( $author_email ) ) {
// Post ID
$post_id = $commentdata['comment_post_ID'];
// Send e-mail
$to = $author_email;
$subject = 'The subject';
$body = sprintf( __(' Thank you for giving a review on %s', 'woocommerce' ), '' . get_the_title( $post_id ) . '' );
$headers = array( 'Content-Type: text/html; charset=UTF-8' );
wp_mail( $to, $subject, $body, $headers );
}
}
}
add_action( 'comment_post', 'action_comment_post', 10, 3 );
So I almost got it, but this last detail of specifying WooCommerce emails is leaving my head in a bit of a knot here.
I need to show ACF (advanced custom fields) fields of products (in this case it's a custom shipping time)
But only in the new order email (processing order and waiting payment order sent to the client) and then new order email to admin.
This was the main way I found: "Display product ACF field value in Woocommerce transaction emails" Thank you in advance #LoicTheAztec
I also added some conditional settings to it (mind me my PHP is very beginning copy-pasty)
which are working pretty well.
However what I can't get around is making it work only on new order emails.
I have it setup like this, and it works, however it shows on all emails that contain the email order details, and I can't have the shipping time showing on the completed order emails as it will create confusion.
// Display product ACF custom field value shipping in email notification
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 2 );
function custom_order_item_name( $item_name, $item ) {
// Targeting email notifications only
if ( 'new_order' == $email->id )
return $item_name;
// Get the WC_Product object (from order item)
$product = $item->get_product();
$othershipping = get_field( 'shipping_custom', $product->get_id());
if( $shpng_value = get_field('shipping_', $product->get_id())== "24h") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>Get it tomorrow(24h)</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "2-5 days") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>2-5 days</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "other") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . $othershipping . '</p>';
}
return $item_name;
}
I have tried switching the
if ( 'new_order' == $email->id )
to
if ( 'new_order' != $email->id )
But that just makes it not work anywhere.
I also thought it could be this part
function custom_order_item_name( $item_name, $item ) {
Where I need to add ($order, $sent_to_admin, $plain_text, $email )
function custom_order_item_name( $item_name, $item, $order, $sent_to_admin, $plain_text, $email )
But it makes the email return an error.
Normally this should work with the code below
Note: my answer is largely based on: "Customize order item meta only for WooCommerce admin email notifications". CREDITS: #Loictheaztec so don't forget to upvote that answer to!
// Setting the "sent_to_admin" as a global variable
function email_order_id_as_a_global($order, $sent_to_admin, $plain_text, $email) {
$GLOBALS['email_data'] = array(
'sent_to_admin' => $sent_to_admin, // <== HERE we set "$sent_to_admin" value
'email_id' => $email->id, // The email ID (to target specific email notification)
);
}
add_action('woocommerce_email_before_order_table', 'email_order_id_as_a_global', 1, 4);
function custom_order_item_name( $item_name, $item ) {
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
// Getting the custom 'email_data' global variable
$refNameGlobalsVar = $GLOBALS;
$email_data = $refNameGlobalsVar['email_data'];
// Only for new order
if( is_array( $email_data ) && $email_data['email_id'] == 'new_order' ) {
// Get the WC_Product object (from order item)
$product = $item->get_product();
$othershipping = get_field( 'shipping_custom', $product->get_id());
if( $shpng_value = get_field('shipping_', $product->get_id())== "24h") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>Get it tomorrow(24h)</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "2-5 days") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>2-5 days</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "other") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . $othershipping . '</p>';
}
}
}
return $item_name;
}
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 2 );
I'm a designer (not a developer) working on a Wordpress site for a customer. Using the ACF-plugin I've set up a custom field on media files for photo credits. This works fine on featured images, where I can call it in single.php like this:
$post_thumbnail = get_post(get_post_thumbnail_id());
$credit = get_field('media_credit', $post_thumbnail);
if($credit):
echo '<div class="media-credit"><p>Photo: '.$credit.'</p></div>';
endif;
So I know the custom field works, and outputs the right data. However, I can't get it to work on image attachments in posts. What I have is this:
add_filter( 'img_caption_shortcode', 'my_img_caption_shortcode', 10, 3 );
function my_img_caption_shortcode( $empty, $attr, $content ){
$attr = shortcode_atts( array(
'id' => '',
'align' => 'alignnone',
'width' => '',
'caption' => ''
), $attr );
if ( 1 > (int) $attr['width'] || empty( $attr['caption'] ) ) {
return '';
}
if ( $attr['id'] ) {
$attr['id'] = 'id="' . esc_attr( $attr['id'] ) . '" ';
}
//OUTPUT CREDIT
$photographer = get_field( 'media_credit', $attachment_id );
if ($photographer):$media_byline = '<br/><span class="media-credit">Photo: '.$photographer.'</span>';endif;
return '<div ' . $attr['id']
. 'class="wp-caption ' . esc_attr( $attr['align'] ) . '" '
. do_shortcode( $content )
. '<p class="wp-caption-text">' . $attr['caption'] . '' . $media_byline . '</p>'
. '</div>';
}
If I remove the if-statement in OUTPUT it shows «Photo: » within the captions, after the text like it should, but it doesn't get any data. What am I missing?
(BTW – I know there are plugins that outputs image credits, but they tend to have styles and features I have to override, resulting in a spaghetti mess I'd hate to hand over to the next guy working on this site.)
Finally got this to work! :-D Instead of using $attachment_id, I got the ID from $attr, and then stripped the 'attachment_' prefix from output.
I also made separate fields for photographer and bureau, but I guess that's beside the point.
Here is the code:
function my_img_caption_shortcode( $empty, $attr, $content ){
$attr = shortcode_atts( array(
'id' => '',
'align' => 'alignnone',
'width' => '',
'caption' => ''
), $attr );
if ( 1 > (int) $attr['width'] || empty( $attr['caption'] ) ) {
return '';
}
$credit_id = $attr['id'];
$credit_id = str_replace( 'attachment_', '', $credit_id );
$photographer = get_field( 'media_credit', $credit_id );
$bureau_credit = get_field( 'media_bureau', $credit_id );
if ( $photographer && $bureau_credit ): $dash = ' / ';
endif;
if ( $photographer || $bureau_credit ): $media_byline = '<br/><span class="media-credit">PHOTO: '
. $photographer . ''
. $dash . '<span class="bureau-credit">'
. $bureau_credit
. '</span></span>';
endif;
return '<div id="attachment_' . $credit_id . '"'
. 'class="wp-caption ' . esc_attr( $attr['align'] ) . '" '
. do_shortcode( $content )
. '<p class="wp-caption-text">' . $attr['caption'] . '' . $media_byline . '</p>'
. '</div>';
}
add_filter( 'img_caption_shortcode', 'my_img_caption_shortcode', 10, 3 );
This solution is something I lifted from the AFC Media Credit-plugin, so credits to the developer.
I hope this is useful for anybody who wants to achieve something similar.
I seem to be having trouble with another piece of what seems to be super basic PHP, but it just won't work for me.
My client (real estate website) needs to be able to have properties with no price to be either “price upon request” OR “auction”. Currently, leaving the price field blank only allows for one.
I tried changing the following code:
$listing_price_labels = array(
‘sold’ => __( ‘Sold’, ‘wpsight’ ),
‘rented’ => __( ‘Rented’, ‘wpsight’ ),
‘request’ => __( ‘Price on request’, ‘wpsight’ ),
‘auction’ => __( ‘Auction’, ‘wpsight’ ), ***– Added this line***
);
And where this code is found…
if( is_admin() )
$listing_price .= ‘<br />’ . wpsight_get_price_value();
} elseif( empty( $listing_price ) ) {
// When no price available Price on request
$listing_price = ‘<span class=”listing-price-on-request”>’ . $listing_price_labels['request'] . ‘</span><!– .listing-price-on-request –>’;
} elseif( $listing_price = ‘auction’ ) {
// When price field contains ‘auction’ (case sensitive)
$listing_price = ‘<span class=”listing-price-on-request”>’ . $listing_price_labels['auction'] . ‘</span><!– .listing-price-on-request –>’;
}
function wpsight_get_price( $post_id = '' ) {
// Get post ID from $post_id
if( empty( $post_id ) )
$post_id = get_the_ID();
// If still empty, return false
if( empty( $post_id ) )
return false;
// Set listing price labels
$listing_price_labels = array(
'sold' => __( 'Sold', 'wpsight' ),
'rented' => __( 'Rented', 'wpsight' ),
'request' => __( 'Price on request', 'wpsight' ),
'auction' => __( 'Auction', 'wpsight' ),
);
$listing_price_labels = apply_filters( 'wpsight_get_price_labels', $listing_price_labels );
// Get listing price
$listing_price = wpsight_get_price_value();
// Get custom fields
$custom_fields = get_post_custom( $post_id );
$listing_status = isset( $custom_fields['_price_status'][0] ) ? $custom_fields['_price_status'][0] : false;
$listing_availability = isset( $custom_fields['_price_sold_rented'][0] ) ? $custom_fields['_price_sold_rented'][0] : false;
// Create price output
if( ! empty( $listing_availability ) ) {
// When listing is not available
$sold_rented = ( $listing_status == 'sale' ) ? $listing_price_labels['sold'] : $listing_price_labels['rented'];
// Display sold/rented bold red in admin
$style = is_admin() ? ' style="color:red;font-weight:bold"' : false;
$listing_price = '<span class="listing-price-sold-rented"' . $style . '>' . $sold_rented . '</span><!-- .listing-price-sold-rented -->';
if( is_admin() )
$listing_price .= '<br />' . wpsight_get_price_value();
} elseif( empty( $listing_price ) ) {
// When no price available Price on request
$listing_price = '<span class="listing-price-on-request">' . $listing_price_labels['request'] . '</span><!-- .listing-price-on-request -->';
} elseif( $listing_price == "auction" ) {
// When price field contains 'auction' (case sensitive)
$listing_price = '<span class="listing-price-on-request">' . $listing_price_labels['auction'] . '</span><!-- .listing-price-on-request -->';
}
return apply_filters( 'wpsight_listing_price', $listing_price );
}
I’m sure my syntax must just be wrong, because with that code in place it makes any property with anything at all written into the price field display “auction”.
Can anyone see what I've done wrong?
try:
if( is_admin() ){
$listing_price .= ‘<br />’ . wpsight_get_price_value();
} elseif( empty( $listing_price ) ) {
// When no price available Price on request
$listing_price = ‘<span class=”listing-price-on-request”>’ . $listing_price_labels['request'] . ‘</span><!– .listing-price-on-request –>’;
}
btw its not recommended to use if( is_admin() ) since its only applicable on 1 line.