Skip to content

feat: show the hosting Reseller's brand instead of FlyWP (White Label) - #30

Draft
shohag121 wants to merge 4 commits into
developfrom
feat/white-label-brand
Draft

shohag121 wants to merge 4 commits into
developfrom
feat/white-label-brand

Conversation

@shohag121

@shohag121 shohag121 commented Sep 28, 2026 •

Copy link
Copy Markdown

Summary

On a FlyWP White Label customer's site, the plugin shows the hosting Reseller's brand instead of "FlyWP" (flywp/flywp-app#2600).

  • Contract: the control plane writes one constant, FLYWP_BRAND (the hex of {name, url, icon} JSON). It goes in wp-config.php, or in the .env on Bedrock (getenv(), then $_ENV/$_SERVER).
  • No brand, no change: a value that does not decode to a name is no brand. The plugin then shows FlyWP exactly as today.
  • No address yet: url is null until the Reseller confirms an address. The brand's name shows, with no dashboard button and no SMTP link.
  • Why hex: it is letters and digits only, so the control plane writes it with no escaping.

Where the brand shows

  • Plugins list: name, author, URLs and description. "View details" is removed.
  • Admin bar: the brand's icon, or none. Never FlyWP's logo.
  • Settings page:
    • The menu and page title, and the header.
    • The dashboard button goes to {Reseller address}/site/{id}, the page where the customer signs in.
  • Email tab: its text and the SMTP link.
  • Test email: subject, body and template. FlyWP's company address is removed under a brand.
  • Missing-key notice.
  • Plugin rows sent to the dashboard: /fly-api/plugins and the updates data.
  • Core's plugin update email: the line is rebuilt from core's own item and translated format. It works in any language and never renames another plugin.
  • Site Health → Info.

Not changed, on purpose:

  • the folder, the ?page=flywp slug, /fly-api/* and /flywp-magic-login;
  • the option and constant names;
  • the wp.org listing.

Testing

  • BrandTest:
    • The fixed vector (the control plane's tests assert the same one).
    • Decoding of bad input.
    • URL rules, and a brand with no https URL (no dashboard link).
    • The plugin row.
    • The email template: without a brand it matches the 1.7.1 template byte for byte.
    • Site Health.
  • BrandingTest: the four hooks, with a few WordPress stand-ins. No hook is added without a brand.
  • PHPUnit: 65 tests, 198 assertions. The changed files are clean under PHPCS.
  • Local WordPress 7.1 in Chrome:
    • With a brand: the Plugins list, admin bar, settings page, Email tab and Site Health.
    • Without a brand: identical to today.
    • With a hostile name (<script>…): it found a stored XSS in the admin menu title, fixed here (escaped, and tags stripped on decode).

Known limits

  • While an update waits, the Plugins list's update row still links "View version … details" to FlyWP's wp.org page.
  • A deactivated plugin, the REST plugins list and the plugin editor show "FlyWP".
  • Four translatable strings now take the name as %s. Existing translations show English there until they are updated.
  • Under a brand with no address yet, the logo at the top of the test email links nowhere (href="").
  • The update email for the release that brings the brand says "FlyWP" once: core sends it from the request that ran the update, where the old version is loaded.

Release

Before release: flywp.php is still 1.7.1. Follow RELEASE.md:

  1. bin/bump-version.sh <next version>.
  2. Add the changelog entry in readme.txt.
  3. Run yarn build, which also regenerates languages/flywp.pot for the four changed strings.
  4. Tag.

Release this to wp.org first. Sites get it by auto-update, and with no FLYWP_BRAND nothing changes. The app then writes the brand: flywp/flywp-app#2662.

🤖 Generated with Claude Code

shohag121 and others added 3 commits September 28, 2026 03:20
…-app#2600)

- The control plane writes `FLYWP_BRAND` (the hex of `{name, url, icon}` JSON) on a White Label
  customer's site. `flywp()->brand()` reads it, then `getenv()` for Bedrock. Anything that does
  not decode is no brand: the plugin shows FlyWP exactly as before.
- Under a brand: the Plugins list row (name, author, URLs, description, no "View details"), the
  admin bar, the settings page title, header and dashboard button (to the Reseller's address),
  the email tab, the test email and its template (no FlyWP address), the missing-key notice, the
  plugin rows sent to the dashboard, core's plugin update email, and Site Health.
- `BrandTest` pins the format with a fixed vector the control plane's tests also assert.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JmBiWG77NN53V6SmxtHdtm
… strip tags on decode

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JmBiWG77NN53V6SmxtHdtm
…r URLs, today's defaults kept

- The update email: rebuilt from core's own item and translated format, so this plugin's line
  is found in any language, and a plugin named "FlyWP …" is left alone.
- A brand URL needs a host and takes no query or fragment; no URL ends in a newline.
- Without a brand, `dashboard_url( 0 )` names site 0 as before, and the test email matches the
  1.7.1 template byte for byte (a fixture).
- Site Health keeps the entry in its place. Hex is checked with a regex (no ext-ctype). Bedrock
  also reads `$_ENV` / `$_SERVER`.
- `BrandingTest` covers the four hooks, with a few WordPress stand-ins.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JmBiWG77NN53V6SmxtHdtm
@shohag121 shohag121 self-assigned this Sep 28, 2026
- The control plane sends `url` as null until the reseller confirms an address.
- `Brand::decode()` needs a name only; a missing or bad URL gives `url()` and
  `dashboard_url()` as ''.
- The settings page hides the dashboard button and the SMTP link then.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JmBiWG77NN53V6SmxtHdtm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant