Получение полей acf в действии publish_post для wp_mail

Вопрос или проблема

У меня есть пользовательский тип записи под названием “Envios”. В нем я создал индивидуальное мета-поле, которое позволяет выбирать пользователей и записи. Когда один из этих пользовательских типов записей публикуется, он отправляет электронное письмо выбранным пользователям с содержимым выбранных записей.
Для выбора записей я использую плагин ACF с полем Post Object.

Проблема в том, что иногда письма отправляются правильно, но в большинстве случаев ничего не доставляется.

Вот код:

    // Добавляет пользовательское мета-поле
    function email_delivery_munda_add_custom_box() {
        $screens = ['envios', 'md_cpt'];
        foreach ($screens as $screen) {
            add_meta_box(
                'md_email_delivery_box_id',           // Уникальный ID
                'Detalles de email',                  // Заголовок поля
                'md_email_delivery_custom_box_html',  // Callback содержимого, должен быть типа callable
                $screen,                              // Тип записи
                'side',
                'default'
            );
        }
    }
    add_action('add_meta_boxes', 'email_delivery_munda_add_custom_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();
            // Массив объектов WP_User.
            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

    }

    // Сохраняет данные записи
    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');


    // Отправляет письмо, когда публикуется пользовательский тип записи Envios
    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="";

        // Удаление отсюда заставляет работать.
        $posts = get_field('casos',$post_id);

        if( $posts ): ?>
            <?php foreach( $posts as $post): // переменная должна называться $post (ВАЖНО) ?>
                <?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(); // ВАЖНО - перезагрузка объекта $post, чтобы остальная часть страницы работала правильно ?>
        <?php endif;
        // до сюда.


        $clients_list = "[email protected]";

        wp_mail( $clients_list, $asunto , $content, $headers );

    }
    add_action('publish_envios', 'md_email_publish_postdata', 10, 2 );

Если я удалю часть ACF из // Удаление отсюда заставляет работать. до // до сюда. письма отправляются корректно каждый раз, но без содержимого выбранных записей.

Я не могу точно сказать, в чем проблема, но, возможно, вы сможете дать какие-то советы на эту тему.
Заранее спасибо!


РЕШЕНИЕ:

ACF использует экшен acf/save_post ПОСЛЕ того, как запись опубликована, так что я пытался получить значение, которое еще не было доступно.
Поэтому я изменил экшен на acf save_post, и внутри него использую if (get_post_status($post_id) == 'publish') {, чтобы проверить статус записи.

Кроме того, я обновляю вывод Object Post следующим образом:

  $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;

…Удалил свои предыдущие ‘решения’…


Итак, реальная проблема здесь заключается в том, что эта функция привязана к экшену publish_post, в этот момент может быть так, что запись еще не сохранена, если это новая запись. Только если это запись, которая уже была сохранена, но с другим статусом, мы можем получить значения ACF, используя get_field().

Решение может заключаться в использовании хука acf/save_post с приоритетом 10 или более, так как он выполняется после того, как запись была сохранена, что позволяет нам получить значения, используя get_field().

Вот короткий пример использования этого хука:

function my_acf_save_post( $post_id ) {

    // выход, если неверный тип записи
    if( get_post_type( $post_id ) !== 'envios' ) {
         return;
    }

    // получать новое значение
    $posts = get_field( 'casos', $post_id );


    // что-то сделать

}

add_action('acf/save_post', 'my_acf_save_post', 20);

И даже если я изменю свой add_action на webhook “save_post_post-type” вместо webhook “publish_post-type”, поля acf по-прежнему не заполнены до тех пор, пока запись не опубликована и затем обновлена!

.

Ответ или решение

Ваша задача заключается в корректной отправке email-сообщений при публикации пользовательского типа записей "Envios" в WordPress, используя мета-поля, созданные с помощью ACF (Advanced Custom Fields). Однако вы столкнулись с проблемой, когда письма не всегда отправляются корректно, особенно если данные ACF ещё не сохранены в момент вызова функции отправки email.

Теория

Проблема заключается в последовательности выполнения хуков в WordPress. Когда вы используете действие publish_post, оно срабатывает до того, как данные, установленные ACF, будут сохранены в базе данных. Это означает, что в вашей функции отправки email данные ещё недоступны. Решение состоит в том, чтобы использовать более подходящий хук, который сработает после сохранения данных.

ACF предоставляет хук acf/save_post, который можно использовать для выполнения действий после того, как все данные полей ACF были успешно сохранены. Это позволит гарантировать, что все необходимые данные доступны для чтения и использования.

Пример

Рассмотрим, как именно можно интегрировать данное решение в существующую структуру вашего кода. Вместо стандартного использования publish_post, мы будем использовать acf/save_post, что даёт гарантию, что данные полей ACF надёжно сохранены к моменту выполнения вашей логики отправки email.

function my_acf_save_post( $post_id ) {
    // Исключаем обработку авто-сохранений и недопустимых типов записей
    if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) || get_post_type( $post_id ) !== 'envios' ) {
        return;
    }

    // Проверяем, опубликован ли пост
    if ( get_post_status( $post_id ) == 'publish' ) {
        // Получаем значения полей ACF
        $posts = get_field( 'casos', $post_id );

        if ($posts) {
            $content = "";

            foreach ($posts as $post) {
                setup_postdata($post);
                $content .= '<h1>' . get_the_title($post) . '</h1><br>';
                $descripcion = get_field('descripcion_breve', $post->ID);
                if ($descripcion) {
                    $content .= '<p>' . $descripcion . '</p><br>';
                } else {
                    $content .= '<p>Description empty</p><br>';
                }
            }

            wp_reset_postdata();

            // Отправка email
            $asunto = sanitize_text_field($_POST['email_delivery_asunto']);
            $headers = array(
                'Content-Type: text/html; charset=UTF-8'
            );

            $receptores = $_REQUEST['clients-email-input'];
            foreach ($receptores as $email) {
                if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
                    wp_mail($email, $asunto, $content, $headers);
                }
            }

            // Обновляем мета-данные с указанием, кому было отправлено
            update_post_meta($post_id, 'email_send', implode(", ", $receptores));
        }
    }
}

add_action('acf/save_post', 'my_acf_save_post', 20);

Применение

При использовании этого метода важно понимать, что вы запланируете отправку email только после того, как данные ACF будут надёжно сохранены. В результате, вы избегаете ошибки, когда данные ещё не были записаны при публикации. Использование acf/save_post гарантирует, что все изменения, сделанные через мета-поля, будут доступны и корректно обработаны.

Таким образом, ваша система теперь работает на более надёжной основе, минимизируя риск некорректной обработки данных и обеспечивая своевременную отправку email при всех необходимых условиях. Это пример улучшенной обработки пользовательских действий и синхронизация с процессами сохранения данных в WordPress.

Теперь, благодаря этому подходу, вы должны ощутить значительное улучшение в стабильности и надежности вашей системы уведомлений по email.

Оцените материал
Добавить комментарий

Капча загружается...