An Independent backoffice for WordPress?

Published: (February 15, 2026 at 04:51 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

It All Started with Metadata

Milk Admin natively relies on two separate databases — one for internal configuration, the other for managing external data. This architecture made it a natural candidate for integration with external systems, such as a WordPress database.

Once connected, I was able to start managing a WordPress site’s tables directly from my panel. From there, an immediate need emerged: handling metadata relationships natively. I looked at how the most well‑known and mature systems similar to mine handled this, and I found that there usually isn’t a native system for it. So I wrote hasMeta, a method that handles native metadata relationships.

$rule->table('#__users')
    ->id()
        ->hasMeta('nickname', UserMetaModel::class, 'user_id')
        ->hasMeta('city', UserMetaModel::class, 'user_id')
    ->string('name', 100)->required();

There are a number of other small conventions I inherited from WordPress: the dynamic table prefix (#__) and a functions.php file for more advanced customizations.

When I showed the metadata functionality to a client, his reaction was enthusiastic. He asked for a demo that had nothing to do with metadata—he wanted to verify whether my admin panel could handle WordPress authentication.

WordPress authentication hook

I developed a plugin that hooks into WordPress’s authenticate filter, with priority 30, to intervene after the standard checks:

add_filter('authenticate', [$this, 'authenticate'], 30, 3);

The method receives three parameters: $user (the result of previous checks), $username, and $password. If conditions require it, the plugin makes a POST call to my admin panel’s endpoint via wp_remote_post:

$args = [
    'headers' => ['Content-Type' => 'application/json'],
    'timeout' => (int)$options['request_timeout'],
    'body'    => wp_json_encode([
        'username' => $username,
        'password' => $password,
    ]),
];
$response = wp_remote_post($endpoint, $args);

Public API endpoint in Milk Admin

On the Milk Admin side, I created a dedicated module that exposes a public endpoint for credential verification:

#[ApiEndpoint('public-auth/check-credentials', 'POST')]

It can be reached with a simple call:

POST /public_html/api.php?page=public-auth/check-credentials
Content-Type: application/json

{
  "username": "user@example.com",
  "password": "password"
}

For this demo the table only contains username and password, but nothing prevents extending the response with additional data such as roles, permissions, or profile information.

The plugin is designed not to interfere with administrators and not to block the native flow when username or password are empty; in those cases, WordPress handles everything as usual.

What started as an experiment with metadata turned into a concrete demonstration of interoperability. My admin panel doesn’t replace WordPress—it works alongside it: it makes it easy to create a management panel that extends WordPress data, and it can also integrate well via API.

GitHub project (link omitted).

0 views
Back to Blog

Related posts

Read more »