Skip to main content

BetterLinks & Affiliate Links

Operational notes for BetterLinks + BetterLinks Pro (both 3.0.0) on id86.net, covering click analytics, the cron dependency, the LiteSpeed REST-cache interaction, and the two places affiliate links are stored.

Quick Facts

PropertyValue
Pluginsbetterlinks + betterlinks-pro (both 3.0.0)
Short-link prefix/link/ (e.g. https://id86.net/link/racknerd)
Links tableid86net_betterlinks
Clicks tableid86net_betterlinks_clicks
Categories tableid86net_betterlinks_terms
JSON bufferwp-content/uploads/betterlinks_uploads/clicks.json

Click Analytics Flow (two-stage)

BetterLinks does not write clicks straight to the DB. It buffers them:

  1. Every redirect records a click into wp-content/uploads/betterlinks_uploads/clicks.json (this is the BETTERLINKS_EXISTS_CLICKS_JSON mode).
  2. The hourly betterlinks/analytics cron moves the buffered clicks into id86net_betterlinks_clicks and empties the JSON file back to {}.

Why analytics can appear empty

If the betterlinks/analytics cron never fires, clicks accumulate in clicks.json forever and the Analytics UI / DB stay at 0. On this site the trigger was missing: WP-Cron only fires on page loads, and LiteSpeed page caching intercepted visits before WP ran cron.

The fix that is in place

A real system cron now drives WP-Cron so the hourly sync always happens:

  • /usr/local/bin/id86-wpcron.sh — runs wp cron event run --due-now as the site user.
  • /etc/cron.d/id86-wpcron*/5 * * * * root /usr/local/bin/id86-wpcron.sh >/dev/null 2>&1
  • wp-config.php sets define( 'DISABLE_WP_CRON', true ); so WordPress does not spawn cron on page loads; the system cron is the only trigger.

Site-scoped (does not affect other sites on the host)

This cron setup is per-site only. The system cron and script hardcode the id86.net path, and DISABLE_WP_CRON lives in this site's own wp-config.php:

  • id86.net — server cron drives WP-Cron (DISABLE_WP_CRON = true).
  • balancesheet (/home/balancesheet/...) on the same host — untouched, still uses default page-load WP-Cron.

The BetterLinks plugin itself schedules its events with standard WP-Cron (wp_schedule_event(..., 'hourly', 'betterlinks/analytics')). The system cron merely ensures those events are fired reliably rather than depending on page loads (which LiteSpeed page caching skips).

Manual flush if ever needed:

sudo -u Dmg59ZFtKg6bIws1 -- wp --path=/home/Dmg59ZFtKg6bIws1/id86net/public_html \
cron event run betterlinks/analytics

LiteSpeed REST Cache Interaction

BetterLinks' admin UI reads categories/links via authenticated REST endpoints (/wp-json/betterlinks/v1/terms/categories, /terms/tags, /links). LiteSpeed's REST cache (cache-rest, default 7-day TTL) can cache those responses keyed to the logged-in cookie, so after adding a category it saves to the DB but the UI keeps serving the stale cached JSON — the category looks "gone" after refresh.

Both settings must stay off:

wp litespeed-option set cache-rest 0
wp litespeed-option set cache-page_login 0

If LiteSpeed is reactivated (e.g. for production), re-apply these two settings and purge (wp litespeed-purge all). They are stored in wp_options as litespeed.conf.cache-rest and litespeed.conf.cache-page_login.

Affiliate links on the Recommendations page (/recommendations/) exist in two places — a DB-only wp search-replace will miss the buttons:

  1. Theme shortcode (the "Visit X" buttons) — hardcoded in functions.php in the child theme: id86_recommendations_shortcode() builds $vps and $ai arrays with 'url' values. Edit → php -l./deploy.shwp flush-opcache flush.
  2. GeneratePress Elements (gp_elements post type) — CTA blocks that also render on the page. These live in id86net_posts.post_content and are edited via wp search-replace.

Current mapping (all point through BetterLinks short links):

ButtonOld affiliate URLNew short link
RackNerdhttps://my.racknerd.com/aff.php?aff=11459https://id86.net/link/racknerd
GreenCloudVPShttps://greencloudvps.com/billing/aff.php?aff=6685https://id86.net/link/greencloudvps
Onidelhttps://onidel.com/?referral=1567346https://id86.net/link/onidel
OpenCode Gohttps://opencode.ai/https://id86.net/link/opencode

OPcache Note

The wp flush-opcache flush WP-CLI command flushes the CLI SAPI (PHP 8.0), not the web worker (lsphp83/84). The web opcache is configured with validate_timestamps=1 and revalidate_freq=60, so a theme deploy is picked up within ~60s automatically. If a change must appear instantly, either wait ~60s or restart the relevant lsphp worker.

Update Safety

None of the above requires modifying BetterLinks plugin code. Everything lives in:

  • wp-config.php (DISABLE_WP_CRON)
  • LiteSpeed plugin settings (wp_options)
  • The child theme functions.php
  • System cron files (/etc/cron.d/, /usr/local/bin/)

Plugin updates therefore cannot break these changes.