Wednesday, November 12, 2025

Welcome to RMC online Tutorials

WordPress Plugin Development – Full Course Index

WordPress Plugin Development
12-Module Learning Portal

#12 🧩 Module 12 – Plugin Security, Performance & Best Practices

Module 12 – Plugin Security, Performance & Best Practices

🧩 Module 12 – Plugin Security, Performance & Best Practices

In this final module, you’ll learn how to keep your WordPress plugin secure, fast, and reliable. We’ll cover sanitization, escaping, nonces, database safety, and performance tips.


Step 1 – Sanitize User Input

Always clean any data from users before saving to the database or displaying on screen.

$user_input = $_POST['username'] ?? ''; $clean_input = sanitize_text_field( $user_input ); // Example: Save safely update_option( 'mfp_username', $clean_input );

Step 2 – Escape Output

When printing values on a page, escape them to prevent XSS (Cross-Site Scripting).

$name = get_option('mfp_username'); echo '<h3>Hello, ' . esc_html( $name ) . '!</h3>';

Step 3 – Use Nonces for Form Security

Nonces ensure only valid requests modify data.

<form method="post"> <?php wp_nonce_field( 'mfp_save_data', 'mfp_nonce' ); ?> <input type="text" name="username"> <input type="submit" value="Save"> </form> <?php if ( isset($_POST['mfp_nonce']) && wp_verify_nonce($_POST['mfp_nonce'], 'mfp_save_data') ) { $username = sanitize_text_field($_POST['username']); update_option('mfp_username', $username); echo '<p style="color:#00ffa3">Saved!</p>'; } ?>

Step 4 – Use Prepared Statements for SQL

Avoid building SQL queries with string concatenation — use the $wpdb->prepare() method.

global $wpdb; $username = 'admin'; $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->users} WHERE user_login = %s", $username ) );

Step 5 – Performance Tips

  • ✅ Use transients to cache data from APIs or heavy DB queries.
  • ✅ Load scripts only when necessary using admin_enqueue_scripts conditions.
  • ✅ Use filemtime() for cache-busting only when scripts truly change.
  • ✅ Avoid loading large CSS/JS on pages where your plugin isn’t used.
// Example: conditional script load function myplugin_enqueue_scripts($hook) { if ( $hook !== 'toplevel_page_myplugin' ) return; wp_enqueue_script( 'myplugin-admin', plugin_dir_url(__FILE__) . 'admin.js', array('jquery'), filemtime(__FILE__), true ); } add_action('admin_enqueue_scripts', 'myplugin_enqueue_scripts');

Step 6 – Follow Coding Standards

  • Use snake_case for functions and variables.
  • Prefix everything (e.g., mfp_) to avoid name collisions.
  • Document your code with clear comments.
  • Validate your plugin with the WordPress Plugin Check tool.

Step 7 – Prepare for Distribution

  • Add readme.txt with description, version, author, and license.
  • Use proper folder structure (includes/, assets/, etc.).
  • Provide translation support with load_plugin_textdomain().
  • Keep plugin lightweight – load only what’s needed.

🎯 Wrap-Up

Congratulations! You’ve now built a full-featured WordPress plugin suite — from login systems, AJAX, REST API, Gutenberg blocks, widgets, to now secure and performant production-ready plugins.

✔ Next Steps: publish your plugin to WordPress.org or your own GitHub repository!

#11 Module 11 – Custom Widgets & Sidebars Integration next, using the same glowing interactive format

Module 11 – Custom Widgets & Sidebars Integration

🧩 Module 11 – Custom Widgets & Sidebars Integration

In this module, we’ll create a custom widget that displays a personalized message, and we’ll register a new sidebar where this widget can be placed.


Step 1 — Create the Plugin File

Create a new folder: my-custom-widget Then inside, create my-custom-widget.php:

<?php /** * Plugin Name: My Custom Widget * Description: Adds a simple custom widget and a sidebar to WordPress. * Version: 1.0 * Author: Your Name */ if ( ! defined( 'ABSPATH' ) ) exit; class My_Custom_Widget extends WP_Widget { function __construct() { parent::__construct( 'my_custom_widget', __( 'My Custom Widget', 'text_domain' ), array( 'description' => __( 'Displays a custom message', 'text_domain' ) ) ); } // Widget front-end display public function widget( $args, $instance ) { echo $args['before_widget']; echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ) . $args['after_title']; echo '<p style="color:#00ffa3;">' . esc_html( $instance['message'] ) . '</p>'; echo $args['after_widget']; } // Widget backend form public function form( $instance ) { $title = !empty( $instance['title'] ) ? $instance['title'] : __( 'My Widget', 'text_domain' ); $message = !empty( $instance['message'] ) ? $instance['message'] : __( 'Hello, World!', 'text_domain' ); ?> <p> <label>Title:</label> <input class="widefat" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /> </p> <p> <label>Message:</label> <input class="widefat" name="<?php echo $this->get_field_name('message'); ?>" type="text" value="<?php echo esc_attr( $message ); ?>" /> </p> <?php } // Save widget form values public function update( $new_instance, $old_instance ) { $instance = array(); $instance['title'] = sanitize_text_field( $new_instance['title'] ); $instance['message'] = sanitize_text_field( $new_instance['message'] ); return $instance; } } // Register the widget function register_my_custom_widget() { register_widget( 'My_Custom_Widget' ); } add_action( 'widgets_init', 'register_my_custom_widget' ); // Register a custom sidebar function my_custom_sidebar() { register_sidebar( array( 'name' => __( 'Custom Sidebar', 'text_domain' ), 'id' => 'custom_sidebar', 'before_widget' => '<div class="widget-container">', 'after_widget' => '</div>', 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); } add_action( 'widgets_init', 'my_custom_sidebar' ); ?>

Step 2 — Activate and Test

  1. Place the folder my-custom-widget inside wp-content/plugins/.
  2. Go to Plugins → Activate "My Custom Widget".
  3. Go to Appearance → Widgets (or the block-based widget editor in newer WP).
  4. Find “My Custom Widget” and drag it into “Custom Sidebar.”
  5. Set your custom title and message, then save.
  6. To display sidebar in your theme, add this to sidebar.php or similar:
<?php if ( is_active_sidebar( 'custom_sidebar' ) ) : ?> <aside id="secondary"> <?php dynamic_sidebar( 'custom_sidebar' ); ?> </aside> <?php endif; ?>

✅ Output

When placed in the sidebar, your widget will show:

  • Widget Title (editable from admin)
  • Custom message (editable)
  • Styled automatically by your theme

💡 Notes

  • Widgets are great for dynamic content areas (sidebars, footers, etc.).
  • You can register multiple widgets using the same structure.
  • Widgets can include forms, data from APIs, or even shortcodes.

#10 Module 10 Implentation Steps

 Nice — here’s a clear, practical, step-by-step implementation for Module 10 — Creating Gutenberg (Block Editor) Blocks. I give a no-build approach (works immediately — no npm or build tools) plus an optional modern build path (recommended for production). Follow the steps exactly and you’ll have a working “Hello Block” in the editor.


Quick summary (what you’ll create)

Folder: my-block-plugin/
Files:

  • my-block-plugin.php — plugin bootstrap (registers scripts & block)

  • block/index.js — block editor script (no-build version)

  • block/editor.css — styles for the editor

  • block/style.css — front-end styles


❗ Prerequisites

  • WordPress site with admin access

  • PHP & WP (no extra tooling required for the no-build version)

  • If you want the modern build path: Node.js + npm (optional)


STEP-BY-STEP — No-build approach (fastest)

1) Create plugin folder

Path:

wp-content/plugins/my-block-plugin/

2) Create my-block-plugin.php

File: wp-content/plugins/my-block-plugin/my-block-plugin.php
Paste this full code:

<?php
/**
 * Plugin Name: My Gutenberg Block
 * Description: Adds a simple "Hello Block" (no-build example).
 * Version: 1.0
 * Author: Your Name
 */

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

function mgb_register_block() {
    // register editor script (no build - using WordPress provided globals)
    wp_register_script(
        'mgb-block-js',
        plugins_url( 'block/index.js', __FILE__ ),
        array( 'wp-blocks', 'wp-element', 'wp-editor' ), // dependencies
        filemtime( plugin_dir_path( __FILE__ ) . 'block/index.js' )
    );

    wp_register_style(
        'mgb-block-editor-style',
        plugins_url( 'block/editor.css', __FILE__ ),
        array(),
        filemtime( plugin_dir_path( __FILE__ ) . 'block/editor.css' )
    );

    wp_register_style(
        'mgb-block-style',
        plugins_url( 'block/style.css', __FILE__ ),
        array(),
        filemtime( plugin_dir_path( __FILE__ ) . 'block/style.css' )
    );

    register_block_type( 'mgb/hello-block', array(
        'editor_script' => 'mgb-block-js',
        'editor_style'  => 'mgb-block-editor-style',
        'style'         => 'mgb-block-style',
    ) );
}
add_action( 'init', 'mgb_register_block' );

Explanation: this registers the JS and CSS, and declares the block type mgb/hello-block. filemtime() forces browsers to reload when you change files.


3) Create block/index.js (no-build, uses wp.* globals)

File: wp-content/plugins/my-block-plugin/block/index.js
Paste:

( function ( wp ) {
    const el = wp.element.createElement;
    const registerBlockType = wp.blocks.registerBlockType;
    const { RichText } = wp.blockEditor || wp.editor; // compatibility

    registerBlockType( 'mgb/hello-block', {
        title: 'Hello Block',
        icon: 'smiley',
        category: 'widgets',
        attributes: {
            content: {
                type: 'string',
                source: 'html',
                selector: 'p'
            }
        },
        edit: function ( props ) {
            const content = props.attributes.content;
            return el(
                'div',
                { className: 'mgb-hello-block' },
                el( RichText, {
                    tagName: 'p',
                    onChange: function ( value ) { props.setAttributes( { content: value } ); },
                    value: content,
                    placeholder: 'Say hello... 👋'
                } )
            );
        },
        save: function ( props ) {
            return el( wp.blockEditor.RichText.Content || wp.RichText.Content, {
                tagName: 'p',
                value: props.attributes.content
            } );
        }
    } );
} )( window.wp );

Notes:

  • This file uses WordPress global wp object — no bundler needed.

  • Compatible with many WP versions by checking blockEditor vs editor.


4) Create editor & front-end CSS

block/editor.css (editor view styling):

.mgb-hello-block {
  background: #002b36;
  border-radius: 10px;
  padding: 10px;
  color: #00ffa3;
}

block/style.css (front-end styling):

.mgb-hello-block p {
  font-size: 18px;
  color: #00d4ff;
  margin: 0;
}

5) Activate plugin & test

  1. Zip or copy folder to wp-content/plugins/ (already done).

  2. In WP Admin: Plugins → Activate “My Gutenberg Block”.

  3. Edit or create a post: Add block → search “Hello Block” (category: Widgets).

  4. Type text in the block, save/update post, view on front-end.

If block does not appear: flush caches, ensure WP version >= 5.x (Gutenberg built-in).


Troubleshooting (no-build)

  • If block fails to load, open browser console — missing wp globals indicate block script loaded on front-end instead of editor. Ensure editor_script is registered — you used register_block_type() correctly.

  • If icons or editor UI missing, check dependencies: 'wp-blocks','wp-element','wp-editor'. For newer WP, consider 'wp-block-editor' too.

  • If CSS not loading: check file paths and permissions.


OPTIONAL: Modern build path (recommended for production)

If you want JSX, ESNext, and modules — use @wordpress/scripts. Short steps:

  1. cd my-block-plugin/block

  2. npm init -y

  3. npm install @wordpress/scripts --save-dev

  4. Create src/index.js (JSX) and build/index.js generated by the tool.

  5. Add package.json scripts:

"scripts": {
  "build": "wp-scripts build",
  "start": "wp-scripts start"
}
  1. Example src/index.js (JSX version):

import { registerBlockType } from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';
import { createElement } from '@wordpress/element';

registerBlockType('mgb/hello-block', {
  title: 'Hello Block',
  icon: 'smiley',
  category: 'widgets',
  attributes: {
    content: { type: 'string', source: 'html', selector: 'p' }
  },
  edit: ({ attributes, setAttributes }) => (
    createElement('div', { className: 'mgb-hello-block' },
      createElement(RichText, {
        tagName: 'p',
        onChange: value => setAttributes({ content: value }),
        value: attributes.content,
        placeholder: 'Say hello... 👋'
      })
    )
  ),
  save: ({ attributes }) => (
    createElement(RichText.Content, {
      tagName: 'p',
      value: attributes.content
    })
  )
});
  1. Run npm run build → this produces build/index.js. Update PHP to point to block/build/index.js instead of block/index.js.

Advantages: cleaner code, JSX, compatibility with future WP patterns.


Extra tips & best practices

  • Use editor_style and style keys in register_block_type() to keep editor and front-end styles separate.

  • Use attributes carefully — define types and sources to keep data serializable.

  • For complex blocks, use InspectorControls to add sidebar controls.

  • For localization, wrap strings with __() and load textdomain in PHP if you plan to translate.


Quick checklist before testing

  • Files in correct places

  • Plugin activated

  • Browser console clear of errors

  • WP version supports block editor

  • Clear caches if styles or scripts don’t update


If you want, I can:

  • Generate the exact plugin ZIP you can download and install, or

  • Convert the no-build JS to a modern @wordpress/scripts project with package.json and full src/ build files ready to npm install + npm run build.

Which next?

#10 Module 10 – Creating Gutenberg (Block Editor) Blocks for Your Plugin

Module 10 – Gutenberg Blocks for Your Plugin | WordPress Plugin Development

🧱 Module 10: Creating Gutenberg Blocks for Your Plugin

Gutenberg (the Block Editor) allows you to add **custom content blocks** visually in WordPress posts and pages. In this module, we’ll build a **“Hello Block”** that you can insert directly into the editor — all powered by your plugin.

Step 1 – Folder Setup

Create a new folder inside your plugin:

my-block-plugin/ │ ├── my-block-plugin.php └── block/ ├── index.js ├── editor.css └── style.css

These files handle the PHP registration, block editor JavaScript, and styles.

Step 2 – Register the Block Script in PHP

'mgb-block-js', 'style' => 'mgb-block-style', )); } add_action('init', 'mgb_register_block'); ?>

📘 This registers your JS and declares the block type mgb/hello-block.

Step 3 – Create the Block JavaScript (index.js)

const { registerBlockType } = wp.blocks; const { RichText } = wp.blockEditor; registerBlockType('mgb/hello-block', { title: 'Hello Block', icon: 'smiley', category: 'widgets', attributes: { content: { type: 'string', source: 'html', selector: 'p' } }, edit: (props) => { const { attributes: { content }, setAttributes } = props; return ( wp.element.createElement( 'div', { className: 'mgb-hello-block' }, wp.element.createElement(RichText, { tagName: 'p', onChange: (value) => setAttributes({ content: value }), value: content, placeholder: 'Say hello... 👋' }) ) ); }, save: (props) => { return wp.element.createElement(RichText.Content, { tagName: 'p', value: props.attributes.content }); } });

📘 You now have a block that lets users type text and see it saved to the post!

Step 4 – Add Simple Styles

editor.css (for the block editor):

.mgb-hello-block { background: #002b36; border-radius: 10px; padding: 10px; color: #00ffa3; }

style.css (front-end):

.mgb-hello-block p { font-size: 18px; color: #00d4ff; }

Step 5 – Test the Block

  1. Go to Plugins → Activate “My Gutenberg Block”.
  2. Open the block editor for any post/page.
  3. Click ➕ → Search “Hello Block”.
  4. Type your text → Update the page → View it live.

✅ You’ve built a working custom Gutenberg block!

Bonus – Register Multiple Blocks

You can register more by repeating registerBlockType() in index.js with different names.

✅ Code copied!
© 2025 WordPress Plugin Tutorial | Module 10 – Gutenberg Blocks

#9 Module 9 Implementaion Steps

 Absolutely 👍 — here’s a clear, practical step-by-step guide to implement everything from Module 9 – Using the REST API & Fetch Requests, directly in your WordPress plugin.

You can follow this in your existing plugin folder (like my-first-plugin) or a new one such as mfp-rest-api.


Module 9 — REST API & Fetch Requests Implementation Steps

🧩 Goal:

You’ll learn to:

  • Create custom REST API endpoints (GET & POST)

  • Fetch data dynamically with JavaScript (fetch())

  • Send form data to your WordPress backend via REST API


Step 1: Create or Open Your Plugin File

Go to:
/wp-content/plugins/mfp-rest-api/mfp-rest-api.php

Paste the following header:

<?php
/*
Plugin Name: MFP REST API Example
Description: A simple example of custom REST API + Fetch integration.
Version: 1.0
Author: Your Name
*/

Step 2: Register a REST API GET Endpoint

Add this code to the same file:

function mfp_register_rest_endpoint() {
    register_rest_route('mfp/v1', '/message', array(
        'methods' => 'GET',
        'callback' => 'mfp_get_message'
    ));
}
add_action('rest_api_init', 'mfp_register_rest_endpoint');

function mfp_get_message() {
    return array('message' => 'Hello from the REST API 🚀');
}

🔍 Test it:

  1. Activate your plugin in WordPress → Plugins.

  2. Visit this URL in your browser:

    https://your-site.com/wp-json/mfp/v1/message
    
  3. You’ll see:

    {"message": "Hello from the REST API 🚀"}
    

Step 3: Create a Shortcode to Display API Data on Front-End

Now we’ll create a shortcode that fetches the above data dynamically.

function mfp_fetch_example_shortcode() {
    ob_start(); ?>
    <div id="mfp-api-output" style="color:#00ffa3;">Loading message...</div>
    <script>
        fetch('<?php echo site_url('/wp-json/mfp/v1/message'); ?>')
            .then(response => response.json())
            .then(data => {
                document.getElementById('mfp-api-output').innerHTML =
                    '<strong>API Says:</strong> ' + data.message;
            })
            .catch(error => {
                document.getElementById('mfp-api-output').innerHTML = 'Error loading API data 😢';
            });
    </script>
    <?php
    return ob_get_clean();
}
add_shortcode('mfp_api_demo', 'mfp_fetch_example_shortcode');

🔍 Test it:

Add this shortcode in any page or post:

[mfp_api_demo]

You’ll see live data from your REST API displayed on the front-end.


Step 4: Create a REST API POST Endpoint

Now, let’s make an endpoint that accepts user data.

function mfp_register_post_endpoint() {
    register_rest_route('mfp/v1', '/submit', array(
        'methods' => 'POST',
        'callback' => 'mfp_submit_data'
    ));
}
add_action('rest_api_init', 'mfp_register_post_endpoint');

function mfp_submit_data($data) {
    $params = $data->get_json_params();
    $name = sanitize_text_field($params['name']);
    return array('response' => 'Hi ' . $name . ', your data was received ✅');
}

🔍 Test it (manually with cURL or Postman):

POST to:

https://your-site.com/wp-json/mfp/v1/submit

Body (JSON):

{ "name": "Ravi" }

You should get:

{ "response": "Hi Ravi, your data was received ✅" }

Step 5: Front-End Form to Submit Data via Fetch

Now add this shortcode:

function mfp_api_post_form_shortcode() {
    ob_start(); ?>
    <form id="mfp-post-form">
        <label>Your Name:</label><br>
        <input type="text" id="mfp_name" required><br><br>
        <button type="submit">Send via REST API</button>
    </form>
    <div id="mfp_result" style="color:#00ffa3;margin-top:10px;"></div>

    <script>
    document.getElementById('mfp-post-form').addEventListener('submit', function(e) {
        e.preventDefault();
        const name = document.getElementById('mfp_name').value;

        fetch('<?php echo site_url('/wp-json/mfp/v1/submit'); ?>', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ name: name })
        })
        .then(response => response.json())
        .then(data => {
            document.getElementById('mfp_result').innerHTML = data.response;
        })
        .catch(err => {
            document.getElementById('mfp_result').innerHTML = '❌ Error sending data.';
        });
    });
    </script>
    <?php
    return ob_get_clean();
}
add_shortcode('mfp_api_form', 'mfp_api_post_form_shortcode');

🔍 Test it:

Add this shortcode to any WordPress page:

[mfp_api_form]

Type your name → click “Send via REST API”
✅ It will instantly show your personalized response from the API.


Step 6: Secure Your Endpoints (Optional)

To restrict access to logged-in users only, modify the route like:

register_rest_route('mfp/v1', '/submit', array(
    'methods' => 'POST',
    'callback' => 'mfp_submit_data',
    'permission_callback' => function() {
        return is_user_logged_in();
    }
));

🧠 Concepts You’ve Learned

Concept Description
register_rest_route() Create custom API endpoints
wp-json/ Default REST API base URL
fetch() JavaScript method to call APIs
sanitize_text_field() Clean user input
add_shortcode() Display dynamic API data on front-end
POST vs GET Sending vs retrieving data

💡 Use Cases

  • Build dynamic dashboards

  • Create single-page plugin interfaces

  • Build React/Vue front-ends powered by WordPress

  • Send or receive data from mobile apps


Would you like me to continue with Module 10 – Creating Gutenberg (Block Editor) Blocks for Your Plugin next, in the same glowing interactive HTML format?

#9 Module 9 – Using the REST API & Fetch Requests

Module 9 – Using the REST API & Fetch Requests | WordPress Plugin Tutorial

🌐 Module 9: Using the REST API & Fetch Requests

The WordPress REST API lets you send and receive data via HTTP — perfect for dynamic front-end interactions without reloading the page. In this module, you’ll create a custom REST API endpoint and connect it to JavaScript using the fetch() API.

Step 1 – Register a Custom REST API Endpoint

(📋 You can copy or edit directly below)

    
function mfp_register_rest_endpoint() { register_rest_route('mfp/v1', '/message', array( 'methods' => 'GET', 'callback' => 'mfp_get_message' )); } add_action('rest_api_init', 'mfp_register_rest_endpoint'); function mfp_get_message($data) { return array('message' => 'Hello from the REST API 🚀'); }

📘 This registers a new API endpoint at https://yourwebsite.com/wp-json/mfp/v1/message Visit it in your browser to see the JSON response.

Step 2 – Create a Front-End Shortcode with JavaScript Fetch

    
function mfp_fetch_example_shortcode() { ob_start(); ?> <div id="mfp-api-output" style="padding:10px;color:#00ffa3;"> Loading message... </div> <script> fetch('') .then(response => response.json()) .then(data => { document.getElementById('mfp-api-output').innerHTML = '<strong>API Says:</strong> ' + data.message; }) .catch(error => { document.getElementById('mfp-api-output').innerHTML = 'Error loading API data 😢'; console.error(error); }); </script> <?php return ob_get_clean(); } add_shortcode('mfp_api_demo', 'mfp_fetch_example_shortcode');

📘 Use the shortcode [mfp_api_demo] in a page or post to see your REST API data displayed live via JavaScript.

Step 3 – Add a POST Endpoint (Send Data from JS)

    
function mfp_register_post_endpoint() { register_rest_route('mfp/v1', '/submit', array( 'methods' => 'POST', 'callback' => 'mfp_submit_data' )); } add_action('rest_api_init', 'mfp_register_post_endpoint'); function mfp_submit_data($data) { $params = $data->get_json_params(); $name = sanitize_text_field($params['name']); return array('response' => 'Hi ' . $name . ', your data was received ✅'); }

📘 Now you can POST data to /wp-json/mfp/v1/submit and get a JSON response!

Step 4 – Connect Front-End Form to the POST API

    
function mfp_api_post_form_shortcode() { ob_start(); ?> <form id="mfp-post-form"> <label>Your Name:</label><br> <input type="text" id="mfp_name" required /><br><br> <button type="submit">Send via REST API</button> </form> <div id="mfp_result" style="color:#00ffa3;margin-top:10px;"></div> <script> document.getElementById('mfp-post-form').addEventListener('submit', function(e) { e.preventDefault(); const name = document.getElementById('mfp_name').value; fetch('', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ name: name }) }) .then(response => response.json()) .then(data => { document.getElementById('mfp_result').innerHTML = data.response; }) .catch(err => { document.getElementById('mfp_result').innerHTML = '❌ Error sending data.'; console.error(err); }); }); </script> <?php return ob_get_clean(); } add_shortcode('mfp_api_form', 'mfp_api_post_form_shortcode');

📘 Use [mfp_api_form] in a page — it sends data to the REST API and displays the result instantly.

✅ Code copied to clipboard!
© 2025 WordPress Plugin Tutorial | Module 9 – Using the REST API & Fetch Requests

#8 Module 8 Implementation Steps

 Absolutely ✅ — here’s your step-by-step guide to implement everything from Module 8: Shortcodes & Front-End Forms in your own WordPress plugin.


⚡ Module 8 — Shortcodes & Front-End Forms

🎯 Goal

You’ll learn how to:

  • Create simple and dynamic shortcodes

  • Display front-end forms

  • Handle form submissions

  • Add nonce-based security


🪜 Step 1 – Open or Create Your Plugin File

Go to:

/wp-content/plugins/my-first-plugin/

Create (or open) your main file — e.g. my-first-plugin.php — and ensure it starts with:

<?php
/**
 * Plugin Name: My First Plugin
 * Description: Learning WordPress Plugin Development – Module 8
 * Version: 1.0
 * Author: You
 */

🪜 Step 2 – Add a Basic Shortcode

Inside the same plugin file, add:

function mfp_simple_shortcode() {
    return "<h3>Welcome to My Plugin Form!</h3>";
}
add_shortcode('mfp_hello', 'mfp_simple_shortcode');

Test:
In a WordPress page or post, insert:

[mfp_hello]

It should show the message “Welcome to My Plugin Form!” on the front-end.


🪜 Step 3 – Create a Front-End Form with Shortcode

Add this function below the first one:

function mfp_contact_form_shortcode() {
    ob_start(); ?>
    <form method="post">
        <label>Your Name:</label><br>
        <input type="text" name="mfp_name" required><br><br>
        <label>Your Message:</label><br>
        <textarea name="mfp_message" required></textarea><br><br>
        <input type="submit" name="mfp_submit" value="Send">
    </form>
    <?php
    return ob_get_clean();
}
add_shortcode('mfp_form', 'mfp_contact_form_shortcode');

Test:
Insert this shortcode in a page:

[mfp_form]

You’ll see a working contact form (though not yet saving or displaying messages).


🪜 Step 4 – Process Form Submissions

Add this handler below:

function mfp_handle_form_submission() {
    if (isset($_POST['mfp_submit'])) {
        $name = sanitize_text_field($_POST['mfp_name']);
        $msg  = sanitize_textarea_field($_POST['mfp_message']);
        echo '<div style="color:#00ffa3;">Thank you, ' . esc_html($name) .
             '!<br>Your message: ' . esc_html($msg) . '</div>';
    }
}
add_action('wp_footer', 'mfp_handle_form_submission');

Test:
Reload your form page, fill it in, click Send, and see your confirmation text appear.


🪜 Step 5 – Add Nonce for Security (Recommended)

Add this secure version to your plugin:

function mfp_contact_form_with_nonce() {
    ob_start(); ?>
    <form method="post">
        <?php wp_nonce_field('mfp_form_action', 'mfp_form_nonce'); ?>
        <label>Your Name:</label><br>
        <input type="text" name="mfp_name" required><br><br>
        <label>Message:</label><br>
        <textarea name="mfp_message" required></textarea><br><br>
        <input type="submit" name="mfp_submit" value="Send Securely">
    </form>
    <?php
    return ob_get_clean();
}
add_shortcode('mfp_secure_form', 'mfp_contact_form_with_nonce');

function mfp_secure_form_handler() {
    if (isset($_POST['mfp_submit']) &&
        isset($_POST['mfp_form_nonce']) &&
        wp_verify_nonce($_POST['mfp_form_nonce'], 'mfp_form_action')) {

        $name = sanitize_text_field($_POST['mfp_name']);
        $msg  = sanitize_textarea_field($_POST['mfp_message']);
        echo '<div style="color:#00ffa3;">✅ Secure message from ' .
             esc_html($name) . ': ' . esc_html($msg) . '</div>';
    }
}
add_action('wp_footer', 'mfp_secure_form_handler');

Test:
Use [mfp_secure_form] in a page or post — the form now includes a hidden nonce field for secure submissions.


🪜 Step 6 – (Optionally) Save or Email the Form Data

Inside your handler, instead of echoing, you can:

wp_mail('you@example.com', 'New Form Submission',
        "From: $name\nMessage:\n$msg");

Or insert into a custom table using $wpdb.


🪜 Step 7 – Final Verification

  1. Activate your plugin from Dashboard → Plugins.

  2. Create a new Page with the shortcode [mfp_secure_form].

  3. Fill and submit the form.

  4. Confirm that:

    • Data sanitization works

    • Nonce verification prevents resubmission by URL reload

    • Output or email is generated properly


✅ Module 8 Summary

Feature Purpose
add_shortcode() Register shortcodes like [mfp_form]
ob_start() / ob_get_clean() Capture & return HTML
$_POST + sanitize_*() Handle and clean user input
wp_nonce_field() Add hidden security tokens
wp_verify_nonce() Verify submitted forms
add_action('wp_footer') Run form logic at page end

💡 Pro Tips

  • Use wp_enqueue_script() and AJAX (coming in Module 9) for smoother form submissions.

  • Always sanitize and escape user data before saving or displaying.

  • You can turn this form into a reusable contact-form plugin easily!


Would you like me to continue with Module 9 – Using the REST API & Fetch Requests next (same glowing interactive HTML format)?

#8 Module 8: Shortcodes & Front-End Forms

Module 8 – Shortcodes & Front-End Forms | WordPress Plugin Development

⚡ Module 8: Shortcodes & Front-End Forms

Shortcodes let you add custom content to posts or pages using simple tags like [my_form]. In this module, you’ll build a form visible on the frontend and process it securely — all inside your plugin!

Step 1 – Register a Simple Shortcode

(📋 Copy or edit directly below)

    
function mfp_simple_shortcode() { return "<h3>Welcome to My Plugin Form!</h3>"; } add_shortcode('mfp_hello', 'mfp_simple_shortcode');

📘 Now add [mfp_hello] to any post or page — it displays “Welcome to My Plugin Form!”.

Step 2 – Create a Front-End Form via Shortcode

    
function mfp_contact_form_shortcode() { ob_start(); ?> <form method="post"> <label>Your Name:</label><br> <input type="text" name="mfp_name" required /><br><br> <label>Your Message:</label><br> <textarea name="mfp_message" required></textarea><br><br> <input type="submit" name="mfp_submit" value="Send" /> </form> <?php return ob_get_clean(); } add_shortcode('mfp_form', 'mfp_contact_form_shortcode');

📘 Use the shortcode [mfp_form] on a page to display the form.

Step 3 – Handle Form Submission (Securely)

    
function mfp_handle_form_submission() { if (isset($_POST['mfp_submit'])) { $name = sanitize_text_field($_POST['mfp_name']); $msg = sanitize_textarea_field($_POST['mfp_message']); // You can save to DB, send email, etc. echo '<div style="color:#00ffa3">Thank you, ' . esc_html($name) . '!<br>Your message: ' . esc_html($msg) . '</div>'; } } add_action('wp_footer', 'mfp_handle_form_submission');

📘 This hook processes the form when it’s submitted — right before the page ends. You could also save the data to a custom table or send an email.

Step 4 – Optional: Add Nonce for Security

    
function mfp_contact_form_with_nonce() { ob_start(); ?> <form method="post"> <?php wp_nonce_field('mfp_form_action', 'mfp_form_nonce'); ?> <label>Your Name:</label><br> <input type="text" name="mfp_name" required /><br><br> <label>Message:</label><br> <textarea name="mfp_message" required></textarea><br><br> <input type="submit" name="mfp_submit" value="Send Securely" /> </form> <?php return ob_get_clean(); } add_shortcode('mfp_secure_form', 'mfp_contact_form_with_nonce'); function mfp_secure_form_handler() { if (isset($_POST['mfp_submit']) && isset($_POST['mfp_form_nonce']) && wp_verify_nonce($_POST['mfp_form_nonce'], 'mfp_form_action')) { $name = sanitize_text_field($_POST['mfp_name']); $msg = sanitize_textarea_field($_POST['mfp_message']); echo '<div style="color:#00ffa3">✅ Secure message from ' . esc_html($name) . ': ' . esc_html($msg) . '</div>'; } } add_action('wp_footer', 'mfp_secure_form_handler');

📘 Use [mfp_secure_form] to show a secure front-end form that protects against CSRF attacks.

✅ Code copied to clipboard!
© 2025 WordPress Plugin Tutorial | Module 8 – Shortcodes & Front-End Forms

#7 Steps - Implementation

Absolutely ✅ — here’s a clear, practical step-by-step guide to implement Module 7: Custom Post Types & Meta Boxes in your own WordPress plugin.


🧱 Module 7 — Implementation Steps

Topic: Custom Post Types & Meta Boxes


🪜 Step 1 – Create or Open Your Plugin File

  • Go to your plugin folder, e.g.

    /wp-content/plugins/my-first-plugin/
    
  • Open or create your main plugin file (for example, my-first-plugin.php).

Make sure the header comment exists:

<?php
/**
 * Plugin Name: My First Plugin
 * Description: Learning WordPress Plugin Development – Module 7.
 * Version: 1.0
 * Author: You
 */

🪜 Step 2 – Register a Custom Post Type (CPT)

Add this function below the header:

function mfp_register_books_cpt() {
    $labels = array(
        'name' => 'Books',
        'singular_name' => 'Book',
        'add_new_item' => 'Add New Book',
        'edit_item' => 'Edit Book',
        'menu_name' => 'Books'
    );

    $args = array(
        'labels' => $labels,
        'public' => true,
        'show_in_menu' => true,
        'menu_icon' => 'dashicons-book-alt',
        'supports' => array('title', 'editor', 'thumbnail'),
        'has_archive' => true,
    );

    register_post_type('book', $args);
}
add_action('init', 'mfp_register_books_cpt');

📘 What it does:
Adds a new “Books” section in the WordPress admin sidebar.


🪜 Step 3 – Add a Meta Box for Extra Fields

Add the meta box to your new post type:

function mfp_add_book_meta_box() {
    add_meta_box(
        'mfp_book_details',
        'Book Details',
        'mfp_render_book_meta_box',
        'book',
        'normal',
        'default'
    );
}
add_action('add_meta_boxes', 'mfp_add_book_meta_box');

Now create the callback to display the input:

function mfp_render_book_meta_box($post) {
    $author = get_post_meta($post->ID, '_mfp_book_author', true);
    wp_nonce_field('mfp_save_book_meta', 'mfp_book_meta_nonce');
    echo '<label>Author Name:</label><br>';
    echo '<input type="text" name="mfp_book_author" value="' . esc_attr($author) . '" style="width:100%;" />';
}

📘 What it does:
Adds a new “Author Name” field under the “Book Details” box when editing a Book.


🪜 Step 4 – Save the Meta Box Data

Add a save handler:

function mfp_save_book_meta($post_id) {
    if (!isset($_POST['mfp_book_meta_nonce']) ||
        !wp_verify_nonce($_POST['mfp_book_meta_nonce'], 'mfp_save_book_meta')) {
        return;
    }

    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;

    if (isset($_POST['mfp_book_author'])) {
        update_post_meta($post_id, '_mfp_book_author', sanitize_text_field($_POST['mfp_book_author']));
    }
}
add_action('save_post_book', 'mfp_save_book_meta');

📘 What it does:
Securely saves the entered author name as post meta every time you save a Book.


🪜 Step 5 – Test It

  1. In the WordPress admin panel → Books > Add New.

  2. You’ll see the Book Details meta box below the content area.

  3. Enter a title, description, and author name, then click Publish.

  4. Verify the author name is saved and editable on future edits.


🪜 Step 6 – Display Meta Data (Optional)

If you want to display the Author Name on the frontend (single book template):

echo '<p><strong>Author:</strong> ' . esc_html(get_post_meta(get_the_ID(), '_mfp_book_author', true)) . '</p>';

You can place that in your theme’s single-book.php template.


✅ Summary

Feature Purpose
register_post_type() Adds a new content type (Books)
add_meta_box() Creates an editable section in the editor
get_post_meta() / update_post_meta() Retrieves and saves extra field data
Nonces Prevents unauthorized form submissions
save_post_{posttype} hook Runs when a CPT item is saved

💡 Pro Tips

  • Always sanitize inputs using sanitize_text_field(), esc_attr(), etc.

  • Add multiple meta boxes for richer data (price, ISBN, etc.).

  • Use supports in CPT to add/remove features like comments or excerpts.



#7 Module 7: Custom Post Types & Meta Boxes

WordPress Plugin Tutorial – Module 7: Custom Post Types & Meta Boxes

🧱 Module 7: Custom Post Types & Meta Boxes

Custom Post Types (CPTs) let you store structured content like “Books,” “Events,” or “Products.” Meta Boxes let you add custom fields for each item — like “Author,” “Price,” or “Date.”

Step 1 – Register a Custom Post Type

(📋 You can copy or edit directly below)

    
function mfp_register_books_cpt() { $labels = array( 'name' => 'Books', 'singular_name' => 'Book', 'add_new_item' => 'Add New Book', 'edit_item' => 'Edit Book', 'menu_name' => 'Books' ); $args = array( 'labels' => $labels, 'public' => true, 'show_in_menu' => true, 'menu_icon' => 'dashicons-book-alt', 'supports' => array('title', 'editor', 'thumbnail'), 'has_archive' => true, ); register_post_type('book', $args); } add_action('init', 'mfp_register_books_cpt');

Step 2 – Add a Meta Box to the CPT Editor

    
function mfp_add_book_meta_box() { add_meta_box( 'mfp_book_details', 'Book Details', 'mfp_render_book_meta_box', 'book', 'normal', 'default' ); } add_action('add_meta_boxes', 'mfp_add_book_meta_box'); function mfp_render_book_meta_box($post) { $author = get_post_meta($post->ID, '_mfp_book_author', true); wp_nonce_field('mfp_save_book_meta', 'mfp_book_meta_nonce'); echo '<label>Author Name:</label><br>'; echo '<input type="text" name="mfp_book_author" value="' . esc_attr($author) . '" style="width:100%;" />'; }

Step 3 – Save the Meta Box Data

    
function mfp_save_book_meta($post_id) { if (!isset($_POST['mfp_book_meta_nonce']) || !wp_verify_nonce($_POST['mfp_book_meta_nonce'], 'mfp_save_book_meta')) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return; if (isset($_POST['mfp_book_author'])) { update_post_meta($post_id, '_mfp_book_author', sanitize_text_field($_POST['mfp_book_author'])); } } add_action('save_post_book', 'mfp_save_book_meta');

✅ Now your WordPress site has a new “Books” post type with an editable “Author Name” field. Try adding a few Books from the dashboard → Books → Add New!

✅ Code copied to clipboard!
© 2025 WordPress Plugin Tutorial | Module 7 – Custom Post Types & Meta Boxes

#6 Module 6: AJAX in Plugins (Dynamic Data Handling)

WordPress Plugin Tutorial – Module 6: AJAX in Plugins

🧩 Module 6: AJAX in Plugins (Dynamic Data Handling)

AJAX allows your plugin to fetch or update data without reloading the page. In this module, we’ll build a small example where a button loads a message from the server asynchronously.

Step 1 – Enqueue Script and Add a Button

(📋 You can copy or edit directly below)

    
function mfp_enqueue_ajax_script() { wp_enqueue_script( 'mfp-ajax-script', plugin_dir_url(__FILE__) . 'mfp-ajax.js', array('jquery'), '1.0', true ); wp_localize_script('mfp-ajax-script', 'mfp_ajax_obj', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('mfp_ajax_nonce') )); } add_action('wp_enqueue_scripts', 'mfp_enqueue_ajax_script'); function mfp_display_ajax_button() { echo '<div style="text-align:center;margin:20px;"> <button id="mfp-ajax-btn" style="padding:10px 20px;background:#00d4ff;color:#000;border:none;border-radius:6px;cursor:pointer;"> Load Message via AJAX </button> <div id="mfp-ajax-result" style="margin-top:15px;color:#00ffa3;"></div> </div>'; } add_action('wp_footer', 'mfp_display_ajax_button');

Step 2 – Handle AJAX Request (PHP)

    
add_action('wp_ajax_mfp_get_message', 'mfp_get_message_callback'); add_action('wp_ajax_nopriv_mfp_get_message', 'mfp_get_message_callback'); function mfp_get_message_callback() { check_ajax_referer('mfp_ajax_nonce', 'nonce'); wp_send_json_success('AJAX works! 🎉 This data came from PHP.'); }

Step 3 – Create JavaScript File (mfp-ajax.js)

    
jQuery(document).ready(function($) { $('#mfp-ajax-btn').on('click', function() { $('#mfp-ajax-result').text('Loading...'); $.post(mfp_ajax_obj.ajax_url, { action: 'mfp_get_message', nonce: mfp_ajax_obj.nonce }, function(response) { if (response.success) { $('#mfp-ajax-result').text(response.data); } else { $('#mfp-ajax-result').text('Error occurred.'); } }); }); });
✅ Code copied to clipboard!
© 2025 WordPress Plugin Tutorial | Module 6 – AJAX Example with Prism.js

#5 Module 5: Custom Admin Tables (Listing Plugin Data)

WordPress Plugin Tutorial - Modules 1 to 5

🎓 WordPress Plugin Development Tutorial (Modules 1–5)

Learn to build WordPress plugins step-by-step. Each module includes real working code examples, Prism.js highlighting, and glowing animated progress bars.


🧩 Module 5: Custom Admin Tables (Listing Plugin Data)

Let’s learn how to show stored plugin data inside a custom admin table.

Step 1: Create a Table on Plugin Activation

register_activation_hook(__FILE__, 'mfp_create_table'); function mfp_create_table() { global $wpdb; $table_name = $wpdb->prefix . 'mfp_records'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, created datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); }

Step 2: Add Sample Data (Optional)

function mfp_insert_sample_data() { global $wpdb; $table = $wpdb->prefix . 'mfp_records'; $wpdb->insert($table, ['name' => 'First Entry']); $wpdb->insert($table, ['name' => 'Second Entry']); } add_action('admin_init', 'mfp_insert_sample_data');

Step 3: Display Data in Admin Table

function mfp_admin_page_html() { global $wpdb; $table = $wpdb->prefix . 'mfp_records'; $results = $wpdb->get_results("SELECT * FROM $table"); ?> <div class="wrap"> <h1>My Plugin Data Table</h1> <table class="widefat fixed"> <thead><tr><th>ID</th><th>Name</th><th>Created</th></tr></thead> <tbody> <?php foreach ($results as $row): ?> <tr> <td><?php echo esc_html($row->id); ?></td> <td><?php echo esc_html($row->name); ?></td> <td><?php echo esc_html($row->created); ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php }

✅ Now, your plugin can create a custom database table and display records inside the WordPress Admin area!


© 2025 WordPress Plugin Tutorial | Modules 1–5 | Built with Prism.js + Animated Progress Bars

#4 Module 1-4 Creating and Saving Plugin Settings (Options API)

WordPress Plugin Tutorial - Modules 1 to 4

🎓 WordPress Plugin Development Tutorial (Modules 1–4)

Learn WordPress plugin development from scratch to advanced concepts. Each module includes ready-to-copy examples with live progress bars and Prism.js highlighting.


🧩 Module 1: Your First Plugin

This simple plugin adds a “Hello, World!” message to your site footer.

<?php /* Plugin Name: My First Plugin Description: A simple starter plugin. Version: 1.0 Author: Your Name */ function mfp_hello_world() { echo "<p style='color:green; text-align:center;'>Hello, World! My first plugin works 🎉</p>"; } add_action('wp_footer', 'mfp_hello_world');

🧩 Module 2: Hooks & Filters

✨ Example: Action Hook

function my_footer_message() { echo "<p style='text-align:center; color:#00d4ff;'>Thank you for visiting my site!</p>"; } add_action('wp_footer', 'my_footer_message');

🧠 Example: Filter Hook

function add_custom_signature($content) { if (is_single()) { $content .= '<p><em>– Thanks for reading!</em></p>'; } return $content; } add_filter('the_content', 'add_custom_signature');

🧩 Module 3: Admin Menu & Settings Page

Now we’ll create an admin menu inside your WordPress Dashboard.

function mfp_add_admin_menu() { add_menu_page( 'My Plugin Settings', 'My Plugin', 'manage_options', 'my-plugin-settings', 'mfp_admin_page_html', 'dashicons-admin-generic', 20 ); } add_action('admin_menu', 'mfp_add_admin_menu'); function mfp_admin_page_html() { if (!current_user_can('manage_options')) return; echo '<div class="wrap">'; echo '<h1>My Plugin Settings</h1>'; echo '<p>Welcome to your custom settings page!</p>'; echo '</div>'; }

🧩 Module 4: Creating and Saving Plugin Settings (Options API)

Now let’s make our settings page functional using WordPress’s built-in Options API.

Step 1: Register the Setting

add_action('admin_init', 'mfp_register_settings'); function mfp_register_settings() { register_setting('mfp_options_group', 'mfp_custom_message'); }

Step 2: Update the Settings Page with a Form

function mfp_admin_page_html() { if (!current_user_can('manage_options')) return; ?> <div class="wrap"> <h1>My Plugin Settings</h1> <form method="post" action="options.php"> <?php settings_fields('mfp_options_group'); ?> <label for="mfp_custom_message">Custom Footer Message:</label><br> <input type="text" name="mfp_custom_message" id="mfp_custom_message" value="<?php echo esc_attr(get_option('mfp_custom_message', '')); ?>" style="width:300px;" /> <?php submit_button(); ?> </form> </div> <?php }

Step 3: Use the Saved Setting

add_action('wp_footer', 'mfp_display_custom_message'); function mfp_display_custom_message() { $message = get_option('mfp_custom_message', ''); if (!empty($message)) { echo '<p style="text-align:center; color:#00ffa3;">' . esc_html($message) . '</p>'; } }

✅ That’s it! Your plugin now has a working settings page and dynamically displays a user-defined message in the site footer.


© 2025 WordPress Plugin Learning Demo | Modules 1–4 | Built with Prism.js + Animated Progress Bars

#3+ Modified Module 3

WordPress Plugin Tutorial - Modules 1 to 3

🎓 WordPress Plugin Development Tutorial

Learn WordPress plugin development step-by-step — each module includes copyable examples with live progress bars powered by Prism.js.


🧩 Module 1: Your First Plugin

This simple plugin adds a “Hello, World!” message to your site footer.

<?php /* Plugin Name: My First Plugin Description: A simple starter plugin. Version: 1.0 Author: Your Name */ function mfp_hello_world() { echo "<p style='color:green; text-align:center;'>Hello, World! My first plugin works 🎉</p>"; } add_action('wp_footer', 'mfp_hello_world');

🧩 Module 2: Hooks & Filters

✨ Example: Action Hook

function my_footer_message() { echo "<p style='text-align:center; color:#00d4ff;'>Thank you for visiting my site!</p>"; } add_action('wp_footer', 'my_footer_message');

🧠 Example: Filter Hook

function add_custom_signature($content) { if (is_single()) { $content .= '<p><em>– Thanks for reading!</em></p>'; } return $content; } add_filter('the_content', 'add_custom_signature');

🧩 Module 3: Admin Menu & Settings Page

Now we’ll create an admin menu inside your WordPress Dashboard.

function mfp_add_admin_menu() { add_menu_page( 'My Plugin Settings', 'My Plugin', 'manage_options', 'my-plugin-settings', 'mfp_admin_page_html', 'dashicons-admin-generic', 20 ); } add_action('admin_menu', 'mfp_add_admin_menu'); function mfp_admin_page_html() { if (!current_user_can('manage_options')) return; echo '<div class="wrap">'; echo '<h1>My Plugin Settings</h1>'; echo '<p>Welcome to your custom settings page!</p>'; echo '</div>'; }

© 2025 WordPress Plugin Learning Demo | Modules 1–3 | Built with Prism.js + Animated Gradient Progress Bars

Welcome to RMC online Tutorials

WordPress Plugin Development – Full Course Index WordPress Plugin Development 12-Module Learning Portal Mod...