0

I am currently making a WP widget and I am stuck with this.

I want to pass a variable $emailReceiver from my form() method to my deliver_mail() method. The problem is that my deliver_mail() method has been executed first and it gives me this error:

"Uncaught phpmailerException: Invalid address:...PHPMailer->addAddress(NULL)"

The idea is when the form displays in the widget section the user should fill the receiver's email address.

 add_action( 'widgets_init', 'contact_form_register_widget' );
 $add_action = new jpen_Custom_Form_Widget();
 $add_action->init();

function contact_form_register_widget() {
    register_widget( 'jpen_Custom_Form_Widget');

    wp_register_script( "contact-form-script-widget", WP_PLUGIN_URL.'/contact-form-widget/contact-form-script-widget.js', array('jquery') );
    wp_localize_script( 'contact-form-script-widget', 'contactFormAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' )));

    wp_enqueue_script( 'jquery' );
    wp_enqueue_script( 'contact-form-script-widget' );
}

class jpen_Custom_Form_Widget extends WP_Widget {
    //private $emailReceiver;

    public function __construct() {
        $widget_options = array(
            'classname' => 'custom_form_widget',
            'description' => 'This is a Custom Form Widget',
        );

        parent::__construct( 'custom_form_widget', 'Custom Form Widget', $widget_options );
         );

    } 

    //Hooks in a separate class method
    public function init() {

        add_action( 'wp_ajax_send_mail', array( $this, 'deliver_mail' ) );
        add_action( 'wp_ajax_nopriv_send_mail', array( $this, 'deliver_mail' ) );
    }

    //deliver mail    
    function deliver_mail() {     

        //name of button 
        require_once "C:/xampp/htdocs/WP/wp-includes/class-phpmailer.php";

        // sanitize form values
        $name    = sanitize_text_field( $_POST["name"] );
        $email   = sanitize_email( $_POST["email"] );
        $subject = sanitize_text_field( $_POST["subject"] );
        $message = esc_textarea( $_POST["message"] );
        // get the blog administrator's email address

        $headers = "From: $name <$email>" . "\r\n";

        // Localhost
        $mail = new PHPMailer(true);
        $mail->IsSMTP(); // telling the class to use SMTP
        $mail->CharSet = 'UTF-8';

        $mail->SMTPDebug = 0;                     // enables SMTP debug information (for testing)
        $mail->SMTPAuth = true;                  // enable SMTP authentication
        $mail->SMTPSecure = "ssl";                 // sets the prefix to the servier
        $mail->Host = "mail.gmx.com";      // sets GMX as the SMTP server for example: mail.gmx.com
        $mail->Port = 465;                 // set the SMTP port for the GMX server


        $mail->Username = $email;
        $mail->Password = 'PASS';

        $mail->SetFrom($email, $name);
        $mail->AddAddress($instance['email']);
         //Here has to be accessed $instance['email'] variable from the form() function;

        $mail->Subject = $subject;
        $mail->MsgHTML($message);

        $headers .= "Content-Type: text/html; charset=utf-8";
        $headers .= "Content-Transfer-Encoding: 8bit";

        try {
            $mail->send();
            $msg = "An email has been sent for verfication.";
            $msgType = "success";

            // wp_safe_redirect( home_url(), 302 );
            //exit();

        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            $msgType = "warning";

            //wp_safe_redirect( home_url(), 302 );
            //exit();
        }

        die();
    }    

    function widget( $args, $instance ) {

        echo $args['before_widget'];


        ?>
<form action="<?php esc_url( $_SERVER['REQUEST_URI'] )?>" method="post" class="contact-form" id="contact-form" >
    <div class=header-contact>
        <p><h2>Contact Form</h2></p>
        <hr>
    </div>
    <div class=input-containers>
        <input type="text" id="name" name="cf-name" pattern="[a-zA-Z0-9 ]+" value="" size="40" placeholder="Име и фамилия"/>
    </div>
    <div class=input-containers>
        <input type="email" id="email" name="cf-email" value="" size="40" placeholder="Поща"/>
    </div>
    <div class=input-containers>
        <input type="text" id="subject" name="cf-subject" pattern="[a-zA-Z ]+" value="" size="40" placeholder="Относно"/>
    </div>
    <div class=input-containers>
        <textarea rows="10" id="message" cols="35" name="cf-message" placeholder="Текст"></textarea>
    </div>
    <div class=input-containers>
        <input type="submit" name="cf-submitted" value="Send" id="submitForm">
        <input type="hidden" name="form_submitted" id="ajax_url" value="<?php echo admin_url('admin-ajax.php'); ?>" />
    </div>
    <button id="btn1">Bacon Button1</button>
    <p id="verify" style="display:none;">Your message has been sent.<br /><br /></p> 
</form>
<script>

</script>
<?php
       echo $args['after_widget']; 
    }

    public function update( $new_instance, $old_instance ) {    
        var_dump( $new_instance);
        return $new_instance;  
    }

    // Displays form in the widget section which the user should use to fill the receiver's email address.
    public function form( $instance )
    {

        $emailReceiver = '';
        if( !empty( $instance['email'] ) ) {
            $emailReceiver = $instance['email'];
        }

        ?>    
    <p>
        <label for="<?php echo $this->get_field_name( 'email' ); ?>"><?php _e( 'Email:' ); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id( 'email' ); ?>" name="<?php echo $this->get_field_name( 'email' ); ?>" type="text" value="<?php echo esc_attr( $emailReceiver ); ?>" />
    </p>
    <?php 
    if(!isset($emailReceiver) || trim($emailReceiver) == '') {
        echo "You did not fill out title field.";
    }
    ?>
<?php
    }
}
1
  • Is $instance defined in your deliver_mail() function?
    – butlerblog
    Commented Nov 13, 2018 at 19:04

1 Answer 1

0

You're trying to use $instance in your deliver_mail method, but that variable doesn't exist in that method. To get that variable, you need to be inside the widget function, but that's not possible. That function is only called when an instance of that widget is being displayed, which will never happen in an Admin AJAX call.

The problem is that my deliver_mail() method has been executed first and it gives me "Uncaught phpmailerException: Invalid address:...PHPMailer->addAddress(NULL)"

This would explain the mistake however, the request that handles the AJAX request, and calls PHPMailer, is a completely different request to the one that renders/saves the widget. They might as well be running on completely different machines, remember, PHP requests aren't like Node/Java/Python web apps, each request starts from a blank slate. It has nothing to do with the order the functions are called, because no request calls both functions to begin with

Additionally, adding Admin AJAX handlers in a WP_Widget based object like this is extremely unusual.

So:

  • First, separate your ajax handlers out of the widget object. They don't belong there
  • Second, you need to send everything that's needed along with the request
  • Thirdly, you can't store the email that the form mails in the widget, because you have no way of knowing which widget sent the request

Sending the email in the request, would allow attackers to use your contact form to email anybody anything using your server as a relay, which would get you quickly blacklisted ( amongst other things ), so that's not an option.

Instead you could store the recipient:

  • In an option
  • Attached to a post, select the post in the widget and pass the post ID along so that the callback can handle it

Additionally, I see you use the old Admin AJAX request, is there a specific reason you didn't use the simpler/easier/newer REST API?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.