wp_mail function timing out

时间:2012-11-29 作者:GhostToast

我有以下功能。这是基于成员资格的网站的一部分。当类型为“message”的帖子移动到发布状态时,它应该向属于该地区的所有用户(自定义用户元)发送一封电子邮件,这些用户在起草帖子时会被选中(分类法)。

如果我发送给一个小组,它似乎会起作用。如果我发送到所有地区,它会挂起,并且似乎没有消息传出。我试着把它分成小块(25)来减轻疼痛,但没有帮助。除了告诉客户一次只发送给一个组之外,还有什么想法吗?

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);
    }

}

2 个回复
最合适的回答,由SO网友:beporter 整理而成

好吧,这本身并不是一个完整的解决方案,但我将从隔离问题是SQL查询还是wp_mail() 呼叫如果您注释掉wp_mail() 第行,您可以了解函数运行查询和构建消息所需的时间,而无需尝试发送它们。

如果您突然发现该功能的速度非常快,那么可以肯定的是,邮件连接会让您的速度变慢,但不幸的是,这会打开另一罐蠕虫,因为电子邮件配置可能因web主机而异。

另一方面,如果函数同样慢,那么查询很可能是罪魁祸首,那么查看Wordpress生成的实际SQL将非常有帮助,以尝试识别性能泄漏。

编辑:

听起来好像是查询在进行许多连接。在这种情况下,目标是避免这种情况。我们可以利用这样一个事实,即我们正在寻找相同的不同案例wp_usermeta.meta_key 用于构建不需要所有联接的查询的值:

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);
    }

}
有几件事没有考虑在内,因为我面前没有这个特定的WP实例可供测试:

无论调用什么\\u CUSTOM\\u QUERY\\u METHOD\\u。用任何正确的方法替换此方法get_users() 已提供foreach($district_members as $district_member). 这个user_can() 方法是对每个正在循环的用户进行2次不必要的DB命中。您已经在查询返回的结果中拥有了用户的功能,请改用它

SO网友:Chris

在我看来,也许在你的PHP运行超过PHP之后,它就挂了。ini的脚本超时限制。

结束

相关推荐

如何将php自定义页面添加到wordpress

我想为我的Wordpress博客创建一个自定义页面,在其中执行我的php代码,同时保留整个网站css/主题/设计的一部分。php代码将使用第三方API(因此我需要包括其他php文件)我如何做到这一点?N、 B.我没有与Wordpress API交互的特定需要-除了包含某些其他需要的php lib之外,我在希望包含在WP页面中的php代码中没有其他依赖项。所以很明显,任何不需要学习WP api的解决方案都是最好的。请帮我解决这个问题。