=== DWD Plugins Hub ===
Contributors: dwd
Tags: plugins, admin, updates
Requires at least: 6.2
Tested up to: 6.9
Requires PHP: 7.4
Stable tag: 1.3.81
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Shared **DWD Plugins** admin menu, installed-product dashboard, and private update catalog for Diz Web Design products.

== Description ==

This plugin is distributed privately for Diz Web Design client sites. It is not intended for the WordPress.org plugin directory.

== Plugin Check (Tools → Plugin Check) ==

Plugin Check is built into WordPress for **wordpress.org** listing rules. You cannot turn off individual checks from this plugin. When developing DWD Plugins Hub, **ignore** findings that only apply to org distribution:

* **Custom updater** in `includes/class-dwd-plugins-hub-remote.php` — Required for DWD products on client sites. The hub merges into WordPress’s normal `update_plugins` transient and **does not replace** updates whose package URL is on `wordpress.org`.
* **Trademark “plugin” in the name/slug** — Org branding only; safe to ignore privately.

Do not upload dotfiles (e.g. `.distignore`, `.plugin-check.json`) into the plugin folder — Plugin Check reports them as hidden files. Remove any that FTP left behind.

== Installation ==

1. Upload the plugin folder to `wp-content/plugins/dwd-plugins-hub/`.
2. Activate through the Plugins screen.
3. Open **DWD Plugins → Plugins Hub** in wp-admin.

== Changelog ==

= 1.3.81 =
* Fix DWD Tracker fly-out: do not hijack an existing top-level menu slug (that caused a redirect loop). Register Tracker in the product map and stop the Hub bridge from redirecting to itself.

= 1.3.80 =
* Multisite: network activation and uninstall loop per-site options/caps (`run_for_sites`, `wp_initialize_site`); network admin UI unchanged.

= 1.3.79 =
* Register **Open Records Registry** in the Hub fly-out product map (`orr-registry` → **Open Records**) so the Hub does not auto-guess a duplicate **Open Records Registry** row.

= 1.3.78 =
* Security: ignore unsigned heartbeat site_token updates.

= 1.3.77 =
* Performance: cache public update manifest REST responses (15 min TTL; ?refresh=1 bypass).

= 1.3.76 =
* Security: ignore unsigned remote wipe banned/blocked; wipe only via verified signed commands.

= 1.3.75 =
* Fix Plugins → Update “No valid plugins were found” caused by stripping the trailing slash from the unpacked package path (WordPress check_package requires it).

= 1.3.74 =
* After Install update, flush product DB/pages sync via a blocking admin-ajax loopback so migrations run with fresh PHP before the Installed redirect (no separate Run update for typical upgrades).

= 1.3.73 =
* Allow Install update for the Plugins Hub itself. Incomplete catalog ZIPs are still rejected by package validation before files are replaced.

= 1.3.72 =
* After Install update, queue product DB/pages sync for the next request so migrations run with freshly loaded plugin code (not stale in-memory classes).

= 1.3.71 =
* Fix Plugins → Update for the hub and other DWD plugins when pre-update rollback backup fails (backup is best-effort; hub self-update skips rollback).

= 1.3.70 =
* NCMEC Posters: canonical plugin file mapping, admin screen bridges (settings, front page, backup, tools), and fly-out compatibility.

= 1.3.69 =
* Fix WP 6.7 early textdomain notices: product registry stores English strings and translates at admin_menu; load textdomain on init. Strip UTF-8 BOM from product-menus. Defer queued post-update sync until init (avoid scrape loopback fatals). Register dwd-gallery fly-out alias.

= 1.3.68 =
* Fix DWD plugin package source selection so hub updates apply.

= 1.3.66 =
* Fly-out product links are listed A–Z. Leading “DWD ” is stripped from fly-out labels (DWD stays in the plugin name / identification only).

= 1.3.65 =
* **Added:** Automatic background updates for installed DWD plugins (Diagnostics → Plugin updates). Enabled by default; the Plugins Hub itself is excluded. Post-update migrations and page sync still run on the next load.

= 1.3.64 =
* After Hub or WordPress Plugins-screen updates, run data sync (migrations + required pages) on the next load for all DWD products. No per-plugin Run update click.

= 1.3.63 =
* **Fix:** Infinite recursion after Hub update — catalog/heartbeat headers listed installed plugins via update resolution, which fetched the catalog again.

= 1.3.62 =
* Remote client: wrap shared functions in `function_exists` so multiple DWD plugins can load without a redeclare fatal.

= 1.3.61 =
* Do not run remote heartbeat or Hub-required wp_die during plugin updates (fixes Hub/WordPress update critical errors).

= 1.3.60 =
* Remote uninstall client, signed Tracker commands, Hub required for other DWD products.

= 1.3.59 =
* Report site URL and installed DWD plugins when fetching the update catalog (DWD Tracker on dizwebdesign.com). HTTP 403 means catalog/updates are blocked for this site.

= 1.3.58 =
* **Added:** DWD Email — Installed-tab maintenance sync, post–Install update migrations/page sync, workspace allowlist, and Email fly-out.

= 1.3.57 =
* **Fix:** Newsletter fly-out uses hub-visible capability (`manage_options` → hub menu cap) so it appears under **DWD Plugins**.

= 1.3.56 =
* **Added:** DWD Newsletter — workspace allowlist and fly-out menu (`dwdn-dashboard` / `manage_newsletter`).

= 1.3.55 =
* **Added:** Appleseed Live — workspace allowlist, fly-out menu, manifest title map, and maintenance sync (`asl_run_upgrade`).

= 1.3.54 =
* **Added:** Factory reset — choose which installed DWD products to reinstall (checkboxes, Select all / Select none); default is all selected.

= 1.3.53 =
* **Added:** Diagnostics → **Factory reset (files only)** — reinstall all installed DWD products from the dizwebdesign.com catalog ZIP; restores missing files; does not run database migrations or page sync. Plugins Hub itself is excluded.

= 1.3.52 =
* **Fix:** DWD plugin update notices on **Plugins** again — merge developer-site updates when WordPress reads the cached `update_plugins` transient (`site_transient_update_plugins`), not only when the transient is rebuilt.

= 1.3.51 =
* **Fix:** Hub **Install update** / catalog install now grants `install_plugins` and `update_plugins` to hub administrators (WordPress upgrader was blocking them).
* **Fix:** Multisite — `map_meta_cap` allows hub operators and site admins to install/update DWD packages on subsites (when `DISALLOW_FILE_MODS` is off); network admin menu and network-aware admin-post URLs.
* **Fix:** Upgrader initializes WP_Filesystem before package install/update; falls back to direct ZIP install when the update transient path fails; preserves network activation after upgrade.

= 1.3.50 =
* **Fix:** **Available from Diz Web Design** lists only plugins not yet installed; file updates for installed products appear on **Installed** only.
* **Fix:** Installed tab remote updates use the live DWD Downloads catalog when it is newer than the cached manifest (fixes missing updates on dizwebdesign.com).
* **Fix:** Hub administrators without `update_plugins` can see and run **Install update** on the Installed tab (same as maintenance sync).

= 1.3.49 =
* **Fix:** Community Registry **Run update** from Installed passes `cr_return=hub` so DB sync returns to the hub after success.

= 1.3.48 =
* **Fix:** DWD Facebook Pages maintenance registry no longer references plugin classes at load time.

= 1.3.47 =
* **Added:** DWD Facebook Pages catalog product — fly-out menu, hub bridge dashboard, Installed tab maintenance sync.

= 1.3.46 =
* **Fix:** Base plugin dashboard opens under DWD Plugins (correct fly-out slug `base-pluggin`, bridge renders dashboard/tools, hub-only admins allowed on bridge pages).

= 1.3.35 =
* **Fix:** Installed tab activate / deactivate / delete works for hub administrators (`manage_dwd_plugins_hub`), not only when `dwd_plugins_hub_parent_capability()` (`manage_options`) passes separately.

= 1.3.34 =
* **Fix:** Installed tab shows file version when the database has no recorded version yet (Profiles, RSSAgg, and other maintenance-registry products).
* **Fix:** **Run update** maintenance link visible to hub administrators (`manage_dwd_plugins_hub`), not only `manage_options`.
* **Fix:** Manual-upload sync still offered when a remote update offer is filtered out.
* **Fix:** Inactive plugins show “Activate first, then run update” instead of a broken sync link.

= 1.3.33 =
* **Fix:** Critical error on wp-admin after 1.3.32 (maintenance update row called a private method).

= 1.3.32 =
* **Installed tab:** Version column shows the **recorded** (database) version until you run **Run update** after a manual upload; uploaded file version appears under **Update available** with “Manual upload — run sync” (Utilities, Downloads, RSSAgg, SocialAutoShare, Profiles, Community Registry, and filter `dwd_plugins_hub_maintenance_registry`).

= 1.3.31 =
* Utilities bridge: open **Tools** (not overview Dashboard) for `utilities-dashboard` and `utilities-tools`.

= 1.3.30 =
* Fly-out: restore `manage_dwd_plugins_hub` on submenus for `manage_options` products so hub admins see SocialAutoShare, RSSAgg, Profiles (pages must allow hub cap).

= 1.3.29 =
* Diagnostics: Run update / sync UI matches DWD Downloads (version + DB schema table, UPDATE button when pending).

= 1.3.28 =
* Fly-out menu: stop matching every product to Project Manager slugs (fixes missing Profiles, RSSAgg, SocialAutoShare links). Registry: Community Registry.

= 1.3.27 =
* Removed `.distignore` from plugin package (Plugin Check treats dotfiles as hidden). ZIP build skips dotfiles. Fixed manifest SQL for Plugin Check.

= 1.3.26 =
* Updater: merge at priority 99 on `pre_set_site_transient_update_plugins` and `site_transient_update_plugins`; skip plugins with wordpress.org packages; respect existing `plugins_api` results; no full transient wipe after upgrade.
* Plugin Check: removed `.plugin-check.json`; fixed `%i` SQL inline prepare; DB column cache.

= 1.3.25 =
* Document intentional private updater for Plugin Check; diagnostics notice; expanded `.plugin-check.json` ignore codes.

= 1.3.24 =
* Plugin Check: remove phpcs.xml.dist from package; `%i` table queries; information_schema column check; object cache; `.plugin-check.json` for private updater.

= 1.3.23 =
* Plugin Check / handbook: sanitized admin query args, output escaping, DB table validation, WP_Filesystem for rollback cleanup, readme.txt.
