Building a WordPress API Client The Right Way

I had a client come to me with a tricky requirement: they needed to sync users between two completely separate WordPress sites. One site was the source of truth, and the other needed to reflect its user base in near real-time. It’s a classic problem, and the WordPress REST API is the perfect tool for the job. My goal was to build a clean, reusable WordPress API client to handle the communication.

My first thought was to grab one of the existing PHP clients for the WordPress API. Why reinvent the wheel, right? But I quickly hit a snag. Most of them are built for the wider PHP world, meaning they pull in external dependencies like Guzzle to handle HTTP requests. For a project that’s already running on WordPress, that felt wrong. It’s like bringing a whole toolbox when you just need one screwdriver that’s already in the kitchen drawer.

WordPress already has a perfectly good, built-in HTTP API powered by the WP_Http class. It’s stable, it’s reliable, and it’s already loaded on every page request. Pulling in another library to do the same thing is just asking for future conflicts and unnecessary bloat. Trust me on this, I’ve seen it cause a total nightmare on a high-traffic site before.

Building a Lean WordPress API Client

So, I decided to build my own lightweight client. The core principle was simple: it had to leverage WordPress internals and be completely self-contained. No outside libraries. The whole approach is based on a solid foundation I first saw detailed by Carl Alexander on his blog, which is a great read if you want to go deeper. The heart of the class is its constructor, where we inject the dependencies it needs to operate.

public function __construct( WP_Http $http, $base_url, $username, $password ) {
    $this->http     = $http;
    $this->base_url = $base_url;
    $this->token    = base64_encode( $username . ':' . $password );
}

By passing in the WP_Http object, we’re using dependency injection. This makes the class more testable and decoupled from WordPress’s global state. The class doesn’t care how the `WP_Http` object is made; it just needs something that can make GET requests. The other two parameters are straightforward: the URL of the site we’re connecting to and the credentials for Basic Authentication.

Here’s the kicker: the actual request method is beautifully simple. It builds the request URL, adds the necessary authorization headers, and then hands the whole thing off to WP_Http. If something goes wrong, it returns a WP_Error object, just like a good WordPress citizen should.

private function get( $endpoint, array $query = [] ) {
    $url = $this->base_url . $endpoint;
    if ( ! empty( $query ) ) {
        $url .= '?' . http_build_query( $query );
    }

    $args = [
        'headers' => [
            'Authorization' => 'Basic ' . $this->token,
        ],
    ];

    $response = $this->http->get( $url, $args );

    if ( is_wp_error( $response ) ) {
        return $response;
    }

    $body = wp_remote_retrieve_body( $response );
    $decoded = json_decode( $body, true );

    if ( json_last_error() !== JSON_ERROR_NONE ) {
        return new WP_Error( 'invalid_json', 'The JSON response could not be decoded.' );
    }

    return $decoded;
}

So, What’s the Point?

Look, you could just use wp_remote_get() with a bunch of arguments every time you need to hit an API endpoint. But that gets messy fast. The real lesson here is about building reusable, professional-grade tools. By wrapping the logic in a class, you get a few key benefits:

  • It’s Reusable: You can use this client anywhere in your project to talk to the remote site.
  • It’s Clean: All the messy details of authentication and URL building are hidden away.
  • It’s Robust: It handles errors gracefully by returning a WP_Error object, which is the standard, expected way to handle failures in WordPress.

This is the difference between a quick hack and a maintainable solution. It’s about thinking ahead and saving your future self—or the next developer—a massive headache.

Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.

Leave a Reply

Your email address will not be published. Required fields are marked *