1

I know that there are many possible duplicates but i keep receiving this error each time

I'm currently working on a WordPress contact form, which is created as plugin. I need after submitting the form to redirects to the same page with a new clean form. The problem is that if i put header("location...) it shows me the message

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\WP\wp-content\themes\group-test\header.php:13) in C:\xampp\htdocs\WP\wp-content\plugins\form-example\form-example.php on line 84

The form is working correctly and it sends email after i press submit button, but the problem is that it keeps the old input values and it resends them again after every reload or submit pressing even the form is empty... The best decision for me would be not to reload the page but only to shows some message after i press "Submit" and to empty the input values from the form as others WP forms functionality(Contact 7 etc.) but i know that Ajax is needed... But firstly i will be glad if someone shows me where i am wrong.

<?php
/*
 Plugin Name: Example Contact Form
 Plugin URI: http://jd.com
 Description: Contact Form
 Version: 1.0
 Author: JD
 Author URI: http://jd.com
 */
function html_form_code() {    
    ?> 
<form action="<?php esc_url( $_SERVER['REQUEST_URI'] )?>" method="post" class="contact-form" id="newsletterform">
    <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" name="cf-email" value="" size="40" placeholder="Поща"/>
    </div>
    <div class=input-containers>
        <input type="text" name="cf-subject" pattern="[a-zA-Z ]+" value="" size="40" placeholder="Относно"/>
    </div>
    <div class=input-containers>
        <textarea rows="10" cols="35" name="cf-message" placeholder="Текст"></textarea>
    </div>
    <div class=input-containers>
        <input type="submit" name="cf-submitted" value="Send" >
    </div>
</form>
<?php
}
//function to generate response

function deliver_mail() {
    require_once "wp-includes/class-phpmailer.php";
    $verificationMessages = array();

    // if the submit button is clicked, send the email
    if ( isset( $_POST['cf-submitted'] ) ) {    
        // sanitize form values
        $name    = sanitize_text_field( $_POST["cf-name"] );
        $email   = sanitize_email( $_POST["cf-email"] );
        $subject = sanitize_text_field( $_POST["cf-subject"] );
        $message = esc_textarea( $_POST["cf-message"] );

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

        $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";
            array_push($verificationMessages, "Check your email to activate your account");
            header("location: http://localhost/wp/");

        } catch (Exception $ex) {
            $msg = $ex->getMessage();
            $msgType = "warning"; 
            array_push($verificationMessages, "Wrong");
            header("location: http://localhost/wp/");
        }      
    }
}

function cf_shortcode() {
    ob_start();

    deliver_mail();
    html_form_code();

    ob_end_flush(); 
    //return ob_get_clean();
}
add_shortcode( 'sitepoint_contact_form', 'cf_shortcode' );
  • What you're trying to do can't be done inside a shortcode, you have to call header before any output, the moment PHP sees a single character even a space, it outputs a set of headers telling the browser to expect a webpage. Once that's done, the header part of the page is done, you can't change it, hence the warning – Tom J Nowell Jul 13 '18 at 20:58
  • So, i have to remove the shortcode function(not to call the other functions from there) and try in a different way? – J.D. Jul 13 '18 at 21:05
1

So the root problem is sending headers, specifically the timing.

Webpages have http headers, and http headers come before the content. The headers tell the browser what it's recieving, and they must be sent first.

When PHP outputs stuff, it needs to tell the browser to expect output, so the moment a character is output, PHP sends HTTP headers telling the browser to expect output.

Once they're sent, they're sent. Horse is out the stable door, cats out of the bag, they can't be changed.

So by the time your site reaches your shortcode, it's already output a html element, and a header and a title etc, it's too late to send a redirect header!

As a result we can conclude, that redirecting inside a shortcode, is not possible. Another solution is required

The root problem is that you're trying to do things inside a shortcode. Displaying the output in the shortcode is great, but it's not good for actual processing.

So instead, lets add a hidden input to the form that we can use to pick up on the form submission:

<input type="hidden" name="form_submitted" value="true" />

Then look for that value on the init hook:

add_action( 'init', function() {
    if ( ! empty( $_POST['form_submitted'] ) ) {
        deliver_email();
    }
}

And finally, fix the broken shortcode that outputs directly instead of returning a HTML string:

function cf_shortcode() {
    ob_start();

    html_form_code();

    return ob_get_clean();
}

Additional notes:

  • prefix everything, but pick one more unique than cf
  • You don't need to include the PHPMailer files, wp_mail and its filters will do fine
  • There's no exit statement after your header redirect
  • Use wp_safe_redirect instead of header
  • Don't hardcode the URL, there are functions for that, e.g. home_url() etc
  • Without exit() statement the page resubmit the form after reload no matter if it is wp_safe, wp_safe_redirect or header. And if you read the description in WordPress.org documentation there is "wp_safe_redirect() / wp_redirect() does not exit automatically and should almost always be followed by exit." – J.D. Jul 14 '18 at 9:09
  • Your answer is very useful. It learns me a lot. Thank you! – J.D. Jul 14 '18 at 9:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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