Create a WordPress Plugin from Scratch
You can write your own plugin in minutes. A plugin is a folder (or even one PHP file) in wp-content/plugins. We will build a plugin that adds a notice box at the end of every post, step by step.
Step 1: Create the folder and file
Make a folder with a unique name, like tc-post-notice, and in it a PHP file with the same name. The comment at the top is the plugin header. Only Plugin Name is required, but add more details:
<?php
/**
* Plugin Name: TC Post Notice
* Description: Shows a notice box at the end of every single post.
* Version: 1.0.0
* Author: Tutorials Class
* License: GPL-2.0-or-later
* Text Domain: tc-post-notice
*/
// Stop if someone opens this file directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Add a notice after the content of a single post.
*/
function tcpn_add_notice( $content ) {
if ( is_singular( 'post' ) && is_main_query() ) {
$text = get_option( 'tcpn_text', 'Thanks for reading!' );
$content .= '<div class="tcpn-notice"><strong>' . esc_html( $text ) . '</strong></div>';
}
return $content;
}
add_filter( 'the_content', 'tcpn_add_notice' );
/**
* Run once when the plugin is activated.
*/
function tcpn_activate() {
add_option( 'tcpn_text', 'Thanks for reading!' );
}
register_activation_hook( __FILE__, 'tcpn_activate' );
Step 2: Activate and test
$ wp plugin list –name=tc-post-notice –fields=name,status,version
name status version
tc-post-notice inactive 1.0.0
$ wp plugin activate tc-post-notice
Plugin 'tc-post-notice' activated.
Success: Activated 1 of 1 plugins.
$ wp option get tcpn_text
Thanks for reading!
$ curl -s http://example.com/hello-world/ | grep -o '<div class="tcpn-notice">.*</div>'
<div class="tcpn-notice"><strong>Thanks for reading!</strong></div></div>
The plugin is visible in the list, it saved its option when it was activated, and the notice is on the post page.
What we used
- The ABSPATH check: stops direct access to the file from the browser.
- A prefix (
tcpn_) for all functions and options, so they do not clash with other plugins. - A filter (
the_content): to change the post content. - Escaping (
esc_html): for safe output. - An activation hook: for the setup work, like default options.
Deactivation and uninstall
Use register_deactivation_hook() to clean temporary data when the plugin is turned off, like scheduled events. When the plugin is deleted from the dashboard, WordPress looks for a file named uninstall.php in the plugin folder and runs it. (In WP-CLI, wp plugin uninstall does the same, while wp plugin delete only removes the files.) This is the right place to remove the options and tables of the plugin:
<?php
// Runs only when WordPress deletes the plugin.
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
delete_option( 'tcpn_text' );
$ wp plugin deactivate tc-post-notice
Plugin 'tc-post-notice' deactivated.
Success: Deactivated 1 of 1 plugins.
$ wp plugin uninstall tc-post-notice
Uninstalled and deleted 'tc-post-notice' plugin.
Success: Uninstalled 1 of 1 plugins.
$ wp option get tcpn_text || echo "option removed"
option removed
Error: Could not get 'tcpn_text' option. Does it exist?
Good practice for plugin code
| Rule | Why |
|---|---|
| Use a unique prefix for functions, classes, options and hooks | Avoid name clashes |
Check ABSPATH at the top of every PHP file | Block direct access |
| Sanitize input, escape output, use nonces and check capabilities | Security. See Data Validation and Security |
| Use hooks, never edit the core | Safe updates |
| Load scripts only where needed | Speed |
Write a readme.txt | Needed to publish on WordPress.org |
| Follow the WordPress Coding Standards | Clean and readable code |
Organize bigger plugins
When the code grows, split it into files: an includes/ folder for classes, an admin/ folder for dashboard code, an assets/ folder for CSS, JS and images, and a languages/ folder for translations. The main file only loads the others with require_once plugin_dir_path( __FILE__ ) . 'includes/class-example.php';.
| Exercises & Assignments |
|---|
| No Content Found. |
| Interview Questions & Answers |
|---|
| No Content Found. |