I have a custom post type called "Envios". In it I've created a Custom Meta box which allows to select users and posts. When one of this custom post types is published it sends an email to the selected users with the content of the selected posts. To select the posts I use the ACF plugin, with the field Post Object.
The issue is that sometimes the emails are sent properly but in most cases nothing is delivered.
Here is the code:
// Adds Custom Meta Box
function email_delivery_munda_add_custom_box() {
$screens = ['envios', 'md_cpt'];
foreach ($screens as $screen) {
add_meta_box(
'md_email_delivery_box_id', // Unique ID
'Detalles de email', // Box title
'md_email_delivery_custom_box_html', // Content callback, must be of type callable
$screen, // Post type
'side',
'default'
);
}
}
add_action('add_meta_boxes', 'email_delivery_munda_add_custom_box');
// Adds the content of the Custom Meta Box
function md_email_delivery_custom_box_html($post)
{
$asunto = get_post_meta($post->ID, 'email_delivery_asunto', true);
wp_nonce_field( 'save_md_email', 'md_email_nonce' );
if ($asunto == "") {
$asunto = "Informe - " . date("d-m-Y");
}
?>
<div class="email-delivery-asunto">
<label for="email_delivery_asunto">Asunto</label>
<input type="text" name="email_delivery_asunto" id="email_delivery_asunto" class="postbox" value=" <?php echo $asunto ?>" placeholder="Informe - <?php echo date("d-m-Y") ?>">
</div>
<div class="email-delivery-receptores">
<label for="select-emails">Destinatarios</label>
<?php
$blogusers = get_users();
// Array of WP_User objects.
echo '<select name="clients-email-input[]" id="select-emails" class="admin-email-receptores" multiple="multiple"><option></option>';
foreach ( $blogusers as $user ) {
echo '<option value="'. esc_html( $user->user_email ) .'">' . esc_html( $user->display_name ) . '</option>';
}
echo '</select>';
?>
</div>
<?php $enviados = get_post_meta($post->ID, 'email_send', true); ?>
<div class="email-delivery-asunto">
<label for="email_send">Ultimo envio</label>
<p id="email_send"><?php echo $enviados ?></p>
</div>
<?php
}
// Saves post data
function md_email_save_postdata($post_id) {
if ( ! isset( $_POST['md_email_nonce'] ) ) {
return $post_id;
}
if ( ! wp_verify_nonce( $_POST['md_email_nonce'], 'save_md_email' ) ) {
return $post_id;
}
$asunto = sanitize_text_field( $_POST['email_delivery_asunto'] );
update_post_meta( $post_id, 'email_delivery_asunto', $asunto );
}
add_action('save_post', 'md_email_save_postdata');
// Sends an email when custom post type Envios is published
function md_email_publish_postdata($post_id) {
$asunto = sanitize_text_field( $_POST['email_delivery_asunto'] );
$headers = array(
'Content-Type: text/html; charset=UTF-8'
);
$enviados = sanitize_text_field( $_POST['email_send'] );
$blogusers = get_users();
foreach ($_REQUEST['clients-email-input'] as $selectedOption) {
array_push($headers, "BCC:" . $selectedOption);
foreach ( $blogusers as $user ) {
if ($user->user_email === $selectedOption) {
$enviados .= "<b>" . esc_html( $user->display_name ) . "</b> " . esc_html( $user->user_email) . "<br>";
}
}
}
update_post_meta( $post_id, 'email_send', $enviados );
$content = '';
// Removing from here makes it work.
$posts = get_field('casos',$post_id);
if( $posts ): ?>
<?php foreach( $posts as $post): // variable must be called $post (IMPORTANT) ?>
<?php setup_postdata($post);
$content .= '<h1>' . get_the_title( $post ) . '</h1><br>';
$content .= '<p>' . get_field( 'descripcion_breve', $post) . '</p><br>';
endforeach; ?>
<?php wp_reset_postdata(); // IMPORTANT - reset the $post object so the rest of the page works correctly ?>
<?php endif;
// until here.
$clients_list = "[email protected]";
wp_mail( $clients_list, $asunto , $content, $headers );
}
add_action('publish_envios', 'md_email_publish_postdata', 10, 2 );
IF I remove the ACF part from // Removing from here makes it work. to // until here. the emails are sent okay every time but without the selected posts content.
I can't really tell which is the problem, but maybe you can impart some wisdom on the matter. Thanks in advance!
SOLUTION:
ACF use the action acf/save_post AFTER the post is published, so I was trying to get a value that wasn't there yet.
So I changed the action to the acf save_post and between it I use if (get_post_status($post_id) == 'publish') {
to check the status of the post.
Furthermore I update the Object Post output as follows:
$posts = get_field( 'casos', $post_id );
if( $posts ):
foreach( $posts as $post):
$content .= '<h1>' . get_the_title( $post ) . '</h1><br>';
if ( get_field( 'descripcion_breve', $post->ID )) {
$content .= '<p>' . get_field( 'descripcion_breve', $post->ID ) . '</p><br>';
} else {
$content .= '<p>Description empty</p><br>';
}
endforeach;
endif;
setup_postdata
andwp_reset_postdata
are for front-end queries, they won't work reliably (or at all) on most admin pages.ACF use the action acf/save_post AFTER the post is published
- that is not entirely correct, it depends on the priority given. If the priority is less than 10, then it is called before the post save, but if it is greater than 10, it is called after the post is saved. Check the official documentation.