How to Send SMS in WordPress with a PHP Plugin

August 02, 2017
Written by
Onwuka Gideon
Contributor
Opinions expressed by Twilio contributors are their own

wordpress-php-plugin

Writers want to stay in touch with their readers. Sending bulk SMS is a great tool to have in your toolbelt. Let’s build a WordPress plugin in PHP so you can send text messages to readers about topics they care about.

WordPress Plugins

Plugins let you extend and add functionality to your WordPress site. Since we are adding an entirely new function to WordPress, we have to use a plugin to achieve this.

First, we need to install WordPress if you haven’t already. You can download and install one locally by following the installation instructions here. I have my WordPress installation path as localhost/sendex/. I’ll be using it as my reference all throughout this tutorial.

Once you are done with the installation, log into your WordPress admin dashboard. This is where we will be working from now on. The admin dashboard should be localhost/sendex/wp-admin assuming you used the same installation path that I used.

Assuming your installation path is http://example.com/, you can get the admin dashboard by opening http://example.com/wp-admin in your browser. Log in with your username and password. If the login was successful, you’re ready to go.

Getting a Twilio SMS Account

Head to Twilio to create an account if you don’t have one already. After that, navigate to the Twilio Console and note down your account sid and auth token keys. They should look like:

ACCOUNT SID = AC90d5e*******************

AUTH TOKEN  = ***************************

Setting Up Our WordPress Plugin

Now we’re ready to write some code. Here’s a rundown of what we’ll do with WordPress:

  • Get the plugin boilerplate
  • Create a settings page
  • Implement the sending messages functionality

The best way to begin with a new plugin is by working on the incredibly useful WordPress Plugin Boilerplate. You might be asking why are we using a boilerplate instead of building from scratch. This boilerplate will get you started quickly with a standardized, organized and object-oriented foundation – basically, everything you want if you started from scratch.

To get started, just go to the WordPress Plugin Boilerplate Generator and fill-out the form then click on the Build button. For example, here are the fields I filled in:

Plugin Name = SEND SMS
Plugin Slug = sendex
Plugin Uri = http://menusms.com/sendex
Author Name = Onwuka Gideon
Author Email = gideon.onwuka1@gmail.com
Author Url = http://menusms.com/dongido

You can fill in whatever you want in the fields above. I’d suggest you use the same details I entered. This will make it easier to follow along with the code. You can change the details later once you fully understand the code.

After downloading the boilerplate above, extract it into your WordPress plugin folder i.e. localhost/sendex/wp-content/plugins.

Once you’re done, go to the admin plugin page localhost/sendex/wp-admin. If you are logged in, you should see our new plugin in the list of plugins.  Activate the plugin by clicking on the activate link.

Now that our plugin is installed, let’s review our boilerplate folder structure.

When you open the plugin folder sendex, you will notice that the plugin has 4 folders: admin, includes, languages, public and some other files.

admin/
      This folder contains all our admin facing code; including css, js, partials folders and a php file class-sendex-admin.php.
     
includes/
In this folder, you will find:

  • The main plugin PHP class class-sendex.php where we will add all our actions and filters
  • The activator file class-sendex-activator.php
  • The deactivator file class-sendex-desactivator.php
  • The internationalization file class-sendex-i18n.php
  • The loader file class-sendex-loader.php which will basically call all our actions in the main class file

languages/
      This folder which is a ready to use .pot file to make your plugin in multiple languages.
     
 public/
         The public folder is the similar files as our admin folder except that all codes here are for public facing functionalities.
         
Now we are left with four files:

  • LICENCE.txt: GPL-2 license
  • README.txt: This will include your plugin name, compatibility version, and description as seen on the plugin page in the WordPress repository. This is the first file we will edit.
  • uninstall.php: This script is called when the user clicks on the Delete link in the WordPress plugin backend.
  • sendex.php: This is the main plugin bootstrap file. You will likely edit this file with the version number and the short description of your plugin.

Create a settings page

We’ll need to add the settings page to our admin panel so we can manage our API credentials easily.
     

Open the admin/class-sendex-admin.php file. Note that from now on we are working in the sendex folder, which is our plugin folder. This admin/class-sendex-admin.php file has 3 functions already. Add these functions to the class:

/**
 *  Register the administration menu for this plugin into the WordPress Dashboard
 * @since    1.0.0
 */
 
public function add_sendex_admin_setting() {

    /*
     * Add a settings page for this plugin to the Settings menu.
     *
     * Administration Menus: http://codex.wordpress.org/Administration_Menus
     *
     */
    add_options_page( 'SENDEX SMS PAGE', 'SENDEX', 'manage_options', $this->plugin_name, array($this, 'display_sendex_settings_page')
    );
}

/**
 * Render the settings page for this plugin.( The html file )
 *
 * @since    1.0.0
 */
 
public function display_sendex_settings_page() {
    include_once( 'partials/sendex-admin-display.php' );
}

  • The add_sendex_admin_setting function calls WordPress core function add_options_page which is used to add settings pages as you can be see here.
  • The add_options_page function is a WordPress core function which is used to add new option pages. We are utilizing this to create our own settings page.

The add_options_page function accepts 5 parameters.

  1. page title: text to be displayed in the title tags of the page when the menu is selected).
  2. menu_title: text that will be displayed on the menu that will be linked to our settings page
  3. the capability option: user capability required for this menu to be displayed to the user
  4. menu slug: a unique string that will be used to refer to the page that we just created. The slug name to refer to this menu by (should be unique for this menu)
  5. (optional): accepts a callable array with $this as the first value, and the name of the class method to pass this data to as the second value

The display_sendex_settings_page renders the settings view page. The view file can be found in the admin/partials/ folder.

Next, create the settings page by copying and saving the below code to a admin/partials/sendex-admin-displays.php file.

<form method="POST" action='options.php'>
   <?php
         settings_fields($this->plugin_name);
         do_settings_sections('sendex-settings-page');
                 
         submit_button();  
   ?>
</form>

  • The settings_fields function prints out the settings fields for our settings section. By default, this will print out all the settings options WordPress has. We will define our own later so it only prints our defined options.
  • do_settings_sections function will print out all settings sections that we will add to our settings page.
  • submit_button prints out the submit button.

You can read more about how all of this works here.

Next, let’s register the settings options and fields that we need. Add the below code to admin/class-sendex-admin.php.

/**
 * Registers and Defines the necessary fields we need.
 *
 */
public function sendex_admin_settings_save(){

    register_setting( $this->plugin_name, $this->plugin_name, array($this, 'plugin_options_validate') );
    
    add_settings_section('sendex_main', 'Main Settings', array($this, 'sendex_section_text'), 'sendex-settings-page');
    
    add_settings_field('api_sid', 'API SID', array($this, 'sendex_setting_sid'), 'sendex-settings-page', 'sendex_main');
    
    add_settings_field('api_auth_token', 'API AUTH TOKEN', array($this, 'sendex_setting_token'), 'sendex-settings-page', 'sendex_main');
}

/**
 * Displays the settings sub header
 *
 */
public function sendex_section_text() {
    echo '<h3>Edit api details</h3>';
} 

/**
 * Renders the sid input field
 *
 */
public function sendex_setting_sid() {

   $options = get_option($this->plugin_name);
   echo "<input id='plugin_text_string' name='$this->plugin_name[api_sid]' size='40' type='text' value='{$options['api_sid']}' />";
}   

/**
 * Renders the auth_token input field
 *
 */
public function sendex_setting_token() {
   $options = get_option($this->plugin_name);
   echo "<input id='plugin_text_string' name='$this->plugin_name[api_auth_token]' size='40' type='text' value='{$options['api_auth_token']}' />";
}

/**
 * Sanitises all input fields.
 *
 */
public function plugin_options_validate($input) {
    $newinput['api_sid'] = trim($input['api_sid']);
    $newinput['api_auth_token'] = trim($input['api_auth_token']);

    return $newinput;
}

The comments throughout the code explain what each function handles.

sendex_admin_settings_save class has 4 functions:

  • register_settings function registers a setting and its sanitization callback. This is part of the Settings API, which allows us to automatically generate wp-admin settings pages by registering our settings and using a few callbacks to control the output.
  • add_settings_section helps us group common input fields.
  • add_settings_field function prints the html input field to the page.

We need to hook these functions to WordPress so WordPress knows about them.

Open up the includes/class-sendex.php then add the below code to the define_admin_hooks function.

// Add setting menu item 
$this->loader->add_action( 'admin_menu', $plugin_admin, 'add_sendex_admin_setting' );

// Saves and update settings
$this->loader->add_action( 'admin_init', $plugin_admin, 'sendex_admin_settings_save' );

The function should now look like this.

<?php

/**
* Register all of the hooks related to the admin area functionality
* of the plugin.
*
* @since    1.0.0
* @access   private
*/
private function define_admin_hooks() {

   $plugin_admin = new Sendex_Admin( $this->get_plugin_name(), $this->get_version() );

   $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );

   $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );

   // Add setting menu item 
   $this->loader->add_action( 'admin_menu', $plugin_admin, 'add_sendex_admin_setting' );
   
   // Saves and update settings
   $this->loader->add_action( 'admin_init', $plugin_admin, 'sendex_admin_settings_save' );
}

When you refresh the admin page, you should see the Settings page..

Now insert your API details and submit. (Pro tip: You should insert your own API credentials)

ACCOUNT SID = AC90d5e*******************
AUTH TOKEN  = ***************************

Add a page for sending messages.

We need to add a page where we can send our SMS from. First, we will add a submenu to the tools tab in the admin area.

Add these functions to the admin/class-sendex-admin.php file.

/**
* Register the sms page for the admin area.
*
* @since    1.0.0
*/
public function register_sendex_sms_page() {
  // Create our settings page as a submenu page.
    add_submenu_page(
            'tools.php',                                         // parent slug
            __( 'SENDEX SMS PAGE', $this->plugin_name.'-sms' ), // page title
            __( 'SENDEX', $this->plugin_name.'-sms' ),         // menu title
            'manage_options',                                 // capability
            $this->plugin_name.'-sms',                       // menu_slug
            array( $this, 'display_sendex_sms_page' )       // callable function
    );
}

/**
* Display the sms page - The page we are going to be sending message from.
*
* @since    1.0.0
*/

public function display_sendex_sms_page() {
   include_once( 'partials/sendex-admin-sms.php' );
}

The add_submenu_page function adds a new page under the tools tab. For further reference, take a look at this reference page.

The display_sendex_sms_page function includes our HTML forms for sending sms.

One more thing, let’s add the hook. Open the includes/class-sendex.php file then add the below inside the define_admin_hooks method.

// Hook our sms page
$this->loader->add_action( 'admin_menu', $plugin_admin, 'register_sendex_sms_page' );

Now, create a new file inside admin/partials/ folder and name it sendex-admin-sms.php.

If you refresh the admin page, you should see our new submenu under the tools tab. If you click it, it should lead to a blank page though.

Next, add the content below to the file you just created: sendex-admin-sms.php.

<!-- admin/partial/ sendex-admin-sms.php. -->

<h2><?php esc_attr_e( 'Send message easily', 'WpAdminStyle' ); ?></h2>

<div class="wrap">
        <div id="icon-options-general" class="icon32"></div>
        <div id="poststuff">
                <div id="post-body" class="metabox-holder columns-2">
                        <!-- main content -->
                        <div id="post-body-content">
                                <div class="meta-box-sortables ui-sortable">
                                        <div class="postbox">
                                                <h2 class="hndle"><span><?php esc_attr_e( 'SEND SMS', 'WpAdminStyle' ); ?></span>
                                                </h2>
                                                <div class="inside">
                           <form method="post" name="cleanup_options" action="" >
                                                          <input type="text" name="sender" class="regular-text" placeholder="Sender ID" required/><br><br>
                                                          <input type="text" name="numbers" class="regular-text" placeholder="+2348059794251" required/><br><br>
                                                          <textarea name="message" cols="60" rows="10" placeholder="Message">

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!-- admin/partial/ sendex-admin-sms.php. -->
 
<h2> esc_attr_e( 'Send message easily', 'WpAdminStyle' ); ?></h2>
 
<div class="wrap">
        <div id="icon-options-general" class="icon32"></div>
        <div id="poststuff">
                <div id="post-body" class="metabox-holder columns-2">
                        <!-- main content -->
                        <div id="post-body-content">
                                <div class="meta-box-sortables ui-sortable">
                                        <div class="postbox">
                                                <h2 class="hndle"><span> esc_attr_e( 'SEND SMS', 'WpAdminStyle' ); ?></span>
                                                </h2>
                                                <div class="inside">
                           <form method="post" name="cleanup_options" action="" >
                                                          <input type="text" name="sender" class="regular-text" placeholder="Sender ID" required/><br><br>
                                                          <input type="text" name="numbers" class="regular-text" placeholder="+2348059794251" required/><br><br>
                                                          <textarea name="message" cols="60" rows="10" placeholder="Message"></textarea><br><br>
                                                          <input class="button-primary" type="submit" value="SEND MESSAGE" name="send_sms_message"/>
                                                        </form>
                                                </div>
                                                <!-- .inside -->
                                        </div>
                                        <!-- .postbox -->
                                </div>
                                <!-- .meta-box-sortables .ui-sortable -->
                        </div>
                        <!-- post-body-content -->
                </div>
                <!-- #post-body .metabox-holder .columns-2 -->
                <br class="clear">
        </div>
        <!-- #poststuff -->
</div> <!-- .wrap -->

If you click SENDEX which is under the tools tab, you should see our new page.

Let’s add the logic that will send our SMS. Maybe you’ve noticed, our form action attribute is empty, so this basically means we are submitting to the same URL. We will add a function that checks if our form is submitted then it processes the data.

Create the function that will process the send SMS form. Add it to class-sendex-admin.php.

public function send_message(){

	     if( !isset($_POST['send_sms_message']) ){ return; }
	           
	      $to        = (isset($_POST['numbers']) ) ? $_POST['numbers'] : '';
	      $sender_id = (isset($_POST['sender']) )  ? $_POST['sender']  : '';
	      $message   = (isset($_POST['message']) ) ? $_POST['message'] : '';

	      //gets our api details from the database.
	      $api_details = get_option('sendex'); #sendex is what we use to identify our option, it can be anything

	      if(is_array($api_details) AND count($api_details) != 0) {
	           $TWILIO_SID = $api_details['api_sid'];
	           $TWILIO_TOKEN = $api_details['api_auth_token'];
	      }
	      
	        try{
                    $to = explode(',', $to);
                    
	                $client = new Client($TWILIO_SID, $TWILIO_TOKEN);

	                  $response = $client->messages->create(
	                        $to ,
	                        array(
	                          'from' => $sender_id,
	                         'body' => $message
	                        )
	                    );

	                   self::DisplaySuccess();

	            } catch (Exception $e) {

	                self::DisplayError( $e->getMessage() );
	            }           
	    }

What this function does is to check if a REQUEST has a $_POST['send_sms_message'], then it tries to send the SMS.  

The try block is for exception handling. It tries to send messages, if there’s no error, it displays a success message. If there is any error, it displays a failure message.

We called new Client(), self::DisplayError(), self::DisplaySuccess() which we have not defined anywhere.  Let’s add those functions too.

Add these to admin/class-sendex-admin.php.

/**
 * Designs for displaying Notices
 *
 * @since    1.0.0
 * @access   private
 * @var $message - String - The message we are displaying
 * @var $status   - Boolean - its either true or false
 */
public static function admin_notice($message, $status = true) {
    $class =  ($status) ? 'notice notice-success' : 'notice notice-error';
    $message = __( $message, 'sample-text-domain' );

     printf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), esc_html( $message ) ); 
}

/**
 * Displays Error Notices
 *
 * @since    1.0.0
 * @access   private
 */
public static function DisplayError($message = "Aww!, there was an error.") {
    add_action( 'admin_notices', function() use($message) {
    self::admin_notice($message, false);
    } );
}

/**
 * Displays Success Notices
 *
 * @since    1.0.0
 * @access   private
 */
public static function DisplaySuccess($message = "Successful!") {
    add_action( 'admin_notices', function() use($message) {
    self::admin_notice($message, true);
    } );
}

The admin_notice function outputs HTML which will contain our error or success messages.

DisplayError function calls the admin_notice to display an error message.

DisplaySuccess function calls the admin_notice to display an success message.

Now download twilio library and extract it into your plugins folder (sendex). The folder name might be twilio-php-master. To make things simple rename the folder to twilio.
   
Now open admin/class-sendex-admin.php then add the below at the top of the file.

require_once( plugin_dir_path( __FILE__ ) .'/../twilio/Twilio/autoload.php');

use Twilio\Rest\Client;

Here is what your file should look like.

<?php

/**
 * The admin-specific functionality of the plugin.
 *
 * @link       http://menusms.com/dongido
 * @since      1.0.0
 *
 * @package    Sendex
 * @subpackage Sendex/admin
 */

/**
 * The admin-specific functionality of the plugin.
 *
 * Defines the plugin name, version, and two examples hooks for how to
 * enqueue the admin-specific stylesheet and JavaScript.
 *
 * @package    Sendex
 * @subpackage Sendex/admin
 * @author     Onwuka Gideon <gideon.onwuka1@gmail.com>
 */
 
require_once( plugin_dir_path( __FILE__ ) .'/../twilio/Twilio/autoload.php');

use Twilio\Rest\Client;

class Sendex_Admin {

	/**
	 * The ID of this plugin.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @var      string    $plugin_name    The ID of this plugin.
	 */
	private $plugin_name;
...

Finally, add a hook for sending message to includes/class-sendex.php. As usual, add it to the define_admin_hooks function.

// calls sending function whenever we try sending messages.
$this->loader->add_action( 'admin_init', $plugin_admin, 'send_message' );

Now open SENDEX under the tools tab and try sending messages.



Yay! Congrats, you just sent message from your WordPress site.

Conclusion

In this tutorial, we learned how to get started building WordPress plugins from a boilerplate code builder, create settings pages in WordPress and to send bulk SMS in WordPress.
 
I hope you enjoyed this tutorial. Thanks for reading. If you have any questions regarding this post or on WordPress, feel free to reach out, cheers!
 
Onwuka Gideon
@gideon_onwuka