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/bootstrap@5.3.2/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/bootstrap@5.3.2/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.
Happy Coding =)
Add new comment
- 379 views