【问题标题】:Thread without access to WordPress functions无法访问 WordPress 功能的线程
【发布时间】:2017-09-26 11:02:43
【问题描述】:

管理员或编辑可以通过我们为个人定制的 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'

【问题讨论】:

    标签: php wordpress pthreads


    【解决方案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 函数,而 get_option 函数又具有用于 DB 访问的全局。所以你会遇到和上面一样的问题。

    鉴于 WordPress 代码库中无处不在的全局变量,线程在这里根本行不通……

    【讨论】:

    • $email_array 是我的一个错字,我简化了代码以在此处发布。当运行线程 WordPress 已经加载但线程无法调用 WP 函数时,我添加了一个编辑与我刚刚尝试过的测试线程,它在线程中调用 update_option 没有进行它应该的更改.删除第一个 update_option 时,数据库中的值保持不变。我想问题是线程看不到 WP 函数,因为它的小线程 WP 没有加载,也许我错了。
    • @PeterBushnell 我已根据您的更新更新了我的答案。
    • 感谢您的澄清。我热衷于使用经过过滤的 wp_mail 来为每封电子邮件添加退订链接。我将使用更传统的解决方案(如 AJAX)并更新页面以向管理员显示工作正在进行中,而不是离开页面。
    【解决方案2】:

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

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

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

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

    示例插件:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多