SureCart/ Hoster Licencing Update

Tech Articles | March 19, 2025 | Automation, Coding, Plugins, Reallyusefulplugins, SureCart, Wordpress

So, I use two licence managers for my plugins and three methods of updating plugins:

Updates:
1. SureCart 2. Hoster 3. WP Update Server

Licencing:
1. SureCart 2. Hoster, I also have this, but I tend not to use it any more as most of my “sales” are through my Surecart instance, and the ones that aren’t are through Hoster. I do also have Quadlayers Licence Manager for WooCommerce but it’s useless, and the documentation and support are pretty lacking

So, the WP Update Server handles my plugin updates. This includes the ones that would traditionally come from WordPress. Why? Because it lets me work with my update server and test plugins before they roll out to my critical sites, it’s just one step in my update progress.

I achieved this twofold in the first instance by running my own update server and my own update class, which is expandable to almost any plugin In fact, in the original version of this, the only plugin that caused me issues was WPcodeBox I had to modify the zip file to stop its inbuilt update check as they clash its all to do with slugs and WordPress requiring them to be unique. I have, though, been testing for quite some time some modifications and tweaks to the wp update server, which can be viewed here. The Updater is bundled with my Ninja Updater plugin and so far I haven’t found a reason to chang a system that works well.

I then disable updates from anything but me with a snippet similar to this one, again run as a snippet by Ninja Updater, so if it’s installed and activated, updates will come from Ninja Updater

add_filter('pre_set_site_transient_update_plugins', function ($transient) {
    if (empty($transient->response) || !is_object($transient)) {
        return $transient;
    }

    // Allowed domains
    $allowed_domains = [
        'downloads.wordpress.org',
        'your-update-server.com', // Replace with your actual update server domain
    ];

    foreach ($transient->response as $plugin_slug => $plugin_data) {
        $update_url = isset($plugin_data->package) ? $plugin_data->package : '';

        // Check if the update URL is from an allowed domain
        if (!empty($update_url)) {
            $parsed_url = parse_url($update_url);
            if (!isset($parsed_url['host']) || !in_array($parsed_url['host'], $allowed_domains)) {
                unset($transient->response[$plugin_slug]); // Remove unauthorized updates
            }
        }
    }

    return $transient;
});
PHP

I can write a more in-depth article on this if there is interest, but the purpose of today’s article was about preparing releases for my “commercial plugins” I put it in speech marks because I still don’t consider myself a developer, and I still don’t consider it a business.

Hoster, I have written previously about my hoster workflow and even updated it recently, but in my last few days cleaning up code bases and making my workflows slicker,I’ve made some additional change and this is fast and efficient, and it all ties into my new documentation methodology

I can now keep a single text file-based update log in a repo for each plugin, call that log when updating hoster or sure cart release.json and upload the same text file to the website to generate the change log, I wanted to do additional work because I noticed some of my maintenance plugins need there “tested version” updated and I hadn’t done this for my hoster files for a longtime.

So I ran PHP on the Windows path, so I wrote an updated bat script, updated the flowmattic flow and threw in a few PHP files to convert the text base change long into HTML ready to upload to Hoster and also can be imported into a SureCart json which accepts the same sort of data.

Another, called scan extracts scans for the WordPress headers and extracts them for me for the update, asking me if I want to update the version number, as well as this in each repo I now have a set of tools to allow me to quickly update the tested version by checking the WordPress API

A version of the updated plugin headers is below

<?php
// Get plugin file from arguments
if ($argc < 2) {
    die("Usage: php update_plugin_headers.php <plugin_file>\n");
}

$plugin_file = $argv[1];

// Ensure the file exists
if (!file_exists($plugin_file)) {
    die("Error: Plugin file not found.\n");
}

// Read the plugin file
$plugin_content = file_get_contents($plugin_file);

// Detect comment style (supports both `/*` and `/**`)
$comment_start = preg_match("/^\s*\/\*{1,2}/m", $plugin_content) ? "/**" : "/**";

// Define standard headers & defaults
$headers = [
    'Plugin Name'       => '',
    'Tested up to'      => '6.7.2',  // Always updated
    'Description'       => 'No description provided.',
    'Requires at least' => '6.5',    // Always updated
    'Requires PHP'      => '7.4',    // Always updated
    'Version'           => '',       // Always updated
    'Author'            => 'reallyusefulplugins.com',
    'Author URI'        => 'https://reallyusefulplugins.com',
    'License'           => 'GPL-2.0-or-later',
    'License URI'       => 'https://www.gnu.org/licenses/gpl-2.0.html',
    'Text Domain'       => '',
    'Website'           => 'https://reallyusefulplugins.com'
];

$plugin_info = [];

// Extract existing values, allowing flexible input formats
foreach ($headers as $key => $default) {
    if (preg_match("/^ \*? $key:\s*(.+)$/mi", $plugin_content, $matches)) {
        $plugin_info[$key] = trim($matches[1]);
    } else {
        $plugin_info[$key] = null; // Mark as missing
    }
}

// Fetch latest WordPress version for "Tested up to"
$latest_wp_version = file_get_contents('https://api.wordpress.org/core/version-check/1.7/');
$latest_wp_version = json_decode($latest_wp_version, true)['offers'][0]['current'] ?? '6.7.2';

// **Ask for version-related fields every time**
function prompt($message, $default) {
    echo "$message [$default]: ";
    $input = trim(fgets(STDIN));
    return $input !== "" ? $input : $default;
}

$plugin_info['Version'] = prompt("Enter new Version", $plugin_info['Version'] ?? '');
$plugin_info['Requires at least'] = prompt("Enter Requires at least", $plugin_info['Requires at least'] ?? '6.5');
$plugin_info['Tested up to'] = prompt("Enter Tested up to (latest: $latest_wp_version)", $latest_wp_version);
$plugin_info['Requires PHP'] = prompt("Enter Requires PHP", $plugin_info['Requires PHP'] ?? '7.4');

// **Only ask for missing fields**
foreach ($headers as $key => $default) {
    if ($plugin_info[$key] === null || $plugin_info[$key] === '') {
        $plugin_info[$key] = prompt("Enter $key", $default);
    }
}

// **Standardize Output**
$max_length = max(array_map('strlen', array_keys($headers))) + 1;
$spacing_format = " * %-{$max_length}s %s"; // **Proper spacing for alignment**
$formatted_header = "$comment_start\n";

// **Ensure fields are in the correct order and properly formatted**
foreach ($headers as $key => $default) {
    if (!empty($plugin_info[$key])) {
        $formatted_header .= sprintf($spacing_format, $key . ":", trim($plugin_info[$key])) . "\n";
    }
}
$formatted_header .= " * */\n";

// **Replace existing header block with the standardized version**
$plugin_content = preg_replace("/\/\*{1,2}.*?\*\//s", $formatted_header, $plugin_content, 1);

// Save the updated plugin file
file_put_contents($plugin_file, $plugin_content);

echo "✅ Plugin headers standardized successfully!\n";
?>
PHP

Below is the output it asks me for information and lets me update them Enter means keep what suggested it now takes seconds to update and prepare a release for zipping

Once its headers are updated, I’ve nailed Hoster; it will generate an HTML file, which is uploaded and pulled by flowmattic on triggering along with new plugin data from the new standardised headers, this allows all this meta data to be updated in hoster with no issues what so ever and keeps my hoster plugins totally uptodate.

So once I am ready for a release, two commands and my plugin is updated, key information is updated as needed, and the release is auto-uploaded and available in hoster within about 30 seconds thanks to the bat scripts, PHP code and sync back pro. I don’t need to log to the website at all to make the update, its all done from my Windows development machine.

So that works for all the hoster plugins with no issues at all.

SureCart

My SureCart workflow is a little different, I don’t have direct access to products to add and update downloads and can’t do what I am doing here it also relies on release.json files in the plugin for updates which makes sense.

So I now needed to find a way to make these slicker and use the same changelog text file I will cover this once I have worked out my methodology.

Support the Author

buy me a coffee
Really Useful Plugin Logo
Appoligies for any spelling and grammer issue. As a dyslexic i need to rely on tools for this they like me are not perfect but I do try my best