• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » WordPress Development Recipe: Efficient binary storage and retrieval in custom tables using Anonymous Classes

WordPress Development Recipe: Efficient binary storage and retrieval in custom tables using Anonymous Classes

Database Schema Design for Binary Data

When dealing with binary data – such as images, PDFs, or serialized objects – within a custom WordPress database table, efficiency in storage and retrieval is paramount. Storing large binary blobs directly in standard MySQL/MariaDB columns like VARCHAR or TEXT is highly inefficient and can lead to significant performance degradation. Instead, we should leverage the BLOB (Binary Large Object) data type. For optimal performance and manageability, consider a schema that separates metadata from the binary content itself. This approach allows for faster querying of record attributes without needing to load the entire binary payload.

Let’s define a custom table, say wp_custom_binary_storage, to hold this data. It will include an ID, a unique identifier for the item (which could be a UUID or a custom slug), a MIME type, a timestamp for creation, and the binary data itself.

SQL Schema Definition

CREATE TABLE wp_custom_binary_storage (
    id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    item_key VARCHAR(255) NOT NULL UNIQUE,
    mime_type VARCHAR(100) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    binary_data LONGBLOB NOT NULL,
    PRIMARY KEY (id),
    KEY idx_item_key (item_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Here, item_key serves as a human-readable or programmatically generated identifier for the stored binary. mime_type is crucial for correctly serving the data later. binary_data uses LONGBLOB, which is suitable for very large binary objects (up to 4GB). The index on item_key ensures quick lookups.

WordPress Plugin Structure and Table Creation

Within your WordPress plugin, you’ll need a mechanism to create this table upon activation. This is typically handled in your main plugin file using the register_activation_hook function.

Plugin Activation Hook

The following PHP snippet demonstrates how to register the table creation logic.

Main Plugin File (e.g., my-binary-storage.php)

<?php
/*
Plugin Name: My Custom Binary Storage
Description: Efficiently stores and retrieves binary data in custom tables.
Version: 1.0
Author: Your Name
*/

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Creates the custom binary storage table on plugin activation.
 */
function my_custom_binary_storage_activate() {
    global $wpdb;
    $table_name = $wpdb->prefix . 'custom_binary_storage';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table_name (
        id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
        item_key VARCHAR(255) NOT NULL UNIQUE,
        mime_type VARCHAR(100) NOT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        binary_data LONGBLOB NOT NULL,
        PRIMARY KEY (id),
        KEY idx_item_key (item_key)
    ) $charset_collate;";

    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );
}
register_activation_hook( __FILE__, 'my_custom_binary_storage_activate' );

/**
 * Optional: Add an uninstall hook to clean up the table.
 */
function my_custom_binary_storage_uninstall() {
    global $wpdb;
    $table_name = $wpdb->prefix . 'custom_binary_storage';
    $wpdb->query( "DROP TABLE IF EXISTS $table_name" );
}
register_uninstall_hook( __FILE__, 'my_custom_binary_storage_uninstall' );
?>

The dbDelta() function is WordPress’s utility for managing database schema changes. It intelligently handles table creation and updates.

Storing Binary Data with Anonymous Classes

To encapsulate the logic for interacting with our custom table, we can leverage anonymous classes. This is particularly useful for creating temporary, single-use objects that implement specific interfaces or provide a set of methods without the overhead of defining a full class file. For binary storage, an anonymous class can act as a data handler.

Data Insertion Logic

Consider a scenario where you need to upload and store a file. The following PHP code demonstrates how to use an anonymous class to manage the insertion process.

<?php
// Assume $file_path is the temporary path to the uploaded file
// Assume $item_key is a unique identifier for this binary object
// Assume $mime_type is the MIME type of the file

if ( ! empty( $file_path ) && file_exists( $file_path ) && ! empty( $item_key ) && ! empty( $mime_type ) ) {

    $binary_data = file_get_contents( $file_path );

    if ( $binary_data === false ) {
        // Handle error: could not read file
        error_log( "Failed to read binary data from: " . $file_path );
        return false;
    }

    $storage_handler = new class($wpdb, $item_key, $mime_type, $binary_data) {
        private $wpdb;
        private $item_key;
        private $mime_type;
        private $binary_data;
        private $table_name;

        public function __construct($wpdb_instance, $key, $mime, $data) {
            $this->wpdb = $wpdb_instance;
            $this->item_key = $key;
            $this->mime_type = $mime;
            $this->binary_data = $data;
            $this->table_name = $this->wpdb->prefix . 'custom_binary_storage';
        }

        public function store() {
            $result = $this->wpdb->insert(
                $this->table_name,
                array(
                    'item_key'    => $this->item_key,
                    'mime_type'   => $this->mime_type,
                    'binary_data' => $this->binary_data,
                ),
                array(
                    '%s', // item_key
                    '%s', // mime_type
                    '%s', // binary_data (wpdb handles BLOB correctly as string)
                )
            );

            if ( $result === false ) {
                error_log( "Database error during binary storage for item_key: " . $this->item_key . " - " . $this->wpdb->last_error );
                return false;
            }
            return $this->wpdb->insert_id;
        }
    };

    $inserted_id = $storage_handler->store();

    if ( $inserted_id ) {
        // Success
        return $inserted_id;
    } else {
        // Failure
        return false;
    }
}
return false;
?>

In this example, the anonymous class takes the necessary dependencies ($wpdb, $item_key, $mime_type, $binary_data) in its constructor. The store() method encapsulates the database insertion logic, including error handling and parameter formatting for $wpdb->insert(). Note that wpdb correctly handles BLOB types when passed as a string.

Retrieving Binary Data

Retrieving the binary data is equally straightforward. We can again use an anonymous class, or a more traditional function, to fetch the data based on its item_key.

Data Retrieval Logic

<?php
// Assume $item_key is the unique identifier for the binary object to retrieve

if ( ! empty( $item_key ) ) {

    $storage_retriever = new class($wpdb, $item_key) {
        private $wpdb;
        private $item_key;
        private $table_name;

        public function __construct($wpdb_instance, $key) {
            $this->wpdb = $wpdb_instance;
            $this->item_key = $key;
            $this->table_name = $this->wpdb->prefix . 'custom_binary_storage';
        }

        public function retrieve() {
            $binary_record = $this->wpdb->get_row(
                $this->wpdb->prepare(
                    "SELECT mime_type, binary_data FROM {$this->table_name} WHERE item_key = %s",
                    $this->item_key
                )
            );

            if ( $binary_record ) {
                return array(
                    'mime_type'   => $binary_record->mime_type,
                    'binary_data' => $binary_record->binary_data,
                );
            }
            return false; // Not found
        }
    };

    $retrieved_data = $storage_retriever->retrieve();

    if ( $retrieved_data ) {
        // $retrieved_data['mime_type'] and $retrieved_data['binary_data'] are now available
        // Example: Outputting the image directly
        // header('Content-Type: ' . $retrieved_data['mime_type']);
        // echo $retrieved_data['binary_data'];
        return $retrieved_data;
    } else {
        // Not found
        return false;
    }
}
return false;
?>

The retrieval logic uses $wpdb->prepare() for security against SQL injection. It fetches only the necessary columns (mime_type and binary_data) to minimize data transfer. The result is an associative array containing the MIME type and the raw binary content.

Serving Binary Data to the Browser

A common use case is serving these binary assets directly, for example, as images for a product catalog. This typically involves a dedicated endpoint (e.g., a WordPress AJAX handler or a custom rewrite rule) that retrieves the data and sends appropriate HTTP headers.

Example: AJAX Endpoint for Serving Images

Add the following to your plugin’s functions.php or a dedicated AJAX handler file:

<?php
add_action( 'wp_ajax_my_binary_storage_get_image', 'my_binary_storage_ajax_get_image' );
// add_action( 'wp_ajax_nopriv_my_binary_storage_get_image', 'my_binary_storage_ajax_get_image' ); // If public access is needed

function my_binary_storage_ajax_get_image() {
    // Ensure a nonce check is performed for security if this is not a public endpoint
    // check_ajax_referer( 'my_binary_storage_nonce', 'nonce' );

    if ( isset( $_GET['item_key'] ) && ! empty( $_GET['item_key'] ) ) {
        $item_key = sanitize_text_field( $_GET['item_key'] );

        // Re-use the retrieval logic (or integrate it directly)
        global $wpdb;
        $table_name = $wpdb->prefix . 'custom_binary_storage';

        $binary_record = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT mime_type, binary_data FROM {$table_name} WHERE item_key = %s",
                $item_key
            )
        );

        if ( $binary_record ) {
            header( 'Content-Type: ' . $binary_record->mime_type );
            // Optional: Add caching headers for better performance
            // header( 'Cache-Control: max-age=31536000, public' );
            // header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 31536000 ) . ' GMT' );
            echo $binary_record->binary_data;
            wp_die(); // This is required to terminate immediately and return a proper response
        }
    }

    // If not found or error, send a 404 or appropriate error response
    status_header( 404 );
    echo 'Not Found';
    wp_die();
}
?>

To access this, you would make a request like /wp-admin/admin-ajax.php?action=my_binary_storage_get_image&item_key=your-unique-key. The wp_die() call is essential for AJAX handlers to prevent WordPress from appending extra output.

Performance Considerations and Alternatives

While storing binary data in the database can be convenient for small to medium-sized applications, it’s crucial to be aware of its limitations. For high-traffic e-commerce sites or applications with very large binary assets, consider these points:

  • Database Load: Large BLOBs can bloat the database, increasing backup times, replication lag, and overall query overhead.
  • Memory Usage: Retrieving large blobs can consume significant memory, potentially leading to PHP memory limit exhaustion.
  • Scalability: Database-centric binary storage doesn’t scale as well as dedicated object storage solutions.

Alternatives:

  • Filesystem Storage: Store files on the server’s filesystem (e.g., in wp-content/uploads/custom-storage/) and store only the file path or URL in the database. This is generally more performant for large files.
  • Object Storage (AWS S3, Google Cloud Storage, etc.): For highly scalable and robust solutions, integrate with cloud object storage services. Store the object URL or identifier in your custom database table.
  • CDN Integration: Serve binary assets through a Content Delivery Network for faster global delivery and reduced load on your origin server.

The anonymous class pattern presented here offers a clean, encapsulated way to manage database interactions within WordPress, making your code more modular and readable, regardless of whether you choose to store binaries directly in the database or reference external storage.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Step-by-Step Guide: Offloading high-frequency shipping tracking histories metadata writes to a Redis KV store
  • How to implement custom REST API Controllers endpoints with token authentication in Gutenberg blocks
  • Step-by-Step Guide to building a custom real-time activity logs block for Gutenberg using PHP block-render callbacks
  • How to implement custom WordPress Database Class ($wpdb) endpoints with token authentication in Gutenberg blocks
  • Building custom automated PDF financial reports and invoices for WooCommerce using custom PHP-Spreadsheet exports

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (41)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (42)
  • WordPress Plugin Development (43)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • Step-by-Step Guide: Offloading high-frequency shipping tracking histories metadata writes to a Redis KV store
  • How to implement custom REST API Controllers endpoints with token authentication in Gutenberg blocks
  • Step-by-Step Guide to building a custom real-time activity logs block for Gutenberg using PHP block-render callbacks

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala