GETTING STARTED

Migrating to 1.4.0

Hoster 1.4.0 changes how packages are stored and how client sites ask for updates. This page tells you what happens when you update, what could break, and what you can do at your own pace.

Short answer
Nothing forces you to change your products. Update Hoster and every plugin and theme you already distributed keeps receiving updates, with the same update URLs, licence keys and activations. Moving your products to the new updater is recommended, not required, and you can do it whenever you next release them.

Do I have to do anything?

  • Your customers: nothing. Their sites keep updating through the update URL that is already in your products.
  • You, right after updating Hoster: a few minutes of checks. Add one server rule if your site runs on nginx, clear your page cache and open Site Health (see Part A below).
  • You, later (recommended): ship each product once with the new updater, and then switch the old update links off. Until you do, licensed products on the old updater stay less protected (see Parts B and C below).

What keeps working without any change

  • Update URLs of products already in the wild. Both old formats are still answered: the secure-download.php link (products made with Hoster 1.0 to 1.3) and the static uploads/downloads/<id>/info.json file (products made before Hoster 1.3).
  • Free products. They always update, through every old and new path.
  • Licensed products on the old updater. They update while Legacy update links for licensed products is on. The upgrade turns it on for every site that already had Downloads, so nothing stops by default.
  • Licence keys, activations, expiry dates and activation limits. Nothing is migrated or reset.
  • Download IDs, slugs, versions, changelogs and Download URLs and their permalinks. The permalink structure stays the same unless you change it yourself in Settings → Permalinks.
  • Your Media Library files. Hoster never deletes them.
  • The GitHub connection and existing release.yml workflows. A workflow copied from an older Hoster keeps building releases. It just doesn't trigger on tags that start with v, and it doesn't install Composer dependencies until you copy the new one from Downloads → Resources.
  • The licence hooks and the WP-CLI command. hoster_create_new_license, hoster_update_license and wp hoster_expire_licenses work as before.

What the upgrade does automatically

The upgrade runs once, on the first page load after you update Hoster.

  • Zips are copied to private storage. Each Download whose zip is in this site's uploads (a Media Library file) gets a copy in wp-content/uploads/hoster-private/<random folder>/. From then on the package is served from that copy.
  • Old public zips are removed. Zips that Hoster rebuilt from private GitHub repositories in wp-content/uploads/downloads/<id>/ are deleted once the Download has its private copy. Empty folders go too.
  • Static info.json files are rewritten, not removed. A Download that had an info.json keeps it, for client sites generated before Hoster 1.3 (see "Products made before Hoster 1.3" below). Files of Downloads that no longer exist are deleted.
  • Post tags become Download Tags. Each tag on a Download is copied to a Download Tag with the same name and slug. A blog tag is deleted only when nothing else uses it. This step runs once Hoster's own licence is active.
  • Legacy update links are turned on for sites that already had Downloads. New installs start with them off.

Downloads whose package is a remote URL have no private copy: Hoster fetches the file and passes it through when a client downloads it.

What can break

Nothing in the update flow breaks by default. The changes below can affect your own setup, so check the ones that apply to you.

1. Download buttons on licensed products now check the licence

Before 1.4.0 the button link of a licensed product was a permanent token link that anyone could open. The button now points to /?hoster_dl=<id>, which checks access when it is clicked:

  • Visitors see "Log in to download".
  • Users with an active licence download the file.
  • You and your editors always download it.
  • Logged-in users without a licence see a locked button with a lock icon and a notice (you can change or hide it in the block settings).

Free products are not affected. If you sold licensed downloads through a public button on purpose, you now need a licence for them, which is what the licence was meant to do. Pages you cached before the upgrade still contain the old link: it works for free products, and for licensed ones only while legacy links are on. Clear your page cache after the upgrade.

2. Raw zip URLs of GitHub rebuilds return 404

If Hoster built zips from a private GitHub repository, they used to sit in wp-content/uploads/downloads/<id>/, publicly readable. The upgrade deletes them. Clients never used these URLs, so updates are not affected. Only a raw zip URL you pasted by hand into a page, email or script stops working. Use a Download Button or the /?hoster_dl=<id> link instead.

3. Custom code that reads the download URL

  • The REST API no longer returns the raw download_url of a Download to users who can't edit it.
  • get_secure_download_url( $id ) is deprecated. It still returns a signed link for free Downloads, and an empty string for licensed ones.
  • Use the /?hoster_dl=<id> link, or the Download Buttons, for anything visitors click.

4. Downloads use Download Tags, not blog tags

If a theme, query or template filters Downloads by the blog's post_tag, update it to the download_tag taxonomy. Tag archive pages moved from your blog's tag URL to /download-tag/<slug>/ (or the base you set in Settings → Permalinks). Downloads no longer show up in blog tag archives.

5. Licence checks are stricter

  • The licence shortcode lets only the licence owner (or an admin) add or remove sites. Adding a site there follows the same status, expiry and activation-limit rules as the remote API.
  • Sites are compared by host: scheme, www. and a trailing slash are ignored, so https://www.Example.com/ and example.com are the same site. A subdomain is a different site. Sites already stored on a licence keep matching.
  • After 10 failed licence attempts from one IP address in a minute, the next ones are blocked for that minute. Behind a proxy, use the hoster_client_ip filter so Hoster sees the real address.

6. The new updater needs pretty permalinks on the Hoster site

Updater 2.1.0 asks https://your-hoster-site.com/wp-json/hoster/v1/update/<slug>. That works with every permalink structure except Plain. If your Hoster site uses Plain permalinks, switch to another structure before you ship products with the new updater. Tools → Site Health → Hoster update endpoint checks it. Products with the old updater are not affected.

7. Turning legacy links off stops old products

This is a choice you make, not something the upgrade does. With Legacy update links for licensed products off, licensed products that still use the old updater get no more updates until customers install a newer version by hand. Free products always keep updating. See Part C below before you switch it off.

8. GitHub tokens

Hoster now refreshes expiring GitHub tokens on its own. If GitHub rejects the refresh, an admin notice asks you to reconnect the account. Connecting also needs an administrator and a one-time state value that Hoster adds itself, so use the Connect button rather than a saved callback URL.

Part A: right after updating Hoster

  1. Back up the site and its wp-content/uploads folder.

  2. Update Hoster and open any admin page once, so the upgrade runs.

  3. nginx only: add this rule to the site's server block and reload nginx. Apache and LiteSpeed read the .htaccess Hoster writes in the private folder, but nginx ignores it.

    location ^~ /wp-content/uploads/hoster-private/ { deny all; }
    
  4. Open Tools → Site Health and fix anything the Hoster checks report. They cover the update endpoint, private storage, permalinks, Downloads without a package, your Hoster licence and legacy client activity.

  5. Clear your page cache, so pages show the new button links.

  6. Check one free and one licensed product on a test site: the update appears and installs.

  7. Optional, recommended: once a Download's sidebar says "Served from private storage; the Media Library file can be deleted.", delete the Media Library zip. Until then that file stays public at its old URL, and anyone who knows the URL can download it without a licence. For future releases use Upload new version, which never puts the zip in the Media Library.

Part B: move your products to Updater 2.1.0

Do this when you next release a product, there is no deadline. Ship one release of the product with the new files. Customers with the old updater install it through the old path, and from then on their site uses the new update endpoint.

What you gain:

  • The licence is checked for every update and every download. Old updaters send no licence key, so their links are permanent and skip that check.
  • The update links expire after an hour and are bound to the licence and the site.
  • The old updater's known problems are fixed: updates that disappear after the first admin page load, missing updates in cron, WP-CLI and auto-updates, and a "Check for updates" link that another plugin caught.
  • The licence message shows on the plugin row, and the upgrade notice shows under the update.

Steps, for each product:

  1. Go to Downloads → Resources and choose the Download.
  2. Main plugin file tab: in your main plugin file, remove the old Hoster block (the constants, the _REMOTE_URL and _CACHE_KEY definitions, the require of inc/update.php and the new …_DPUpdateChecker(...) call). Add the two lines from the generated file instead: the …_FILE constant and require_once __DIR__ . '/inc/hoster.php';. For a theme, use the generated style.css header and functions.php line.
  3. Save the generated inc/hoster.php in your product.
  4. Updater tab: replace inc/update.php with the generated file (Updater Version: 2.1.0 in its header).
  5. Licensed products: make sure your licence code saves the activated key in the option shown on the License tab, for example my_plugin_license_key. Customers who activated their licence before this release need their key in that option too, so copy it there from wherever your product stored it. Without the key, the plugin row shows "Enter your license key to receive updates." and the update can't be installed.
  6. Bump the version and release it the way you normally do.

See Create Plugin Update for the full file layout and License on Hosted Plugin for the licence key.

Part C: turn legacy links off

The package links behind the old updater, and the links inside the static info.json files, are permanent and not licence-checked. While the setting is on, anyone who has one of those links can download the licensed product.

Turn Legacy update links for licensed products off (Downloads → License → Client updates) when:

  • your licensed products have shipped with Updater 2.1.0 for a while, and
  • their sidebar says "Legacy client requests: last seen never", or the date hasn't moved for weeks.

Site Health also says "Legacy update links can probably be turned off" when no legacy client asked for a licensed Download in the last 30 days.

With the setting off:

  • Licensed products on the old updater get no more updates. Their customers see no update until they install a current version by hand.
  • Package links already handed to old clients stop working for licensed products.
  • The static info.json files of licensed products are deleted.
  • Free products are not affected.
  • You can switch it back on at any time, and the files come back.

See which products still have old clients

  • On each licensed Download, under the Licensed toggle: "Legacy client requests: last seen 3 days ago" (or "never").
  • In Tools → Site Health, the Hoster legacy update links check lists the licensed Downloads that old clients asked for in the last 30 days.

Only requests from WordPress sites count, so a legacy link opened in a browser (for example a button link cached before the upgrade) doesn't. The time is stored at most once an hour per Download.

Products made before Hoster 1.3

Updater snippets generated with Hoster 1.2 or older don't ask your site for updates. They read a static file straight from your uploads folder:

https://your-site.com/wp-content/uploads/downloads/<id>/info.json

Hoster 1.4.0 keeps these files working:

  • The upgrade marks every Download that had an info.json file, and rewrites the file with the current update info. Downloads created after the upgrade never get one.
  • Hoster rewrites the file whenever the Download changes: on every save, Upload new version, Release API call and GitHub sync.
  • The package link in the file is the permanent legacy link (/hoster-secure-download/?token=…), because a static file can't hold a link that expires.
  • Free products always keep their file.
  • Licensed products keep it only while Legacy update links for licensed products is on.
  • A Download that is unpublished, trashed or deleted has no file. It comes back when the Download is published again.

These customers read the file without asking Hoster, so they only show up in "last seen" when they download an update. A customer who skipped several releases may still use one even when "last seen" says "never". Moving the product to Updater 2.1.0 (Part B) is the way to bring them over.

Summary

  • Nothing is forced. Update Hoster and everything you shipped keeps updating.
  • Part A is a few minutes of checks and is worth doing right away.
  • Part B and Part C are recommended for licensed products, at your own pace. Until you finish them, the old, unchecked links stay reachable.
  • What can break is limited to your own setup: raw zip URLs pasted by hand, code that reads download_url or blog tags on Downloads, and public buttons for licensed products.