线程无法访问WordPress功能

时间:2017-04-28 10:44:42

标签: php wordpress pthreads

管理员或编辑可以通过我们为个人定制的WordPress插件向用户发送电子邮件,以便电子邮件单独发送,这可以使页面等待一段时间以完成邮件处理。计划是多线程将用户返回到页面并让电子邮件继续在服务器上发送。问题似乎是缺少从线程的run()函数访问WordPress的'wp_mail()函数。调用wp-load.php似乎无法访问WordPress函数。

以下是线程邮件的简化版本。我们如何使用Test_Mailer线程中的wp-mail()函数?

class Test_Mailer extends Thread {
    private $email;

    public function __construct($emails, $subject, $message) {
        $this->emails = $emails;
        $this->subject = $subject;
        $this->message = $message;
    }

    public function run() {
        require( '../../../wp-load.php' );

        foreach($this->emails as $email)
            wp_mail( $email, $this->subject, $this->message);
    }
}

$test_mailer = new test_mailer(array('test@test.com'), 'Subject', 'Message');
$test_mailer->start();
编辑:如果我尝试访问WordPress函数没有任何反应如下所示,这让我觉得WP没有加载,但我没有在PHP错误日志中得到任何错误。

class Test_Thread extends Thread {
    public function run() {
        update_option('test', 'two');
    }
}

update_option('test', 'one');
$test_thread = new test_mailer();
$test_thread->start();
// test option is set to 'one'

2 个答案:

答案 0 :(得分:1)

您正在使用require( '../../../wp-load.php' );重新加载WordPress。这就是Ajax的用途。

以下示例的内容是操作wp_ajax_(已记录的用户)和wp_ajax_nopriv_(未记录的用户)。这些是通过JavaScript调用执行的PHP操作,在您的情况下为wp_mail()

您必须将JS文件排入正确的页面,并通过wp_localize_script(Ajax URL,安全现时,自定义内容)传递一些变量。

它会创建一个管理页面,其中包含提示输入电子邮件的链接。该地址将传递给发送电子邮件的Ajax函数,并根据true结果返回falsewp_mail()

示例插件:

<?php
/** 
  * Plugin Name: (B5F) Test Email
  * Version: 1.0
  * Author: brasofilo
  */

add_action('admin_menu', 'add_menu_43678305');
add_action( 'wp_ajax_mail_43678305', 'mail_43678305' ); 
add_action( 'wp_ajax_nopriv_mail_43678305', 'mail_43678305' );

function add_menu_43678305() {
    $page = add_menu_page( 
        'sendMail', 
        '<span style="color:#d00;">Send Mail</span>', 
        'read', 
        'send-mail', 
        'menu_page_43678305', 
        'http://i.imgur.com/Vk42k.png', 
        6 // position, just after Posts
    );
    add_action( "admin_print_scripts-$page", 'enqueue_scripts_43678305' );
}

function enqueue_scripts_43678305(){
    wp_enqueue_script( 
        'ajax_script', 
        plugins_url('/ajax_43678305.js',__FILE__), 
        array('jquery'), 
        TRUE 
    );
    wp_localize_script( 
        'ajax_script', 
        'myAjax', 
        array(
            'url'   => admin_url( 'admin-ajax.php' ),
            'nonce' => wp_create_nonce( "nonce_43678305" ),
        )
    );
}

function menu_page_43678305() {
    echo '<h4><a href="#" id="send-mail">TEST AJAX</a></h4>';
}
function mail_43678305(){
    check_ajax_referer( 'nonce_43678305', 'nonce' );

    if( true ) { // Dummy test
        $sent = wp_mail( $_POST['email'], "Subject", "message" );
        wp_send_json_success( $sent );
    }
    else
        wp_send_json_error( array( 'error' => $custom_error ) );
}

JS文件:

jQuery(document).ready(function($) {
    $('#send-mail').click(function(e) {
        e.preventDefault();
        var email = window.prompt('Email?');
        if ( email === '' || email === null )
            return;

        var data = {
            action: 'mail_43678305', // Ajax PHP function
            nonce: myAjax.nonce, // security, passed via wp_localize_script
            email: email
        };

        $.post( myAjax.url, data, function( response ) {
            $('#send-mail').html( response.data );
        });
    });
});

答案 1 :(得分:1)

在创建新线程时,pthreads将复制当前环境中可用的所有函数(以及类,接口,特征等)(除非在Thread::start中使用了选择性继承标志,课程)。这意味着如果您已经包含wp-load.php文件,那么您不需要在新线程(Thread::run)内再次包含它。 (如果你还没有包含这个文件,那么你所做的很好。)

查看示例代码,您将构造函数中的$emails参数分配给$this->emails属性。但是,foreach正在尝试迭代$this->email_array属性,该属性只是null。因此,至少从您的示例代码来看,问题在于您正在访问的属性,而不是wp_mail函数无法访问。

尽管如此,看起来你似乎试图在Web服务器环境中使用pthread。这有其自身的影响,简直是一个坏主意。你最好排队这些任务(通过RabbitMQ或其他东西)在其他地方处理它们。

更新(来自您的更新):

简要介绍一下WordPress代码库,我可以看到线程在这里根本不起作用。代码库对这种并发技术非常不友好。

update_option函数不起作用,因为它依赖于全局数据库连接。此连接不能在不同的上下文(线程)中使用 - 相反,必须为每个线程创建一个新连接。

wp_mail函数使用get_bloginfo函数,后者又使用get_option函数,该函数又具有全局数据库访问权限。因此,您将遇到与上述相同的问题。

鉴于WordPress代码库中全局变量无处不在,线程在这里根本不起作用......

相关问题