A Guide to Building Your Own Custom WordPress Plugin
In this tutorial, we will dive into the development of a Custom WordPress Plugin using the PHP language. The primary goal is to provide students and beginners, particularly those new to WordPress and PHP, with a reference to learning useful techniques to enhance their knowledge and programming capabilities. I'll be offering sample snippets and a sample WordPress plugin source code that demonstrates our main goal in this tutorial.
What is WordPress?
WordPress is a widely utilized open-source content management system (CMS) that enables users to create and manage websites and blogs. It is written in PHP and employs a MySQL or MariaDB database. WordPress has evolved from its origins as a blogging platform to a versatile CMS utilized by individuals, businesses, and organizations for various types of websites, including blogs, portfolios, e-commerce sites, and corporate websites.
What is WordPress Plugin?
A WordPress plugin is a software component that extends and enhances the functionality of a WordPress website. Plugins are pivotal in making WordPress a flexible and customizable content management system (CMS). They enable users to incorporate specific features or capabilities into their websites without modifying the core WordPress code.
How to Create a Custom WordPress Plugin?
Step 1
To create a Custom WordPress Plugin, make a new directory in your WordPress website within the `source_code_path>wp-contents>plugins` folder. Then, create a new PHP file.
Step 2
Open your newly created PHP file with your preferred code editor, such as MS VS Code, Sublime, or Notepad++.
Step 3
Next, we need to provide the Plugin's information header at the top line of the PHP file. The information header is enclosed in comment tags. Below is an example information header for a sample WordPress Plugin:
- <?php
- /**
- * Plugin Name: My Custom Plugin Name
- * Plugin URI: URI of your plugin where your docs, updates, or etc located
- * Description: A brief description of yout plugin
- * Version: your plugin version
- * Author: the plugins author name
- * Author URI: the plugins author URI
- * License: license name e.g. GPL2
- */
- ?>
After completing these steps, you will be able to locate your Custom WordPress Plugin on the Plugins Page of your WordPress admin side.
For a more better understanding of creating a Custom WordPress Plugin, I have developed a simple plugin that includes CRUD (Create, Read, Update, and Delete) features on the admin side. The provided plugin script also involves the creation of a new database table.
Below is the PHP script for the simple plugin I created:
- <?php
- /**
- * Plugin Name: My First Custom Plugin
- * Plugin URI: https://sample-domain.com
- * Description: Lorem ipsum dolor sit amet consectetur adipisicing elit.
- * Version: 1.0
- * Author: oretnom23
- * Author URI: https://www.sourcecodester.com/user/257130/activity
- * License: GPLv2 or later
- */
- die;
- }
- class MyFirstPlugin{
- public $notices = [];
- function __construct()
- {
- add_action( 'admin_menu', [ $this, 'pages' ] );
- add_action( 'admin_enqueue_scripts', [$this, 'bootstrap_scripts'], 10, 1 );
- // Process Form
- add_action( 'admin_init', [ $this, 'save_form' ] );
- add_action( 'admin_init', [ $this, 'delete_mfcp' ] );
- // print_r(gettype($this->notices));exit;
- add_action( 'admin_notices', [$this, 'display_notices'] );
- }
- function pages(){
- //add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
- add_menu_page(__('My First Custom Plugin'), __('Custom Plugin'), 'administrator', 'my-first-custom-plugin-page', [$this, 'my_plugin_list_page'], '', 25);
- add_submenu_page('my-first-custom-plugin-page', __('Manage Plugin\'s DB'), __('Add New'), 'administrator', 'my-first-custom-plugin-page-form', [$this, 'my_plugin_form_page']);
- }
- function display_notices(){
- // print_r($this->notices);exit;
- foreach($this->notices as $k =>$notice){
- ?>
- <div class="notice notice-<?= $notice['type'] ?> <?= ($notice['dismissible']) ? "is-dismissible" : "" ?>">
- </div>
- <?php
- }
- }
- update_option("mfcp_notices", []);
- }
- function activate(){
- // Install Plugin's Database
- $this->install_db();
- }
- function deactivate(){
- }
- function uninstall(){
- }
- /**
- * Enqueue Styles and Scripts
- */
- function bootstrap_scripts($hook){
- // Enqueue Bootstrap CDN CSS and JS only in plugin's page
- if($hook == 'toplevel_page_my-first-custom-plugin-page' || $hook == 'custom-plugin_page_my-first-custom-plugin-page-form'){
- wp_enqueue_style("fontawesome-icon-cdn","https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css",[],"6.1.2", "all");
- wp_enqueue_style("bootstrap-css-cdn","https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css",[],"5.3.2", "all");
- wp_enqueue_script("fontawesome-icon-js-cdn","https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/js/all.min.js",[],"6.1.2", "all");
- wp_enqueue_script("bootstrap-js-cdn","https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js",[],"5.3.2", "all");
- }
- // echo $hook;exit;
- }
- /**
- * Create Plugin's Database
- */
- function install_db(){
- global $wpdb;
- $table = $wpdb->prefix."mfp_tbl";
- $qry = $wpdb->prepare("SHOW TABLES LIKE %s", $wpdb->esc_like($table));
- if($wpdb->get_var($qry) == $table){
- /**
- * Table Already Exists
- */
- }else{
- /**
- * Table Doesn't Exists on the Database
- * - Install Table
- */
- $charset_collate = $wpdb->get_charset_collate();
- $sql = "CREATE TABLE IF NOT EXISTS $table (
- `id` int(30) NOT NULL PRIMARY KEY AUTO_INCREMENT,
- `meta_field` text DEFAULT NULL,
- `meta_value` text DEFAULT NULL,
- `created_at` datetime NOT NULL DEFAULT current_timestamp(),
- `updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp()
- ) $charset_collate;";
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
- dbDelta($sql);
- }
- }
- /**
- * Create Plugin's Form Page
- */
- function my_plugin_form_page(){
- global $wpdb;
- $data = $wpdb->get_row(
- $wpdb->prepare("SELECT * FROM `{$wpdb->prefix}mfp_tbl` where `id` = %d", [$_GET['mfcp_id']]),
- ARRAY_A
- );
- }
- ?>
- <style>
- .card{
- max-width: unset !important;
- }
- </style>
- <div class="container-fluid">
- <div class="card shadow col-lg-5 col-md-8 col-sm-12 col-12 mx-auto p-0">
- <div class="card-header rounded-0">
- <div class="card-title">Plugin's Sample Form <?= (!empty($mfcp_id ?? "")? " - Updating #{$mfcp_id}" : "") ?></div>
- </div>
- <div class="card-body">
- <div class="container-fluid">
- <form action="" id="sample-form" method="POST">
- <?php wp_nonce_field( "mfcp-sample-form" ); ?>
- <input type="hidden" name="action" value="save-mfcp-sample-form">
- <input type="hidden" name="id" value="<?= $mfcp_id ?? "" ?>">
- <div class="mb-3">
- <label for="meta_field" class="form-label">Meta Field <small class="text-danger">*</small></label>
- <input type="text" class="form-control rounded-0" id="meta_field" name="meta_field" value="<?= $_POST['meta_field'] ?? $mfcp_meta_field ?? "" ?>" required="required" autofocus>
- </div>
- <div class="mb-3">
- <label for="meta_value" class="form-label">Meta Value <small class="text-danger">*</small></label>
- <textarea name="meta_value" id="meta_value" rows="3" class="form-control rounded-0" requried=""><?= $_POST['meta_value'] ?? $mfcp_meta_value ?? "" ?></textarea>
- </div>
- <div class="mb-3">
- <button class="btn btn-primary rounded-0" type="submit">Save</button>
- </div>
- </form>
- </div>
- </div>
- </div>
- </div>
- <?
- }
- /**
- * Create Plugin's List Page
- */
- function my_plugin_list_page(){
- global $wpdb;
- $data = $wpdb->get_results(
- $wpdb->prepare("
- SELECT * FROM `{$wpdb->prefix}mfp_tbl` order by id ASC
- "),
- ARRAY_A
- );
- ?>
- <style>
- .card{
- max-width: unset !important;
- }
- </style>
- <div class="container-fluid">
- <div class="card shadow col-12 p-0">
- <div class="card-header rounded-0">
- <div class="card-title">Plugin's Database Data</div>
- </div>
- <div class="card-body">
- <div class="container-fluid">
- <div class="table-responsive">
- <table class="table table-striped table-hover table-bordered">
- <colgroup>
- <col width="20%">
- <col width="30%">
- <col width="30%">
- <col width="20%">
- </colgroup>
- <thead>
- <tr>
- <th class="text-center px-2 py-1 text-light bg-primary">Date Added</th>
- <th class="text-center px-2 py-1 text-light bg-primary">Meta Field</th>
- <th class="text-center px-2 py-1 text-light bg-primary">Meta Value</th>
- <th class="text-center px-2 py-1 text-light bg-primary">Action</th>
- </tr>
- </thead>
- <tbody>
- <?php foreach($data as $row): ?>
- <tr>
- <td class="px-2 py-1"><?= $row['meta_field'] ?></td>
- <td class="px-2 py-1"><?= $row['meta_value'] ?></td>
- <td class="px-2 py-1">
- <div class="input-group d-flex justify-content-center">
- <a href="<?= admin_url("admin.php?page=my-first-custom-plugin-page-form&mfcp_id={$row['id']}") ?>" class="btn btn-sm btn-outline-primary rounded-0" title="Edit"><i class="fa fa-edit"></i></a>
- <a href="<?= admin_url("admin.php?page=my-first-custom-plugin-page-form&action=delete_mfcp&mfcp_id={$row['id']}") ?>" class="btn btn-sm btn-outline-danger rounded-0 delete-mfcp" title="Delete"><i class="fa fa-trash"></i></a>
- </div>
- </td>
- </tr>
- <?php endforeach; ?>
- <?php else: ?>
- <tr>
- <th class="text-center px-2 py-1" colspan="4">No Data Found!</th>
- </tr>
- <?php endif; ?>
- </tbody>
- </table>
- </div>
- </div>
- </div>
- </div>
- </div>
- <script>
- var delete_mfcp = document.querySelectorAll('.delete-mfcp')
- delete_mfcp.forEach(el=>{
- el.addEventListener('click', function(e){
- if(confirm(`Are you sure to delete this data?`) === false)
- e.preventDefault();
- })
- })
- </script>
- <?
- }
- /**
- * Save Form Data
- */
- function save_form(){
- global $wpdb;
- $resp=[];
- if(
- $_POST['action'] == 'save-mfcp-sample-form'
- ){
- if(!wp_verify_nonce( $mfcp__wpnonce, 'mfcp-sample-form')){
- $resp = ["type" => "danger", "message" => "Security Check Failed!"];
- }else{
- $mfcp_meta_field = sanitize_text_field( $mfcp_meta_field );
- $mfcp_meta_value = sanitize_textarea_field( $mfcp_meta_value );
- $save = $wpdb->insert(
- "{$wpdb->prefix}mfp_tbl",
- [
- "meta_field" => $mfcp_meta_field,
- "meta_value" => $mfcp_meta_value
- ],
- [
- '%s',
- '%s'
- ]
- );
- }else{
- $save = $wpdb->update("{$wpdb->prefix}mfp_tbl",
- [
- "meta_field" => $mfcp_meta_field,
- "meta_value" => $mfcp_meta_value
- ],
- [
- "id" => $mfcp_id,
- ],
- [
- '%s',
- '%s'
- ],
- [
- '%d',
- ]
- );
- }
- if($wpdb->last_error){
- $resp = ["type" => "danger", "message" => $wpdb->last_error];
- }else{
- $resp = ["type" => "success", "message" => "Data has been saved successfully!"];
- }
- }
- $this->notices[] = $resp;
- update_option("mfcp_notices", $this->notices);
- echo "<script>location.replace(`".admin_url("admin.php?page=my-first-custom-plugin-page")."`)</script>";
- exit;
- }
- }
- /**
- * Delete Data
- */
- function delete_mfcp(){
- global $wpdb;
- if(
- $_GET['page'] == 'my-first-custom-plugin-page-form' &&
- $_GET['action'] == 'delete_mfcp'&&
- ){
- $delete = $wpdb->delete("{$wpdb->prefix}mfp_tbl", [ "id" => $_GET['mfcp_id']], ['%d']);
- if($wpdb->last_error){
- $resp = ["type" => "danger", "message" => $wpdb->last_error];
- }else{
- $resp = ["type" => "success", "message" => "Data has been deleted successfully!"];
- }
- $this->notices[] = $resp;
- update_option("mfcp_notices", $this->notices);
- echo "<script>location.replace(document.referrer)</script>";
- exit;
- }
- }
- }
- $MyFirstPlugin = new MyFirstPlugin();
- }
Snapshots
Explore the snapshots below, capturing the results of the Custom WordPress Plugin Script provided above:
Plugin's Custom Form Page
Plugin's Custom List Page
And there you have it! I trust this Custom WordPress Plugin Guide proves helpful for your needs and becomes a valuable resource for your current and future WordPress projects.
Consider exploring the following topics as well:
- Generate a Table of Contents for Your WordPress Post with PHP
- Creating CRUD Operation using PHP OOP Approach and SQLite3 Database
Explore more into this website for an array of Tutorials, Free Source Codes, and Articles spanning various programming languages.