Skip to content

A2 Hosting runbook — Phase 0 cleanup (executed 2026-04-24)

The play-by-play of the production cleanup on fruitplug.co.uk (A2 Hosting az1-ts106). Every step below was run via infra/a2/*.py tooling.

Environment snapshot

Value
Host az1-ts106.a2hosting.com
IP 106.0.62.69
SSH fruitplu@fruitplug.co.uk:7822
Home /home/fruitplu
WP path /home/fruitplu/public_html
WP 6.9.4
WC 10.7.0
PHP 7.4.33 (EOL — upgrade pending via cPanel)
MySQL 8.0.39
WP-CLI 2.12.0
Disk 7.0T total, 159G free (98% full)
public_html 1.6 GB

1. Backup ✅

Command: A2_PASSPHRASE=... python infra/a2/a2.py backup

Remote dir: /home/fruitplu/backups/pre-cleanup-20260424-205535/

Archive Size
db.sql 69 MB · 105 tables
wp-content-plugins.tar.gz 113 MB
wp-content-themes.tar.gz 33 MB
wp-content-mu-plugins.tar.gz 4 KB (empty — no mu-plugins)
wp-content-uploads.tar.gz 936 MB (stays on server)

Downloaded locally to backups/a2-20260424-205535/ (219 MB) except uploads. Retrieve uploads via python infra/a2/a2.py pull-uploads when needed.

2. Plugin cleanup ✅

Ran in 5 batches of 4 (+ final 2), smoke-testing the home page between each.

  • Batch 1: elementor, kingcomposer, unlimited-elements-for-elementor, apus-themer
  • Batch 2: mobile-menu-premium, loading-page, wp-multi-step-checkout, woo-checkout-field-editor-pro
  • Batch 3: xt-woo-ajax-add-to-cart, woo-variation-swatches, show-only-lowest-prices-in-woocommerce-variable-products, customize-my-account-for-woocommerce
  • Batch 4: google-site-kit, woocommerce-google-analytics-integration, meta-tag-manager, pdf-catalog-woocommerce-pro
  • Batch 5: cost-of-goods-for-woocommerce, printify-for-woocommerce

All 18 deactivated cleanly (home returned 200 after every batch), then wp plugin delete removed the files.

Active count: 38 → 20 plugins.

3. Revisions cleanup ✅

wp post delete $(wp post list --post_type=revision --format=ids) --force

Before: 578 revisions. After: 0.

4. HPOS migration ⏳ DEFERRED

Attempted wp option update woocommerce_custom_orders_table_enabled yes → Woo fatal error because orders in the old posts table aren't synced to the HPOS tables yet.

Proper flow requires the admin UI:

  1. Log in to wp-admin → WooCommerce → Settings → Advanced → Features
  2. Enable Order data storage: High-performance order storage (HPOS)this turns on sync in compatibility mode
  3. Wait until the order sync banner clears (4,188 orders; should take 10–30 min depending on server load)
  4. Set Compatibility mode off
  5. Verify with wp option get woocommerce_custom_orders_table_enabled → should return yes

5. Data fixes ✅

Categories rebalanced.

Before: - Uncategorized: 6 products (2 rare fruits, 1 box, 3 specials) - Signature Collection Box appeared in both Fruits and Fruit Plug Boxes

After: | Category | Count | |---|---| | Rare & Special (NEW) | 5 | | Fruit Plug Boxes | 4 | | Fruits | 24 | | Merchandise | 10 | | Subscription | 3 | | Uncategorized | 0 |

  • Created Rare & Special (term_id 149, slug rare-special) — Super Rare Cacao Pod, MANGO MADNESS, Soursop leaves, Jelly nut coconut, Super Rare Annona
  • Moved Guineps (Box) into Boxes (was Uncategorized)
  • Removed Signature Collection Box from the Fruits category (it's a box, not a fruit)
  • PWA /shop/rare-special goes live automatically via the Woo Store API

6. Fruit description rewrites ⏳ PENDING

Manual content work: 26 fruits × ~80 words each, consolidating from the existing Preparation Guide page. Can be done in wp-admin → Products → Quick Edit, or bulk via wp post update <id> --post_content="...".

7. PHP 7.4 → 8.2 upgrade ✅

Upgraded via cPanel → Account PHP Settings (global). On first switch the site 500'd because the default extension set on PHP 8.2 missed some WP-required extensions. Fix was ticking them in cPanel → Select PHP Version → Extensions:

Extension Status before After
mysqli unchecked ✅ ticked
sodium unchecked ✅ ticked
imagick unchecked ✅ ticked

Already-enabled extensions that WP needs and we confirmed present: mysqlnd, pdo_mysql, gd, curl, intl, mbstring, zip, openssl, xml, dom, json, bcmath, fileinfo.

Site restored to 200 on the next request.

8. fruitplug-api plugin install ✅

A2_PASSPHRASE=... python infra/a2/rsync_plugin.py
  • 14 files uploaded via SFTP to wp-content/plugins/fruitplug-api/
  • wp plugin activate fruitplug-api succeeded
  • Activation hook ran Migrations::activate() which created:
  • wp_fruitplug_points_ledger
  • wp_fruitplug_streaks
  • wp_fruitplug_passport
  • wp_fruitplug_saved_boxes
  • wp_fruitplug_referrals
  • wp_fruitplug_push_endpoints
  • wp_fruitplug_reel_products
  • Default seasonal calendar seeded in wp_options (fruitplug_seasonal_calendar)
  • REST health check at /wp-json/fruitplug/v1/health returns {"status":"ok", …}

Active plugin count: 21 (20 cleanup survivors + fruitplug-api)

8. Remaining active plugins (20)

Plugin Audit verdict
woocommerce keep (core)
woocommerce-payments keep (Stripe)
woocommerce-subscriptions keep (migration bridge)
woocommerce-shipstation-integration keep (fulfilment)
woocommerce-shipment-tracking keep
local-delivery-drivers-for-woocommerce keep
bp-custom-order-status-for-woocommerce keep (driver statuses)
customer-reviews-woocommerce keep (218 reviews)
woo-update-manager keep (commercial updater)
mailchimp-for-woocommerce keep (email)
google-listings-and-ads keep (Merchant Center)
facebook-for-woocommerce keep (Meta pixel)
tiktok-for-business keep (TikTok pixel)
redirection keep (URL redirects for migration)
jetpack-protect keep (security)
easy-hide-login keep (security)
wordpress-seo keep (user-confirmed)
cmb2 evaluate (check dependencies)
jetpack evaluate (remove unless Backup is used)
akismet evaluate (remove — we don't accept WP comments)

Commands for future ops

# Run anything as wp-cli on A2
PYTHONIOENCODING=utf-8 A2_PASSPHRASE=xxx python infra/a2/a2.py run 'wp <command>'

# e.g. check a specific order
python infra/a2/a2.py run 'wp wc shop_order get 5200 --format=json'

# Pull uploads tarball (900+ MB)
python infra/a2/a2.py pull-uploads