web-dev-qa-db-fra.com

la fonction wp_mail arrive à expiration

J'ai la fonction suivante. Cela fait partie d'un site à base d'adhésion. Lorsqu'un message de type "message" est déplacé vers le statut Publier, il doit envoyer un courrier électronique à tous les utilisateurs appartenant (méta utilisateur personnalisé) au (x) district (s) vérifié (s) (taxonomie) lors de la rédaction du message.

Si j'envoie à un petit groupe, cela semble fonctionner. Si j'envoie à tous les districts, le message est bloqué et aucun message ne semble sortir. J'ai essayé de le limiter en morceaux (25) pour soulager la douleur, mais ça n'aide pas. Avez-vous des idées à part dire au client de n’envoyer qu’un groupe à la fois?

add_action('publish_messages', 'messages_notify', 10, 3);
function messages_notify() {
    global $post;
    // if post already published, abort
    if($post->post_status == 'publish') {
        return;
    }
    // get districts ticked, else abort
    $districts = get_the_terms($post->ID, 'message_district');
    if(empty($districts)) return;

    // query members who belong to one of the districts ticked
    $the_districts = array();
    $district_args = array('relation' => 'OR' );
    foreach($districts as $district){
        $the_districts[] = $district->name;
        if ($district->name == 'Northeast') {
            $district_args[] = array('key' => 'whprms_district_ne', 'value' => 1);
        }
        if ($district->name == 'North Central') {
            $district_args[] = array('key' => 'whprms_district_nc', 'value' => 1);
        }
        if ($district->name == 'Southeast') {
            $district_args[] = array('key' => 'whprms_district_se', 'value' => 1);
        }
        if ($district->name == 'Southwest') {
            $district_args[] = array('key' => 'whprms_district_sw', 'value' => 1);
        }
        if ($district->name == 'West') {
            $district_args[] = array('key' => 'whprms_district_w', 'value' => 1);
        }
    }
    $district_members = get_users( 
            array(
            'meta_query' => $district_args,
            )
    );

    $attachment_args = array('post_type' => 'attachment', 'orderby' => 'date', 'order' => 'ASC', 'numberposts' => -1, 'post_status' => NULL, 'post_parent' =>$post->ID);
    $attachments = get_posts($attachment_args);
    if ($attachments) {
        $att_array = array();
        foreach ($attachments as $attachment) {
            $att_array[] = get_the_title($attachment->ID);
        }
    }

    // message only users with desired role(s)
    $bcc = array();
    foreach($district_members as $district_member) {
        if(user_can($district_member->ID, 'board_members') || user_can($district_member->ID, 'members')) {
            $bcc[] = $district_member->user_email;
        }
    }

    $subject = 'WHPRMS Message: '.$post->post_title;
    $message = 'New message posted by ';
    if(user_can($post->post_author, 'administrator')) {
        $message .= get_the_author_meta('user_nicename', $post->post_author)."\n\r";
    }
    else {
        $message .= get_the_author_meta('first_name', $post->post_author).' '.get_the_author_meta('last_name', $post->post_author)."\n\r"; 
    }

    $message .= 'Excerpt: '.stripslashes(substr($post->post_content, 0, 240)).'...'."\n\r";
    $message .= 'Link: '.get_permalink($post->ID)."\n\r";

    $message .= 'District(s): '.implode(', ', $the_districts)."\n\r";
    if (!empty($att_array)) {
        $message .= 'Attachment(s): '.implode(', ', $att_array)."\n\r";
    }

    $message .= 'You are receiving this message because you belong to one of the districts mentioned above.';

    $chunked_bcc = array_chunk($bcc, 25);

    foreach($chunked_bcc as $bcc_chunk){
        $headers = array();
        $headers['Bcc'] = 'BCC: '.implode(', ', $bcc_chunk);
        wp_mail('[email protected]', $subject, $message, $headers);
    }

}
3
GhostToast

Eh bien, ce n'est pas une solution complète en soi, mais je commencerais par isoler si le problème est lié aux requêtes SQL ou à l'appel wp_mail(). Si vous commentez la ligne wp_mail(), vous pouvez avoir une idée du temps nécessaire à la fonction pour exécuter les requêtes et créer les messages sans essayer de les envoyer.

Si vous constatez que la fonction est soudainement rapide, alors il est fort probable que les connexions de messagerie ralentissent votre travail, mais malheureusement, cela ouvre une autre boîte de Pandore, car les configurations de messagerie peuvent varier énormément d'un hébergeur à l'autre.

Si, par contre, la fonction est aussi lente, les requêtes sont probablement les coupables. Il serait alors très utile de voir le code SQL réel généré par Wordpress afin de tenter d'identifier la perte de performances.

MODIFIER:

On dirait que ce sont les requêtes qui font beaucoup de JOIN après tout. Dans ce cas, l'objectif est d'éviter cela. Nous pouvons tirer parti du fait que nous recherchons différents cas de la même valeur wp_usermeta.meta_key pour créer une requête qui n'a pas besoin de tous les JOIN:

function messages_notify() {
    global $post;
    // if post already published, abort
    if($post->post_status == 'publish') {
        return;
    }
    // get districts ticked, else abort
    $post_districts = get_the_terms($post->ID, 'message_district');
    if(empty($post_districts)) return;

    // Build a list of districts to get users from.
    $districts = array(
        'Northeast' => 'whprms_district_ne', 
        'North Central' => 'whprms_district_nc', 
        'Southeast' => 'whprms_district_se', 
        'Southwest' => 'whprms_district_sw', 
        'West' => 'whprms_district_w', 
        //'Another' => 'whprms_district_XX', 
    );

    $searchDistricts = array();
    $districtNames = array_keys($districts);
    foreach($post_districts as $d){
        if(in_array($d->name, $districtNames){
            $searchDistricts[] = $districts[$d->name];
        }
    }

    $districts = implode(' OR ', array_map(function($s){ return "wp_usermeta.meta_key = '{$s}'"; }, $searchDistricts));  // Squash it down into an sql-compatible WHERE subclause.

    $sql = "SELECT DISTINCT wp_users.* 
    FROM wp_users 
    INNER JOIN wp_usermeta ON (wp_users.ID = wp_usermeta.user_id) 
    WHERE 
    -- This part isolates to keys in the list of districts
    ({$districts}) 
    -- Where the value of the district is 1.
    AND CAST(wp_usermeta.meta_value AS CHAR) = '1'
    ORDER BY user_login ASC";

    $district_members = $wpdb->WHATEVER_THE_CUSTOM_QUERY_METHOD_IS_CALLED($sql);

    $attachment_args = array('post_type' => 'attachment', 'orderby' => 'date', 'order' => 'ASC', 'numberposts' => -1, 'post_status' => NULL, 'post_parent' =>$post->ID);
    $attachments = get_posts($attachment_args);
    if ($attachments) {
        $att_array = array();
        foreach ($attachments as $attachment) {
            $att_array[] = get_the_title($attachment->ID);
        }
    }

    // message only users with desired role(s)
    $bcc = array();
    foreach($district_members as $district_member) {
        // Don't use user_can()! It's a DB hit!
        //if(user_can($district_member->ID, 'board_members') || user_can($district_member->ID, 'members')) {  //@TODO:  Look at $district_member->caps
        if(in_array('board_members', $district_member->roles) || in_array('members', $district_member->roles)) {
            $bcc[] = $district_member->user_email;
        }
    }

    $subject = 'WHPRMS Message: '.$post->post_title;
    $message = 'New message posted by ';
    if(user_can($post->post_author, 'administrator')) {
        $message .= get_the_author_meta('user_nicename', $post->post_author)."\n\r";
    }
    else {
        $message .= get_the_author_meta('first_name', $post->post_author).' '.get_the_author_meta('last_name', $post->post_author)."\n\r"; 
    }

    $message .= 'Excerpt: '.stripslashes(substr($post->post_content, 0, 240)).'...'."\n\r";
    $message .= 'Link: '.get_permalink($post->ID)."\n\r";

    $message .= 'District(s): '.implode(', ', $the_districts)."\n\r";
    if (!empty($att_array)) {
        $message .= 'Attachment(s): '.implode(', ', $att_array)."\n\r";
    }

    $message .= 'You are receiving this message because you belong to one of the districts mentioned above.';

    $chunked_bcc = array_chunk($bcc, 25);

    foreach($chunked_bcc as $bcc_chunk){
        $headers = array();
        $headers['Bcc'] = 'BCC: '.implode(', ', $bcc_chunk);
        wp_mail('[email protected]', $subject, $message, $headers);
    }

}

Deux choses que cela ne prend pas en compte, car je n'ai pas devant moi cette instance particulière de WP à tester:

  • WHATEVER_THE_CUSTOM_QUERY_METHOD_IS_CALLED. Remplacez-le par quelque méthode que ce soit.
  • Je ne sais pas non plus dans quel format se retrouveront les résultats. Si vous pouvez obtenir des objets WP_user, ce serait idéal, car la section suivante dépend de $ district_users qui ressemble à ce que get_users() a fourni.
  • Faites également attention au changement de foreach($district_members as $district_member). La méthode user_can() consiste en 2 hits de base de données inutiles pour CHAQUE utilisateur sur lequel vous effectuez une boucle. Vous avez déjà les capacités de l'utilisateur dans les résultats renvoyés par la requête - utilisez-les plutôt.
2
beporter

Cela me semble peut-être suspendu après que votre PHP exécution dépasse la limite de délai d'expiration du script de PHP.ini.

4
Chris