Two Different Logos on a Single WP Instance

The practice of providing the same products under multiple selling brands, combined with the popularity of WordPress and WooCommerce platforms, inspired us to tackle the given problem from a technical perspective. The focus is on the implementation of dynamic logo displaying, based on the store brand. In the scenario where the single WordPress/WooCommerce system should provide e-store functionality for different brands, there is a wide range of criteria based on which logo should be changed. It comes handy to have full control over the implementation and to be able to easily and flexibly apply necessary criteria, whenever it changes.

Two Different Logos on a Single WP Instance

Chosen Logo Changing Criteria

There are multiple criteria rules that could be defined and properly applied to decide which logo should be presented to the user. Some examples might include the device being used, the country from which the user is accessing the web store, existing cookies that might indicate a previous user's engagement with the specific brand, etc. These examples are from the perspective that the user is a guest user. If the user is signed up and logged in to the store, the options range is wider because the system might contain information about previous purchases, preferred products, etc.

This article describes how to implement dynamic logo functionality based on the domain name. Two domain names and corresponding Logo URLs are provided through the WP Admin area. The idea is that when the user accesses the web store using "domain1.com" and "domain2.com" it is presented with "Logo 1" and "Logo 2" respectively.

GitHub Repository

Complete implementation of the solution shown in this article can be cloned from GitHub repository: https://github.com/emir-gradient/gradient-logo-changer.

Preparing Local Environment

First, perform the following steps:

After these two steps, you should have Web Store up and running.

To test the implemented solution, we utilized the /etc/hosts file configuration on Linux operating system. On Windows, that file is C:\Windows\System32\drivers\etc\hosts. On Mac-OS that file is /private/etc/hosts.

To achieve this, make sure to add the following lines in the hosts file below "127.0.0.1 localhost" line:

127.0.0.1   domain1.com
127.0.0.1   domain2.com

These lines basically inform the underlying operating system that, when requested to access domains from this list (domain1.com or domain2.com), it should resolve them to IP 127.0.0.1 instead of utilizing DNS service for domain IP resolution. This allows local testing with different domains for scenarios where access domains matter.

Writing the WordPress Plugin

To create a plugin that would be recognized by the WordPress system, we need to put the necessary plugin implementation in the wp-content/plugins directory (found in the root of the WordPress project). We created a directory gradient-logo-changer and an empty PHP file named gradient-logo-changer.php inside of it.

The first step in writing a plugin is to write a plugin header to gradient-logo-changer.php in the form of a PHP comment. These are parsed by WordPress for plugin recognition. So, after this action, the gradient-logo-changer.php file looks like this:

/**
 * Plugin Name: Gradient Logo Changer
 * Author: Gradient Team
 * Author URI: https://gradient.ba
 */

Also, as presented in the following screenshot, the WordPress system recognizes that the Gradient Logo Changer plugin exists:

Blog picture

To add more details about the written plugin, check out the official WordPress documentation: Plugin Header Requirements.

Modifying Logo Image by Filter

WordPress provides hooks for plugins that allow modification of final solution behavior by themes and plugins. Hooks are separated into two categories: actions and filters. For the purpose of dynamic modification of the logo image, we have utilized the wp_get_attachment_image_src filter. WordPress invokes this filter whenever any attachment image is requested (including logo image).

Inside our plugin implementation, we write the following statement:

add_filter('wp_get_attachment_image_src', 'modify_logo_image', 10, 3);

This means that whenever an attachment image is requested in WordPress, our modify_logo_image function should be invoked. Argument "10" means that the filter function has a priority of 10 when executed together with other filters that are added for the wp_get_attachment_image_src filter. Argument "3" means that provided function accepts 3 parameters. More on this can be checked here: Add Filter.

Implementation of modify_logo_image function is as follows:

function modify_logo_image($imageInfo, ...$args)
{
    $customLogoId = get_theme_mod('custom_logo');

    if ($args[0] === $customLogoId) {
        $imageInfo[0] = 'https://gradient.ba/assets/img/logo.png';
    }

    return $imageInfo;
}

Filter wp_get_attachment_image_src is executed for every attachment image. To recognize the call executed for the logo, we utilize get_theme_mod('custom_logo') function call to get the logo ID. Additionally, our modify_logo_image function is invoked with the args[0] parameter that represents the ID of the attachment image to which the filter is applied. When args[0] matches $customLogoId, we can be sure that the filter is applied on the logo and we should perform our modification.

Finally, we simply replace $imageInfo[0] with the URL of the image we need for the logo.

Deciding on Logo Image by the Domain Criteria

So far, we have an implementation that will modify the logo of the website with a hard-coded Gradient logo, regardless of which logo is configured in the system. The next step is the implementation of the criteria function, to actually make a decision about the logo to be presented related to the site domain. In PHP (hence in WordPress) we can recognize domain name using PHP global $_SERVER['SERVER_NAME']. Global $_SERVER['SERVER_NAME'] gives the value of the server name as defined in the host configuration. If we need a hostname that is targeted in the user's request we use $_SERVER['HTTP_HOST'].

So, we create the following function:

function get_logo_image() {
    $domain = sanitize_url($_SERVER['SERVER_NAME']);

    $logo = null;

    if ($domain === 'domain1.com') {
        $logo = 'https://...Domain1Logo.jpg';
    } else if ($domain === 'domain2.com') {
        $logo = 'https://...Domain2Logo.png';
    }

    return $logo;
}

What it does is that it, based on the server name, returns the appropriate logo image path. In case the server name does not match any of the requested domains, then null is returned.

So, in our modify_logo_image filter function, we utilize get_logo_image function to retrieve a valid logo image:

function modify_logo_image($imageInfo, ...$args)
{
    $customLogoId = get_theme_mod('custom_logo');

    if ($args[0] === $customLogoId) {
        $logoImageSrc = get_logo_image();
        if ($logoImageSrc) {
            $imageInfo[0] = $logoImageSrc;
        }
    }

    return $imageInfo;
}

In case when there is no result image (null is returned) then we keep the default one to be presented.

Configuration of Domains and Logo Sources through the WP Admin

The last step is to implement configurations through WP Admin, to eliminate the necessity to change plugin implementation whenever domains or logo images change. To achieve that, we defined two domains and two logo URLs as WordPress options.

So, to intercept default WordPress behavior, first, we register the function to be executed on the admin_init hook. This action is executed whenever the WP Admin area is initialized.

add_action('admin_init', 'set_domains_settings_inputs');

Function set_domains_settings_inputs implementation (together with utility functions used) is implemented as follows:

function set_domains_settings_inputs()
{
    create_settings_field('domainA', 'Domain A');
    create_settings_field('logoA', 'Logo A');
    create_settings_field('domainB', 'Domain B');
    create_settings_field('logoB', 'Logo B');
}

function create_settings_field($fieldId, $title) {
    add_settings_field($fieldId, $title, function () use ($fieldId) {
        render_settings_input($fieldId);
    }, 'general');

    register_setting(
        'general',
        $fieldId
    );
}

function render_settings_input($optionName)
{
    $value = '';
    $option = get_option($optionName);
    if ($option !== false) {
        $value = $option;
    }

    echo '<input type="text" name="' . $optionName . '" id=' . $optionName .'" value="' . $value . '" />';
}

So, to demystify this part:

Function create_settings_field actually registers the option with the name $fieldId and defines its $title (presented on the interface). It is defined that inputs should be presented on the general page in the WordPress site settings. Function render_settings_input actually renders input on the interface. More details on Add Settings Field and Register Setting.

After these steps, when one navigates to settings -> general page of WP Admin, it should get an interface like this:

Blog picture

At this point, saving values for Domain A, Logo A, Domain B, and Logo B should work properly.

The final action to do is to extend get_logo_image() function to actually read these options. To read options from the database, we use get_option() function. Function get_logo_image() after this change looks like this:

function get_logo_image() {
    $domain = sanitize_url($_SERVER['SERVER_NAME']);

    $domainA = get_option('domainA');
    $domainB = get_option('domainB');

    $logo = null;
    if ($domain === $domainA) {
        $logoA = get_option('logoA');
        if ($logoA !== false) {
            $logo = $logoA;
        }
    } else if ($domain === $domainB) {
        $logoB = get_option('logoB');
        if ($logoB !== false) {
            $logo = $logoB;
        }
    }

    return $logo;
}

At this point, WordPress page logo should be changed based on configuration from settings.

Complete Plugin Implementation

After all performed steps and implementation split into files based on concerns, the resulting plugin has three files with the following contents:

gradient-logo-changer.php

/**
 * Plugin Name: Gradient Logo Changer
 * Author: Gradient Team
 * Author URI: https://gradient.ba
 */

$pluginDir = plugin_dir_path( __FILE__ );

require_once("$pluginDir" . 'wp-admin-settings.php');
require_once("$pluginDir" . 'wp-frontend.php');

add_action('admin_init', 'set_domains_settings_inputs');
add_filter('wp_get_attachment_image_src', 'modify_logo_image', 10, 3);

wp-frontend.php

function get_logo_image() {
    $domain = sanitize_url($_SERVER['SERVER_NAME']);

    $domainA = get_option('domainA');
    $domainB = get_option('domainB');

    $logo = null;
    if ($domain === $domainA) {
        $logoA = get_option('logoA');
        if ($logoA !== false) {
            $logo = $logoA;
        }
    } else if ($domain === $domainB) {
        $logoB = get_option('logoB');
        if ($logoB !== false) {
            $logo = $logoB;
        }
    }

    return $logo;
}

function modify_logo_image($imageInfo, ...$args)
{
    $customLogoId = get_theme_mod('custom_logo');

    if ($args[0] === $customLogoId) {
        $logoImageSrc = get_logo_image();
        if ($logoImageSrc) {
            $imageInfo[0] = $logoImageSrc;
        }
    }

    return $imageInfo;
}

wp-admin-settings.php

function get_logo_image() {
    $domain = sanitize_url($_SERVER['SERVER_NAME']);

    $domainA = get_option('domainA');
    $domainB = get_option('domainB');

    $logo = null;
    if ($domain === $domainA) {
        $logoA = get_option('logoA');
        if ($logoA !== false) {
            $logo = $logoA;
        }
    } else if ($domain === $domainB) {
        $logoB = get_option('logoB');
        if ($logoB !== false) {
            $logo = $logoB;
        }
    }

    return $logo;
}

function modify_logo_image($imageInfo, ...$args)
{
    $customLogoId = get_theme_mod('custom_logo');

    if ($args[0] === $customLogoId) {
        $logoImageSrc = get_logo_image();
        if ($logoImageSrc) {
            $imageInfo[0] = $logoImageSrc;
        }
    }

    return $imageInfo;
}

Get an Offer

Contact Us or Schedule a Meeting with us to get an offer for our development & consulting services regarding your current or next WordPress project.

There are no comments

Leave your comment