Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

173
Views
Thread without access to WordPress functions

An Admin or Editor can send out emails to users via our WordPress Plugin customised to the individual so the emails are sent individually, this can make the page wait a while for the mailing process to finish. The plan is to multithreaded to return the user to the page and let the emails carry on sending on the server. The problem seems to be lack of access to WordPress' wp_mail() function from the thread's run() function. Calling wp-load.php does not seem to give access to WordPress functions.

Below is a simplified version of the threaded mailer. How do we use the wp-mail() function from the Test_Mailer thread?

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

EDIT: If I try accessing a WordPress function nothing happens as shown below, which makes me think that WP is not loaded, but I do not get any errors in the PHP error log.

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'
over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

You're loading WordPress all over again with that require( '../../../wp-load.php' );. That's what Ajax is for.

The meat of the following example are the actions wp_ajax_ (logged users) and wp_ajax_nopriv_ (non logged users). These are the PHP actions to execute by a JavaScript call, in your case wp_mail().

You have to enqueue the JS file in the correct page and pass some variables via wp_localize_script (Ajax URL, security nonce, custom stuff).

It creates an admin page with a link that prompts for an email. The address is passed to the Ajax function that sends the email and returns true or false depending on wp_mail() result.

Example plugin:

<?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 file:

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 );
        });
    });
});
over 4 years ago · Santiago Trujillo Report

0

When creating a new thread, pthreads will make a copy of all functions (as well as classes, interfaces, traits, etc) available from the current environment (unless selective inheritance flags have been used in Thread::start, of course). This means that if you have already included the wp-load.php file, then you do not need to include it again inside of the new thread (in Thread::run). (If you haven't included this file yet, then what you've done is fine.)

Looking at your example code, you are assigning the $emails parameter from the constructor to the $this->emails property. However, the foreach is attempting to iterate over the $this->email_array property, which will simply be null. So from your example code at least, it looks like the problem is with what property you're accessing, rather than the wp_mail function not being accessible.

With all that said, it does look like you're attempting to use pthreads in a web server environment. This has its own ramifications and is simply a bad idea. You'd be better off queueing such tasks (via RabbitMQ or something) to handle them elsewhere.

UPDATE (from your update):

Having a brief look through the WordPress codebase, I can see that threading simply isn't going to work here. The codebase is just incredibly unfriendly to such concurrency techniques.

The update_option function will not work because it relies upon a global DB connection. This connection cannot be used across different contexts (threads) - instead, a new connection must be created per thread.

The wp_mail function uses the get_bloginfo function, which in turn uses the get_option function, which in turn has a global for DB access. So you're going to have the same problem there as above.

Given the ubiquity of globals in the WordPress codebase, threading is simply not going to work here...

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!