domingo, 30 Ago 2026

Exclusive resources and tools for web design and development experts

Explore
BiblioWeb

Biblioweb.es

All About Web Technology

  • Start
  • Categories
    • Web Development and Plugins
    • AI & Web Automation
    • Cybersecurity and Web Security
    • WordPress Plugins
    • Web error solution
    • Web Hosting & Performance
  • WordPress
    • All about WordPress
    • WordPress Plugins
    • Web Development and Plugins
    • AI and Web Automation
    • WooCommerce
    • Hosting and Web Performance
    • Cybersecurity and Web Security
    • Web Error Resolution
    • Online Stores and Funnels
  • About Plugins
    • Yoast SEO
    • WooCommerce
    • Rank Math SEO
    • AI Engine
    • WP Rocket
    • WPCode
    • WP Translate Master
    • CartBounty
    • WP SEO Pro
  • Tools
    • Password Generator
    • QR Code Generator
    • Word Counter
    • JSON Formatter
    • Compresor de Vídeo para Web
    • Generador de Firmas de Email
    • Image to WebP Converter
    • Email Checker
  • Plugins Library
  • Español
  • English ✓
  • 🇨🇳 中文(简体)
  • Français
  • Deutsch
  • Italiano
History
  • WordPress
  • WordPress plugins
  • Create website
  • WooCommerce
  • WordPress tricks
  • See everything
BiblioWebBiblioWeb
Font ResizerAa
  • News History
Search
  • Start
  • Categories
    • Web Development and Plugins
    • AI & Web Automation
    • Cybersecurity and Web Security
    • WordPress Plugins
    • WooCommerce
    • Web Hosting & Performance
    • Troubleshooting web errors
    • Online Stores & Sales Funnels
  • WordPress
    • All about WordPress
    • WordPress Plugins
    • Web Development and Plugins
    • AI and Web Automation
    • WooCommerce
    • Hosting and Web Performance
    • Cybersecurity and Web Security
    • Web Error Resolution
    • Online Stores and Funnels
  • About Plugins
    • Rank Math SEO
    • AI Engine
    • WP Rocket
    • WPCode
    • WP Translate Master
    • CartBounty
    • WP SEO Pro
  • Blog
    • Español
    • English ✓
    • 🇨🇳 中文(简体)
    • Français
    • Deutsch
    • Italiano
  • My account
    • News History
  • Tools
    • Password Generator
    • QR Code Generator
    • Word Counter
    • JSON Formatter
    • Image to WebP Converter
    • Email Checker
    • Compresor de Vídeo para Web
    • Generador de Firmas de Email
Have an existing account? Sign In
Follow Us
© 2026 BiblioWeb — All rights reserved.
Cover » Blog » How to create a WordPress plugin from scratch
Web Development and Plugins

How to create a WordPress plugin from scratch

Adrián Alcalá
Last updated: 08/08/2026 21:11
By Adrián Alcalá
Share
17 Min Read
How to create a WordPress plugin from scratch
SHARE

Learn to create a WordPress plugin is the step that separates those who use the platform from those who truly master it. A plugin is nothing more than a set of PHP files that WordPress loads alongside the core and can modify or extend almost any system behavior: add functions, change texts, create content types, or connect the website with external services. The good news is that the entry barrier is much lower than it seems: with one file, a comment header, and basic knowledge of hooks, you already have a functional plugin. In this guide, we will build one from scratch, step by step and with complete code that you can copy, test, and extend. We will cover the recommended file structure, how actions and filters work, how to add a settings page, and what good security practices you should apply from day one to make your code robust and maintainable.

Contents
Why create a WordPress plugin and not touch the themeWhat you need before startingThe minimum structure: folder, file, and headerHooks: the heart of any pluginThe complete plugin: main class with settings and outputBest practices that make a differenceHow to test and debug your pluginNext steps: grow with orderFrequently Asked QuestionsConclusion

Why create a WordPress plugin and not touch the theme

Before writing a single line, it's good to understand where each type of code should live in WordPress. The general rule is simple: the theme controls how your website looks, and plugins control what your website does. If you add functionality to the file functions.php of your theme, that functionality will disappear as soon as you change themes or, even worse, as soon as the theme updates and overwrites your changes.

A plugin, on the other hand, is independent of the design. You can activate it, deactivate it, move it to another installation, or publish it in the official directory. These are the typical situations where the correct answer is create a WordPress plugin custom:

  • You need a specific function (a shortcode, a notice, an integration) that doesn't justify installing a huge commercial plugin.
  • You want the functionality to survive a theme change.
  • You are going to reuse the same code on several client websites.
  • An existing plugin does almost what you want, but not exactly, and you prefer to control the code.

For very small snippets, there's an intermediate alternative: snippet managers. If you only need to paste ten lines of PHP, you might be interested in reading our analysis of WPCode, the WordPress snippet manager. But as soon as the code grows or needs organization, a custom plugin wins by a landslide.

What you need before starting

The toolkit is minimal. No paid software or complicated environment is needed:

  • A test WordPress installation. Never develop directly in production. A local environment with Local WP, XAMPP, or similar is ideal.
  • A code editor. Visual Studio Code is the most popular and free option.
  • File access. Locally you have it direct; on a server, via SFTP or the hosting's file manager.
  • Basic PHP concepts. Variables, functions, and arrays are enough to start.

It's also advisable to activate debug mode while developing. Add this to your wp-config.php of the testing environment:

You Might Also Like

Cloud development environments for WordPress
WordPress Hooks: what actions and filters are
Cómo conectar Google Sheets con WordPress
Beyond Framer and Webflow: The web builder comparison that interests your WordPress agency
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

With this configuration, errors and notices are saved in wp-content/debug.log instead of being displayed on screen, which will allow you to catch problems without breaking the browsing experience.

The minimum structure: folder, file, and header

A plugin can be a single PHP file inside wp-content/plugins, but the recommended practice is to create its own folder from the beginning. For our example, we will build a real and useful plugin: a customizable notice at the top of the website, with an included settings page. The structure will be this:

wp-content/plugins/bw-aviso-superior/
├── bw-aviso-superior.php   (archivo principal)
├── includes/
│   └── class-bw-aviso.php  (lógica del plugin)
└── assets/
    └── css/
        └── aviso.css       (estilos del aviso)

The only essential thing for WordPress to recognize the plugin is the plugin header: a comment block at the beginning of the main file. Create bw-aviso-superior.php with this content:

<?php
/**
 * Plugin Name:       BW Aviso Superior
 * Plugin URI:        https://biblioweb.es/
 * Description:       Muestra una barra de aviso personalizable en la parte superior de la web.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            BiblioWeb
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       bw-aviso-superior
 */

// Seguridad: impedir el acceso directo al archivo.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

define( 'BW_AVISO_VERSION', '1.0.0' );
define( 'BW_AVISO_PATH', plugin_dir_path( __FILE__ ) );
define( 'BW_AVISO_URL', plugin_dir_url( __FILE__ ) );

require_once BW_AVISO_PATH . 'includes/class-bw-aviso.php';

// Arrancar el plugin cuando WordPress haya cargado los plugins.
add_action( 'plugins_loaded', array( 'BW_Aviso', 'init' ) );

With just this file (and the class we'll see now), the plugin will already appear in the list of Plugins of the dashboard, ready to be activated. Note the check for ABSPATH: prevents someone from directly executing the file by typing its URL, a basic security measure that should open all your PHP files.

Hooks: the heart of any plugin

WordPress is built on a system of hooks (hooks) that allows your code to attach to specific moments of execution. Without hooks, there is no plugin: they are the official mechanism to intervene without modifying the core. There are two types:

Actions: do something at a given moment

A action executes your function when an event occurs: WordPress finishes loading, a post is published, the footer is rendered. They are used with add_action():

add_action( 'wp_footer', 'bw_mensaje_en_footer' );
function bw_mensaje_en_footer() {
    echo '<!-- Generado por BW Aviso Superior -->';
}

Filters: modify data before it is used

A filter receives a value, transforms it, and returns it. WordPress uses it for everything: a post's title, content, excerpt length. They are used with add_filter():

add_filter( 'excerpt_length', 'bw_extracto_corto' );
function bw_extracto_corto( $length ) {
    return 25; // palabras del extracto
}

The key difference: an action does things and returns nothing; a filter always must return the value (modified or not). Forgetting the return in a filter is one of the most common mistakes when starting and can leave empty texts all over the website.

The complete plugin: main class with settings and output

Now let's move on to the central piece. Create includes/class-bw-aviso.php with the class that registers the settings, renders the options page, and displays the notice on the public side:

<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class BW_Aviso {

    const OPTION = 'bw_aviso_opciones';

    public static function init() {
        $instancia = new self();

        // Parte pública.
        add_action( 'wp_body_open', array( $instancia, 'mostrar_aviso' ) );
        add_action( 'wp_enqueue_scripts', array( $instancia, 'cargar_estilos' ) );

        // Administración.
        add_action( 'admin_menu', array( $instancia, 'registrar_pagina_ajustes' ) );
        add_action( 'admin_init', array( $instancia, 'registrar_ajustes' ) );
    }

    public function mostrar_aviso() {
        $opciones = get_option( self::OPTION );
        if ( empty( $opciones['activo'] ) || empty( $opciones['texto'] ) ) {
            return;
        }
        printf(
            '<div class="bw-aviso-superior">%s</div>',
            esc_html( $opciones['texto'] )
        );
    }

    public function cargar_estilos() {
        $opciones = get_option( self::OPTION );
        if ( empty( $opciones['activo'] ) ) {
            return;
        }
        wp_enqueue_style(
            'bw-aviso-superior',
            BW_AVISO_URL . 'assets/css/aviso.css',
            array(),
            BW_AVISO_VERSION
        );
    }

    public function registrar_pagina_ajustes() {
        add_options_page(
            'Aviso Superior',
            'Aviso Superior',
            'manage_options',
            'bw-aviso-superior',
            array( $this, 'render_pagina_ajustes' )
        );
    }

    public function registrar_ajustes() {
        register_setting(
            'bw_aviso_grupo',
            self::OPTION,
            array( 'sanitize_callback' => array( $this, 'sanear_opciones' ) )
        );
    }

    public function sanear_opciones( $entrada ) {
        return array(
            'activo' => ! empty( $entrada['activo'] ) ? 1 : 0,
            'texto'  => isset( $entrada['texto'] )
                ? sanitize_text_field( $entrada['texto'] )
                : '',
        );
    }

    public function render_pagina_ajustes() {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }
        $opciones = get_option( self::OPTION, array( 'activo' => 0, 'texto' => '' ) );
        ?>
        <div class="wrap">
            <h1>Aviso Superior</h1>
            <form method="post" action="options.php">
                <?php settings_fields( 'bw_aviso_grupo' ); ?>
                <table class="form-table">
                    <tr>
                        <th scope="row">Mostrar aviso</th>
                        <td>
                            <label>
                                <input type="checkbox"
                                    name="<?php echo esc_attr( self::OPTION ); ?>[activo]"
                                    value="1" <?php checked( 1, $opciones['activo'] ); ?> />
                                Activar la barra de aviso
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row">Texto del aviso</th>
                        <td>
                            <input type="text" class="regular-text"
                                name="<?php echo esc_attr( self::OPTION ); ?>[texto]"
                                value="<?php echo esc_attr( $opciones['texto'] ); ?>" />
                        </td>
                    </tr>
                </table>
                <?php submit_button(); ?>
            </form>
        </div>
        <?php
    }
}

And finally the styles, in assets/css/aviso.css:

.bw-aviso-superior {
    background: #1d2327;
    color: #ffffff;
    text-align: center;
    padding: 10px 16px;
    font-size: 15px;
}

Activate the plugin, go to Settings → Top Notice, check the box, type some text, and save. The bar will appear at the top of your website. You have now achieved create a WordPress plugin complete: with a settings page, options saved in the database, custom styles, and output on the public side.

Best practices that make a difference

The previous example already applies several rules that you should internalize. Let's review them along with others equally important:

Sanitize input and escape output

All incoming data (forms, URL, APIs) is sanitized with functions like sanitize_text_field(), and all data displayed on screen is escaped with esc_html(), esc_attr() o esc_url(). This pair of habits prevents the vast majority of XSS vulnerabilities. If you are interested in the defensive approach, we have a guide with 7 tricks to strengthen your WordPress security which complements very well what you do at the code level.

Unique prefixes everywhere

Functions, classes, options, and style handles must have their own prefix (in our case bw_ y BW_). PHP does not allow two functions with the same name: if your plugin declares enviar_email() and another plugin also, the website will crash with a fatal error.

Check capabilities and use nonces

Before displaying or operating on administration pages, verify permissions with current_user_can(). In custom forms, add nonces with wp_nonce_field() and verify them when processing. The settings API we use (settings_fields()) already manages the nonce for you, another reason to prefer it over processing forms manually.

Load resources only when needed

Our CSS is only enqueued if the notice is active. Apply the same criterion always: a plugin that loads scripts on all pages unnecessarily penalizes the performance of the entire website. In fact, many of the speed problems attributed to WordPress are actually poorly written plugins; in the guide on how to speed up WordPress with PHP settings you can see the real impact of these decisions.

How to test and debug your plugin

With WP_DEBUG activated, your workflow will be: save the file, reload the page, and check wp-content/debug.log if something doesn't work. Some additional tips:

  1. Test activation and deactivation. Activate and deactivate the plugin several times, checking that it doesn't throw warnings.
  2. Test with other active plugins. Conflicts between plugins are the main source of real incidents.
  3. Test with different users. Log in with an editor or subscriber and confirm that they don't see the settings page.
  4. Use error_log() as a cheat sheet. Writing error_log( print_r( $variable, true ) ); at a point in the code shows you the content of any variable in the log.

If your plugin is going to handle structured data (for example, API responses in JSON), a tool like the BiblioWeb JSON formatter and validator will save you time when inspecting and validating those responses during development.

Next steps: grow with order

From this base, you can extend the plugin in many directions: add a color picker for the bar, schedule start and end dates for the notice, create a shortcode, or expose options in the REST API. When the project grows, maintain structural discipline: the logic in includes/, the resources in assets/, and the main file only as an entry point.

The essential reference for in-depth study is the Official WordPress Plugin Handbook, which documents everything from available hooks to the directory publication process. And if you want to see how the big players solve things, nothing beats reading the code of established plugins: the ones we review in the 5 essential WordPress plugins for beginners are a good starting point for studying structure and style.

Frequently Asked Questions

Do I need to know a lot of PHP to create a WordPress plugin?

Not to start. With variables, functions, arrays, and conditionals, you can build useful plugins like the one in this guide. The development itself will naturally and progressively lead you to more advanced concepts (classes, namespaces, APIs).

Where are plugins stored in WordPress?

In the folder wp-content/plugins of your installation. Each plugin occupies its own subfolder (or a single PHP file in very simple cases). WordPress automatically detects any file with a valid plugin header within that path.

Can I break my website when developing a plugin?

A PHP syntax error in an active plugin can bring down the website, which is why development is always done in a testing environment. If it happens in production, simply renaming the plugin folder via SFTP is enough to deactivate it and instantly restore the site.

How do I publish my plugin in the official directory?

You must comply with the directory guidelines (GPL license, secure code, no obfuscation), prepare a file readme.txt and submit it for review from wordpress.org. After approval, you receive access to an SVN repository from which versions are distributed.

Conclusion

Creating a WordPress plugin is not exclusive territory for veteran programmers: it's a folder, a header, and a handful of well-chosen hooks. In this guide, you've built a complete one, with a settings page, data sanitization, conditional styles, and the security best practices used by professional plugins. The leap in quality compared to pasting code into the theme is enormous: your functionality is now portable, updatable, and isolated from the design. The best final advice is simple: choose a small, real problem on your own website and solve it with a plugin. There's no better school than maintaining your own code running on a real site.

Share This Article
Email Copy Link Print
ByAdrián Alcalá
Follow:
Adrián Alcalá es desarrollador WordPress y consultor SEO, autor del plugin WP Translate y creador de BiblioWeb. Desde aquí comparte guías, tutoriales y herramientas gratuitas para quienes crean, optimizan y posicionan páginas web. Lleva años ayudando a negocios de toda España a sacar el máximo partido a WordPress, y todo lo que publica está probado en proyectos reales.
Previous Article What is Elementor and how to use it to design pages What is Elementor and how to use it: a getting started guide
Next Article WordPress backup: complete guide How to make a WordPress backup
como instalar wordpress - ¡Tu primera web en marcha! 🎉 Cómo instalar WordPress sin estrés y con la confianza de un experto (
¡Tu primera web en marcha! 🎉 Cómo instalar WordPress sin estrés y con la confianza de un experto (¡Te lo ponemos fácil!).
WordPress
como instalar wordpress - ¿Quieres saber cómo instalar WordPress como un PRO? 🚀 Guía definitiva para elegir el hosting perfe
¿Quieres saber cómo instalar WordPress como un PRO? 🚀 Guía definitiva para elegir el hosting perfecto (¡y que tu web vuele!)
WordPress
Best resources to learn WordPress
Los mejores recursos para aprender WordPress en español
WordPress
como instalar wordpress - ¡Adiós al miedo! Cómo instalar WordPress en tu propio servidor local (¡Perfecto para experimentar s
¡Adiós al miedo! Cómo instalar WordPress en tu propio servidor local (¡Perfecto para experimentar sin riesgos y crear tu #CrearPaginaWeb!)
WordPress
Advertisement

You May Also Like

WordPress without coding: no-code
Web Development and Plugins

WordPress sin programar: qué puedes construir con no-code

24/08/2026
Custom Post Types in WordPress: complete guide
Web Development and Plugins

Custom Post Types in WordPress: complete guide

08/08/2026
WordPress - Beyond the Basics: Unlock Yoast SEO's Hidden Tricks to Take Your WordPress to the Next Level (and
Web Development and Plugins

Advanced Yoast SEO tricks to improve your WordPress

08/08/2026
What is Elementor and how to use it to design pages
Web Development and Plugins

What is Elementor and how to use it: a getting started guide

08/08/2026
Show More
  • More News:
  • WordPress
  • Install
  • Guide
  • Create Web Page
  • how to install WordPress
  • Create
  • installation
  • future
  • Discover
  • Yoast
  • Plugins
  • tricks
  • WordPress installation
  • Goodbye
  • Runways
  • page
  • Create webpage
  • truco
  • Error
  • Construcción
BiblioWeb

Biblioweb.es

Web Technology News

Information you can trust: guías y soluciones prácticas de tecnología web — WordPress, plugins, ciberseguridad, hosting, rendimiento y solución de errores.

RSS

Enlaces de interés

  • About us
  • Contact
  • Free tools
  • Plugin Library

Subscribe now to receive real-time updates on the latest news!

Legal

  • Legal Notice
  • Terms and Conditions
  • Cookies Policy
  • Privacy Policy

Latest news

como instalar wordpress - ¡Tu primera web en marcha! 🎉 Cómo instalar WordPress sin estrés y con la confianza de un experto (

¡Tu primera web en marcha! 🎉 Cómo instalar WordPress sin estrés y con la confianza de un experto (¡Te lo ponemos fácil!).

25/08/2026
Continue reading
como instalar wordpress - ¿Quieres saber cómo instalar WordPress como un PRO? 🚀 Guía definitiva para elegir el hosting perfe

¿Quieres saber cómo instalar WordPress como un PRO? 🚀 Guía definitiva para elegir el hosting perfecto (¡y que tu web vuele!)

24/08/2026
Continue reading

© 2026 BiblioWeb — All rights reserved.

Gestionar consentimiento
Utilizamos tecnologías como las cookies para almacenar y/o acceder a la información del dispositivo. Lo hacemos para mejorar la experiencia de navegación y para mostrar anuncios (no) personalizados. El consentimiento a estas tecnologías nos permitirá procesar datos como el comportamiento de navegación o los ID's únicos en este sitio. No consentir o retirar el consentimiento, puede afectar negativamente a ciertas características y funciones.
Funcional Always active
El almacenamiento o acceso técnico es estrictamente necesario para el propósito legítimo de permitir el uso de un servicio específico explícitamente solicitado por el abonado o usuario, o con el único propósito de llevar a cabo la transmisión de una comunicación a través de una red de comunicaciones electrónicas.
Preferences
El almacenamiento o acceso técnico es necesario para la finalidad legítima de almacenar preferencias no solicitadas por el abonado o usuario.
Estadísticas
El almacenamiento o acceso técnico que es utilizado exclusivamente con fines estadísticos. El almacenamiento o acceso técnico que se utiliza exclusivamente con fines estadísticos anónimos. Sin un requerimiento, el cumplimiento voluntario por parte de tu proveedor de servicios de Internet, o los registros adicionales de un tercero, la información almacenada o recuperada sólo para este propósito no se puede utilizar para identificarte.
Marketing
El almacenamiento o acceso técnico es necesario para crear perfiles de usuario para enviar publicidad, o para rastrear al usuario en una web o en varias web con fines de marketing similares.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Ver preferencias
  • {title}
  • {title}
  • {title}
Welcome to Foxiz
Username or Email Address
Password

Lost your password?