How to Create an Effective Subscription Form in WordPress and Send Newsletter from Scratch
Learn how to create a powerful subscription form in WordPress and efficiently send newsletters from scratch.
Prerequisites: c
- Basic understanding of WordPress: You should be familiar with navigating the WordPress dashboard, installing plugins, and creating pages or posts.
- HTML: Understanding HTML is essential for structuring the subscription form. You’ll need to know how to create form elements such as input fields, buttons, and labels.
- CSS: Knowledge of CSS can help you style your subscription form to match your website’s design.
- JavaScript: JavaScript is used to add interactivity to your subscription form, such as form validation or dynamic behavior.
Creating the subscription form
<div class="c-subscribe">
<div class="c-subscribe__inner center">
<form id="subscribe" class="c-subscribe__form" novalidate>
<div class="c-subscribe__shell">
<input type="email" name="email" id="subscribe_email" placeholder="Email" class="c-subscribe__field" autocomplete="off">
</div>
<input type="submit" class="c-subscribe__submit" value="Subsribe">
</form>
</div>
</div>
- These two
<div>
elements create a container for the subscription form. Thec-subscribe
class is used for styling purposes, whilec-subscribe__inner
andcenter
classes define the inner content’s layout and alignment. - The
<form>
element establishes the subscription form. It has an ID of “subscribe” for easy identification in JavaScript or CSS. Thec-subscribe__form
class is used for styling the form.\ - Inside the form, there’s a
<div>
element with the classc-subscribe__shell
, which might serve as a container for styling purposes. Inside this container, there’s an<input>
element with the type “email”, allowing users to input their email addresses. Thename
attribute is set to “email”, and the ID is “subscribe_email” for identification. Theplaceholder
attribute provides an example or hint to users about what to enter. The classc-subscribe__field
is used for styling, andautocomplete="off"
disables browser auto-complete for this input field. - Finally, there’s an
<input>
element with the type “submit”, serving as the subscription form’s submit button. The classc-subscribe__submit
is used for styling, and the value attribute sets the text displayed on the button, which is “Subscribe” in this case.
You can create the subscription form as a shortcode, Gutenberg block, or Elementor widget to make it easier to add to your WordPress site.
Submitting the form
To submit the form, you would typically use JavaScript to handle the form submission event and send the form data to your server or an external service, such as an email marketing provider. Here’s how you can achieve that:
Make sure you have added your script correctly in your WordPress theme or plugin:
wp_enqueue_script( 'zing-script', get_template_directory_uri() . '/assets/script.js', array(), filemtime( get_template_directory() . '/assets/script.js' ), array( 'strategy' => 'defer', 'in_footer' => false ) );
This function loads the script ‘zing-script’ located in the ‘/assets/’ directory of your theme. It uses filemtime
to automatically version the script based on its modification time. The script is set to defer loading ('strategy' => 'defer'
) and not placed in the footer ('in_footer' => false
).
wp_localize_script( 'zing-script', 'zing', array(
'ajaxurl' => admin_url('admin-ajax.php'),
'ajaxnonce' => wp_create_nonce( 'ajaxsubmit' )
) );
This function localizes the script ‘zing-script’ to provide two variables: ‘ajaxurl’, which contains the URL to admin-ajax.php for AJAX requests, and ‘ajaxnonce’, which contains a nonce generated using wp_create_nonce
with the action ‘ajaxsubmit’.
const ajaxurl = zing.ajaxurl;
const ajaxnonce = zing.ajaxnonce;
const subscribe = document.querySelectorAll('#subscribe');
This part of the code initializes variables ajaxurl
, ajaxnonce
, and selects the subscribe
element(s) from the DOM.
The first two lines extract the ajaxurl
and ajaxnonce
variables from the zing
object, which was localized using wp_localize_script
in WordPress. These variables hold the URL for the admin-ajax.php file and the nonce value respectively.
With document.querySelector('#subscribe')
, you’re selecting the first element in the DOM that has the ID subscribe
. This method returns a single element (not a NodeList like querySelectorAll
), making it suitable when you’re expecting only one element with the specified ID.
Now, you can proceed to attach an event listener to this element to handle form submission or perform any other actions you need with it. For example:
subscribe.addEventListener('submit', e => {
e.preventDefault();
const email = subscribe.querySelector('input[type="email"]');
const data = {
action: 'zing_subscribe',
ajaxnonce: ajaxnonce,
email: email.value,
}
handleSubscribe( data );
})
This code sets up an event listener for the form submission, prevents the default behavior, retrieves the email input value, constructs an object containing data for the AJAX request, and then calls a function to handle the subscription process.
const handleSubscribe = async ( data ) => {
const response = await fetch( ajaxurl, {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'X-WP-Nonce': ajaxnonce,
},
body: new URLSearchParams(data).toString(),
});
if (response.ok) {
response.json().then( response => {
});
}
}
handleSubscribe
function is an asynchronous function that handles the AJAX request to submit the subscription data to the server.
If the response status is okay (in the 200-299 range), the code converts the response body to JSON using response.json()
and then executes a function to handle the successful response. You can add your logic inside this function to process the response data.
Handling the AJAX request
add_action( "wp_ajax_zing_subscribe", "zing_subscribe" );
add_action( "wp_ajax_nopriv_zing_subscribe", "zing_subscribe" );
These lines of code are WordPress actions that hook into the AJAX functionality for handling the subscription request. They associate the specified action ("wp_ajax_zing_subscribe"
and "wp_ajax_nopriv_zing_subscribe"
) with the callback function zing_subscribe
.
Here’s what each part does:
add_action( "wp_ajax_zing_subscribe", "zing_subscribe" );
:- This line adds an action hook that specifies the
zing_subscribe
function to be called when the AJAX request with the actionzing_subscribe
is made. This hook is for logged-in users.
- This line adds an action hook that specifies the
add_action( "wp_ajax_nopriv_zing_subscribe", "zing_subscribe" );
:- This line adds an action hook similar to the first one, but it’s for non-logged-in users. The
wp_ajax_nopriv_
prefix indicates that it’s for users who are not logged in.
- This line adds an action hook similar to the first one, but it’s for non-logged-in users. The
These actions ensure that the zing_subscribe
function is executed when an AJAX request with the action zing_subscribe
is made, regardless of whether the user is logged in or not.
Now, you need to define the zing_subscribe
function in your PHP code to handle the subscription logic. This function will receive the AJAX request, process the subscription data, and send a response back to the client-side JavaScript.
function zing_subscribe() {
$secure = check_ajax_referer( 'ajaxsubmit', 'ajaxnonce' );
if( !$secure ) {
wp_send_json( array(
'code' => 'request_error'
'message' => 'Request error'
) );
}
// Process subscription logic here
// Retrieve data from $_POST
$email = $_POST['email'];
// Perform subscription actions (e.g., save to database, send confirmation email, etc.)
// Send response back to JavaScript
wp_send_json(array(
'code' => 'subscribe_success',
'message' => 'User subscribed'
));
wp_die(); // Always call wp_die() after sending the response
}
Sending the newsletter
To create an options page with a button to send a newsletter and handle the AJAX functionality for it, you’ll follow a similar approach to what we did earlier for the subscription form, but with different AJAX functions. Here’s a step-by-step guide:
- Create the Options Page: First, create an options page in your WordPress admin panel where you’ll place the button to send the newsletter. You can use the Settings API or a plugin like ACF (Advanced Custom Fields) to create custom options pages easily.\
- Add Button to the Options Page: Within your options page, add a button that, when clicked, triggers the AJAX request to send the newsletter. You can use HTML and JavaScript to create and handle the button.
- Handle AJAX Request: Create a PHP function to handle the AJAX request when the button is clicked. This function will be responsible for sending the newsletter. It will receive the AJAX request, process it, and trigger the newsletter sending process.
- Define AJAX Actions: Hook into WordPress AJAX actions (
wp_ajax_
andwp_ajax_nopriv_
) to define the callback function for handling the AJAX request. - Implement the AJAX Functionality: Write JavaScript code to send the AJAX request when the button is clicked.
- Send Newsletter: Within the PHP callback function, implement the logic to send the newsletter. This may involve retrieving subscribers’ email addresses from the database and sending the newsletter using a third-party service or a custom mailing function.
// Step 3: Handle AJAX Request
function send_newsletter() {
// Process newsletter sending logic here
// For example, retrieve subscribers' email addresses from the database and send the newsletter
// Send response back to JavaScript
wp_send_json_success(array(
'code' => 'newsletter_success',
'message' => 'Newsletter sent'
));
wp_die();
}
// Step 4: Define AJAX Actions
add_action('wp_ajax_send_newsletter', 'send_newsletter');
add_action('wp_ajax_nopriv_send_newsletter', 'send_newsletter');
Send a newsletter email
You can use this functions to send the newsletter to the users.
if( !function_exists('zing_send_email')) {
/**
* Send an email to a user.
*
* @param string $email
* @param string $subject
* @param string $conent
* @param array $what
* @param string|int $who
* @return void
*/
function zing_send_email( $email, $subject, $body, $link ) {
$headers = array('Content-Type: text/html; charset=UTF-8');
ob_start(); ?>
<html>
<head>
<title><?php echo get_bloginfo( 'name' ); ?></title>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
</head>
<div class="zing-mail">
<div class="zing-mail__inner" style="margin-bottom: 30px;">
<h1 class="zing-mail__title" style="font-size: 34px; color: #5243aa;">
<?php echo $subject; ?>
</h1>
<p class="zing-mail__body" style="font-size: 20px; margin-top: 0; margin-bottom: 30px;">
<?php echo $body; ?>
</p>
<a class="zing-mail__button" href="<?php echo $link; ?>" style="font-size: 20px; color: #5243aa;">
<?php echo 'Learn more'; ?>
</a>
</div>
</div>
</html>
<?php
$content = ob_get_clean();
return wp_mail( $email, get_bloginfo( 'name' ) . ': ' . $subject, $content, $headers );
}
}
For testing purposes, Mailtrap is an excellent choice. It allows you to test email functionality in your application without sending emails to real recipients.
For production use, you typically want to use a reliable and scalable email delivery service that specializes in sending transactional and marketing emails. While Mailtrap is excellent for testing, it’s not suitable for production use because it’s designed specifically for testing purposes and not for delivering emails to real recipients.