Writing WordPress Plugin




Introduction

A WordPress plugin lets you add meaningful functionality to your WordPress website. There are thousands of such plugins available in the WordPress plugin directory. On the other hand, if you provide a service that WordPress users can use, then a plugin will easily and elegantly help the user use your service. This blog is for people who wish to write a plugin for a service they want to provide to WordPress users.

It is not every day that you have to write a WordPress plugin. Most of us will be writing one or maybe a few WordPress plugins. You wish you get handy material to read through quickly and generate a plugin in a few hours for such stuff.

Before you start, you need to be clear about how the WordPress user will use the WordPress plugin. Most common WordPress plugins fall into one of the following categories:

To get started with the plugin you need to be familiar with PHP and should have a WordPress installation to develop and test the plugin. Next you need to figure out the plugin slug name. This is like a domain name that uniquely identifies your plugin. Preferably use your domain name or company name. Since there are thousands or other plugins the name you choose should be uniquely able to identify your plugin. This will be reviewed by the WordPress team before they approve your plugin.

The plugin methods that you write are going to work in a shared namespace. So it will make sense to append the PHP filenames and methods names with the slug name that you choose. You should also go thru the detailed guidelines provided by WordPress here.


Getting Started

Create a folder in your WordPress installation under wp-content/plugins/ use the chosen slugname (we will assume slugname to be slugname) as the folder name. Under this folder wp-content/plugins/slugname, create two files index.php and slugname.php.

index.php is a place holder and contains the following:

<?php
// Silence is golden.
slugname.php contains the plugin details as follows:

<?php
/**
 * @package Slugname Service
 * @version 0.0.1
 * @email: info at ibeyonde.com
 */
/*
Plugin Name: Slugname
Plugin URI: http://WordPress.org/plugins/slugname/
Description: A shortcode based WordPress plugin to enable Slugname on the webpage
Author: Ibeyonde
Version: 0.0.1
Author URI: https://ibeyonde.com/
*/

define( 'SLUGNAME_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );

require_once(SLUGNAME_PLUGIN_DIR .'slugname_init.php');
require_once(SLUGNAME_PLUGIN_DIR .'slugname_settings.php');
require_once(SLUGNAME_PLUGIN_DIR .'slugname_shortcode.php');

In slugname.php include plugin details and other plugin files that are part of your plugin code, as shown above. The other files are slugname_init.php, slugname_settings.php and slugname_shortcode.php.

slugname_init.php contains code to initialize the plugin, as shown below:


<?php
/**
 * Slugname initial settings
 * 
 * The initial setup for each page.
 * 
 */
function slugname_init() {
    /**
    * The options store the values that are initialized by the WordPress user in the plugins settings page. 
    **/
    $options = get_option( 'slugname_options' );
    
    /**
    * Use the values in options to initialize local variables
    **/
    $field_id = isset($options["slugname_field_id"]) ? $options["slugname_field_id"] : null;
    
    /**
    * If some important setting is missing abort the plugin setup
    **/
    //If field_id is not defined donot register the plugin
    if ($field_id == null){
        return;
    }
    
    /**
    * Add javascript files that are required by your plugin. Use "enque"" so that the WordPress engine loads it in an optimized fashion
    **/
    
    wp_enqueue_script('slugname', plugin_dir_url(__FILE__) . 'http://slugname.com/slugname-latest.js', array('jquery'), null, true );
    
    $inline_js = '< some javascript that will be added to all the pages > ';
    
    wp_add_inline_script('slugname', $inline_js);
}

/**
 * Register our slugname_settings_init to the admin_init action hook.
 */
add_action( 'init', 'slugname_init' );

Most of the plugins can do with a settings page. So we start our coding section on how to put the settings page on WordPress plugin. A typical settings page, slugname_settings.php, with a input field and a dropdown is shown below:


<?php
/**
 * Custom settings
 */
function slugname_settings_init() {
    // Register a new setting for "slugname" page.
    register_setting( 'slugname', 'slugname_options' );
    
    // Register a new section in the "slugname" page.
    add_settings_section(
            'slugname_section_developers',
            __( 'Worlds best wordpress solution.', 'slugname' ), 'slugname_section_developers_callback', 'slugname'
            );
    
    add_settings_field(
            'slugname_field_id', 
            // Use $args' label_for to populate the id inside the callback.
            __( 'Web Id', 'slugname' ),
            'slugname_field_id_cb',
            'slugname',
            'slugname_section_developers',
            array(
                    'label_for'         => 'slugname_field_id',
                    'class'             => 'slugname_row_id',
                    'custom_data'       => 'slugname_custom_id',
            )
            );
    
    
    add_settings_field(
            'slugname_field_position', 
            // Use $args' label_for to populate the id inside the callback.
            __( 'Item Placement', 'slugname' ),
            'slugname_field_position_cb',
            'slugname',
            'slugname_section_developers',
            array(
                    'label_for'         => 'slugname_field_position',
                    'class'             => 'slugname_row_position',
                    'custom_data'       => 'slugname_custom_position',
            )
            );
}

/**
 * Register our slugname_settings_init to the admin_init action hook.
 */
add_action( 'admin_init', 'slugname_settings_init' );


/**
 * Custom option and settings:
 *  - callback functions
 */

/**
 * Developers section callback function.
 *
 * @param array $args  The settings array, defining title, id, callback.
 */
function slugname_section_developers_callback( $args ) {
    ?>
    <p id="<?php echo esc_attr( $args['id'] ); ?>"><?php esc_html_e( 'To link the user account, please provide the details below.', 'slugname' ); ?></p>
    <?php
}
 
/**
 * Id field callback function.
 *
 * @param array $args
 */
function slugname_field_id_cb( $args ) {
    /**
    * Get the value of the setting that were given before to pre-populate the fields
    **/
    $options = get_option( 'slugname_options' );
    ?>
    <input type='text' name="slugname_options[<?php echo esc_attr( $args['label_for'] ); ?>]" 
        id="<?php echo esc_attr( $args['label_for'] ); ?>" 
        value="<?php echo isset( $options[ $args['label_for'] ] ) ? $options[ $args['label_for'] ] :  '' ; ?>"
        placeholdertext="web id" size="100">
    <p class="description">
        <?php esc_html_e( 'You will get this value from your slugname account\'s WordPress setting.', 'slugname' ); ?>
    </p>
    <?php
}


/**
 * Poistion field callback function valid values are:
 *  'top' | 'top-start' | 'top-end' 
 *
 * @args
 */
function slugname_field_position_cb( $args ) {
    // Get the value of the setting we've registered with register_setting()
    $options = get_option( 'slugname_options' );
    ?>
    <select
            id="<?php echo esc_attr( $args['label_for'] ); ?>"
            data-custom="<?php echo esc_attr( $args['custom_data'] ); ?>"
            name="slugname_options[<?php echo esc_attr( $args['label_for'] ); ?>]">
        <option value="top" <?php echo isset( $options[ $args['label_for'] ] ) ? ( selected( $options[ $args['label_for'] ], 'top', false ) ) : ( '' ); ?>>
            <?php esc_html_e( 'top', 'slugname' ); ?>
        </option>
        <option value="top-start" <?php echo isset( $options[ $args['label_for'] ] ) ? ( selected( $options[ $args['label_for'] ], 'top-start', false ) ) : ( '' ); ?>>
            <?php esc_html_e( 'top-start', 'slugname' ); ?>
        </option> 
        <option value="top-end" <?php echo isset( $options[ $args['label_for'] ] ) ? ( selected( $options[ $args['label_for'] ], 'top-end', false ) ) : ( '' ); ?>>
            <?php esc_html_e( 'top-end', 'slugname' ); ?>
        </option>
    </select>
    <p class="description">
        <?php esc_html_e( 'Select the position of the Item placement on the webpage.', 'slugname' ); ?>
    </p>
    <?php
}

/**
 * Add the top level menu page.
 */
function slugname_options_page() {
    add_menu_page(
        'Slugname',
        'Slugname Settings',
        'manage_options',
        'Slugname',
        'slugname_options_page_html'
    );
}
 
 
/**
 * Register our slugname_options_page to the admin_menu action hook.
 */
add_action( 'admin_menu', 'slugname_options_page' );
 
 
/**
 * Top level menu callback function
 */
function slugname_options_page_html() {
    // check user capabilities
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }
 
    // add error/update messages
 
    // check if the user has submitted the settings
    // WordPress will add the "settings-updated" $_GET parameter to the url
    if ( isset( $_GET['settings-updated'] ) ) {
        // add settings saved message with the class of "updated"
        add_settings_error( 'slugname_messages', 'slugname_message', __( 'Settings Saved', 'slugname' ), 'updated' );
    }
 
    // show error/update messages
    settings_errors( 'slugname_messages' );
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <form action="options.php" method="post">
            <?php
            // output security fields for the registered setting "slugname"
            settings_fields( 'slugname' );
            // output setting sections and their fields
            // (sections are registered for "slugname", each field is registered to a specific section)
            do_settings_sections( 'slugname' );
            // output save settings button
            submit_button( 'Save Settings' );
            ?>
        </form>
    </div>
    <?php
}

With the init and settings page, you are mostly started. Now comes the plugin-specific part. In this, we will look at how you can use shortcodes. Shortcodes are placeholders that are embedded in the WordPress page using solid braces like [slugname_shortcode id=abc]. The method you will define here will substitute these shortcodes with the HTML/javascript/CSS you specify in the shortcode methods.

Create a file called slugname_shortcode.php and type as per the code guidelines provided below:


<?php

// Add the action.
add_action( 'plugins_loaded', function() {
    // Add the shortcode.
    add_shortcode( 'slugname', 'slugname_shortcode' );
});

/**
 * This function defines the slugname_shortcode
 *
 * @param  Attributes $atts
 * @return string
 * @since  1.0.0
 * 
 */
function slugname_shortcode( $atts ) {
    $options = get_option( 'facee_options' );
    
    /**
    * Get values from shortcode definition [slugname_shortcode id=abc]
    **/
    $type = trim(isset($atts["id"]) ? $atts["id"] : null);
    
    /**
    * Do something meaningful like write javascript, html or CSS
    **/
    
    $inline_js = '< some javascript >';
    wp_add_inline_script('ibeyonde', $inline_js);
    
    $_return = "< Some html code >"
    
    return $_return;
}

Once you are done coding your WordPress plugin you will also need to do some documentation like writing the license file and readme.txt. For License, this is what WordPress suggests. A sample readme.txt file can be found here. You can submit your plugin here. Learn a bit about SVN here , it will come in handy.

The above will mostly set you up and get you ready for writing your own WordPress plugin. You can get in touch with us at info[at]ibeyonde.com if you need further help.