How to create a CRUD application in WordPress without plugins: A step-by-step guide

Developing a CRUD in WordPress without relying on additional plugins offers you flexibility and control over the data you manipulate on your site. In this tutorial, we will show you how to do this using PHP and native WordPress functions. We will cover how to create, read, update, and delete data (CRUD) in WordPress without the need to install plugins, thanks to a practical code example you can use and adapt.

What is a CRUD?

A CRUD is a system that allows you to perform four basic operations with data: Create, Read, Update, and Delete (Create, Read, Update, Delete). These operations are fundamental in any application that needs to interact with a database, enabling dynamic information management.

Benefits of not using plugins

While WordPress has thousands of plugins that facilitate creating a CRUD, building one from scratch has many advantages, such as:

  • Greater customization, adapting the CRUD to your exact needs.
  • Total control over the code and performance.
  • Lower site load, as you will avoid relying on external plugins that can overload your installation.

Description of the CRUD in WordPress without plugins

In this article, we will build a simple CRUD in WordPress that allows you to manage a custom table in the database. Our example will work with a table that stores names and descriptions, and you will be able to insert, view, update, and delete records through a form on the frontend.

Below, we show you how to implement this system using PHP code that you can copy and paste into your WordPress theme, or even convert into a small plugin, as we will see in this tutorial.

Explained CRUD code

The provided code uses some of WordPress's core functions to interact with the database through the global object $wpdb. We will break down the code to understand how each section works.


Creating the database table

When you activate the plugin or add this code to your file functions.php, the first task is to create a custom table in the database where the records will be stored. To do this, we use the function dbDelta() from WordPress, which allows you to create or update tables securely.

function mi_crud_plugin_activate() {
    global $wpdb;
    $table_name = $wpdb->prefix . 'mi_crud_table';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        nombre varchar(255) NOT NULL,
        descripcion text NOT NULL,
        PRIMARY KEY (id)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}
  • $wpdb->prefix ensures that the table respects the prefix that WordPress uses for its tables.
  • The function dbDelta() handles the creation of the table.

This step runs automatically when you activate the plugin, and the table will be created if it does not exist.


Creating records (Create)

To create a new record in our table, we use the following block of code, which captures the form data and inserts it into the database table:

if (isset($_POST[&#039;create&#039;]) &amp;&amp; check_admin_referer(&#039;my_crud_nonce_action&#039;)) { $name = sanitize_text_field($_POST[&#039;name&#039;]); $description = sanitize_textarea_field($_POST[&#039;description&#039;]); $wpdb-&gt;insert( $table_name, [ &#039;name&#039; =&gt; $name, &#039;description&#039; =&gt; $description ] ); echo&quot;'<p>Record created successfully.</p>";
}
  • sanitize_text_field() y sanitize_textarea_field() are used to clean the data entered by the user, protecting your site from potential code injection attacks.
  • $wpdb->insert() is the function that inserts the data into the database table.

This code allows users to enter data through the form and save it to the database.


Reading records (Read)

Once you have records in the table, you need to be able to view them. The following block of code retrieves all records from the database and displays them in an HTML table:

$registros = $wpdb-&gt;get_results("SELECT * FROM $table_name");"<tr>";"<td>" . esc_html($registro-&gt;id) . "</td>";"<td>" . esc_html($registro-&gt;nombre) . "</td>";"<td>" . esc_html($registro-&gt;descripcion) . "</td>";"</tr>";
}
  • $wpdb->get_results() is used to perform a query and obtain the data stored in the table.
  • esc_html() ensures that the data is printed securely in the HTML.

4. Updating records (Update)

To update an existing record, the code captures the new values entered by the user and saves them to the database using $wpdb->update():

if (isset($_POST['actualizar']) &amp;&amp; check_admin_referer('mi_crud_nonce_action')) {
    $nombre = sanitize_text_field($_POST['nombre']);
    $descripcion = sanitize_textarea_field($_POST['descripcion']);
    $id = intval($_POST['id']);
    
    $wpdb-&gt;update(
        $table_name,
        [
            'nombre' =&gt; $nombre,
            'descripcion' =&gt; $descripcion
        ],
        ['id' =&gt; $id]
    );
    echo "<p>Record updated successfully.</p>";
}

Here, the record is updated based on the id provided, and the new values replace the old ones in the table.


5. Deleting records (Delete)

The following code allows you to delete a record from the database using $wpdb->delete():

if (isset($_GET['eliminar']) &amp;&amp; check_admin_referer('mi_crud_nonce_action')) {
    $wpdb-&gt;delete($table_name, ['id' =&gt; intval($_GET['eliminar'])]);
    echo "<p>Record deleted successfully.</p>";
}
  • This code captures the id the record to be deleted and removes it from the table.
  • intval() ensures that the id is treated as an integer.

6. Shortcode implementation

Finally, the following code allows you to insert the form and the record table into any page or post by using a shortcode:

add_shortcode('mi_crud', 'mi_crud_shortcode');

function mi_crud_shortcode() {
    ob_start(); 
    mi_crud_form();
    return ob_get_clean(); 
}

This shortcode can be used as [mi_crud] in the WordPress editor, displaying the form and the table wherever you insert it.


Complete Code

&lt;?php
    <!-- FORMULARIO PARA CREAR NUEVOS REGISTROS -->
    <form method="post" action="">
        <?php wp_nonce_field('mi_crud_nonce_action'); // Campo de seguridad para proteger el formulario ?>
        <label for="nombre">Name:</label>
        <input type="text" name="nombre" id="nombre" required>
        <br><br>
        <label for="descripcion">Description:</label>
        <textarea name="descripcion" id="descripcion" required></textarea>
        <br><br>
        <input type="submit" name="crear" value="Create">
    <input type="hidden" name="trp-form-language" value="en"/></form>

    <!-- MOSTRAR TODOS LOS REGISTROS EXISTENTES -->
    <h2>Existing Records</h2>
    <table border="1" cellpadding="5" cellspacing="0">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Description</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($registros as $registro): ?>
                <tr>
                    <td>id); ?&gt;</td> <!-- Mostrar el ID -->
                    <td>nombre); ?&gt;</td> <!-- Mostrar el nombre escapado -->
                    <td>descripcion); ?&gt;</td> <!-- Mostrar la descripción escapada -->
                    <td>
                        <!-- Enlace para eliminar (con confirmación de usuario y nonce de seguridad) -->
                        <a href="/en/</?php echo esc_url(add_query_arg('eliminar', $registro->id)); ?>&amp;_wpnonce=<?php echo wp_create_nonce('mi_crud_nonce_action'); ?>" onclick="return confirm('¿Estás seguro de eliminar este registro?');">Delete</a>

                        <!-- Enlace para editar (abre el formulario de edición) -->
                        <a href="#editar_<?php echo esc_attr($registro->id); ?>" onclick="document.getElementById('form_editar_<?php echo esc_attr($registro->id); ?>').style.display='block'; return false;">Edit</a>
                    </td>
                </tr>

                <!-- FORMULARIO PARA EDITAR UN REGISTRO EXISTENTE -->
                <tr id="form_editar_<?php echo esc_attr($registro->id); ?>" style="display: none;">
                    <td colspan="4">
                        <form method="post" action="">
                            <?php wp_nonce_field('mi_crud_nonce_action'); // Protección de nonce para la actualización ?>
                            <input type="hidden" name="id" value="<?php echo esc_attr($registro->id); ?>">
                            <label for="nombre">Name:</label>
                            <input type="text" name="nombre" value="<?php echo esc_attr($registro->nombre); ?>" required>
                            <br><br>
                            <label for="descripcion">Description:</label>
                            <textarea name="descripcion" required><?php echo esc_textarea($registro->descripcion); ?></textarea>
                            <br><br>
                            <input type="submit" name="actualizar" value="Update">
                        <input type="hidden" name="trp-form-language" value="en"/></form>
                    </td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
    &lt;?php

FAQs

Is it necessary to have advanced PHP knowledge to implement this?

You don't need to be an expert, but having a basic understanding of PHP and WordPress functions will help you customize this code according to your needs.

Is this code secure?

Yes, as long as you use data sanitization functions such as sanitize_text_field(), sanitize_textarea_field() y check_admin_referer().

Can I add more fields to the CRUD?

Yes, you can add more fields to the table and forms by adjusting the table code and the creation and update functions.

Will this CRUD work on any WordPress theme?

Yes, the code is theme-independent and will work as long as native WordPress functions are used.

Is it recommended to use a plugin for the CRUD, or is this method better?

If you need customization and full control, this method is better. However, for a quick and hassle-free solution, you could opt for a plugin.


Conclusion

Creating a CRUD in WordPress without relying on plugins is an excellent way to learn more about WordPress's internal workings and have greater control over the data on your site. The provided code is a starting point that you can customize according to your needs.

This approach not only improves your site's performance by reducing the number of plugins but also gives you the flexibility to adapt the system to any type of data you wish to manage.

Do you need help with a web project?

Do you need help with a web project? Don't hesitate to contact me. I develop complete and customized solutions with WordPress and PHP, using modern tools and processes, HTML, CSS, SCSS, PHP, JavaScript, Bootstrap, and more. Ready? Send me a message and let's talk about your web project!