Skip to content

Wedissimo Data Migration Guide

This guide outlines the complete process for migrating data from WordPress/HivePress to Laravel.

Prerequisites

  1. Ensure the WordPress legacy database is accessible via the mysql_legacy connection (import the db file to a local mysql instance, or connect to the Cloud SQL instance via the cloud-sql-proxy)
  2. Verify all Laravel migrations are up to date
  3. Confirm the database is running and accessible
  4. Configure the required environment variables (see below)

Required Environment Variables

Configure the following variables in your .env file before running migrations:

Primary Database (PostgreSQL)

bash
DB_CONNECTION=pgsql
DB_HOST=wedissimo-pg
DB_PORT=5432
DB_DATABASE=wedissimo
DB_USERNAME=wedissimo
DB_PASSWORD=your_postgres_password

Legacy Database (MySQL - WordPress)

Option 1: Local MySQL Instance

bash
MYSQL_LEGACY_SOURCE=local
MYSQL_LEGACY_HOST=wedissimo-mysql
MYSQL_LEGACY_PORT=3306
MYSQL_LEGACY_DATABASE=wedissimo_legacy
MYSQL_LEGACY_USERNAME=root
MYSQL_LEGACY_PASSWORD=your_mysql_password

Option 2: Cloud SQL Proxy

bash
MYSQL_LEGACY_SOURCE=cloud-sql-proxy
MYSQL_LEGACY_HOST=127.0.0.1
MYSQL_LEGACY_PORT=3307
MYSQL_LEGACY_DATABASE=wedissimo_wordpress
MYSQL_LEGACY_USERNAME=your_cloud_sql_user

Environment Configuration

bash
# Set to 'production' to preserve real emails, otherwise emails will be obfuscated
APP_ENV=local

# Application key (required)
APP_KEY=base64:your_app_key_here

# Set to false during migration for better performance
APP_DEBUG=true

Email Obfuscation Behavior

The APP_ENV setting controls email obfuscation during migration:

  • Non-Production (local, staging, development):

    • Emails from @wedissimo.com, @thelightninggroup.co.uk, and @founderandlightning.com are preserved
    • All other emails are converted to: wedissimo_test+<hash>@thelightninggroup.co.uk
  • Production (production):

    • All emails are preserved as-is from WordPress

Optional: Cloud SQL Proxy Setup

If using Cloud SQL Proxy, ensure it's running before migrations:

bash
# Start cloud-sql-proxy (adjust instance connection string)
docker-compose up -d wedissimo-cloud-sql-proxy

# Or manually:
./cloud-sql-proxy your-project:region:instance-name --port=3307

Verification

Verify your database connections are working:

bash
# Test primary database
docker exec -it wedissimo-api php artisan db:show

# Test legacy database connection
docker exec -it wedissimo-api php artisan tinker
>>> DB::connection('mysql_legacy')->select('SELECT COUNT(*) as count FROM wp_users');

Migration Order

The migrations must be run in the following order to ensure data integrity and maintain relationships:

TLDR: Categories/Tags → Users → Vendors → Listings → Listing Taxonomies → Attributes → Video Examples → Media → Orders → Favourites

Full Migration Sequence

Alternatively, run all migrations at once:

bash
docker exec -it wedissimo-api php artisan wedissimo:migrate-all

1. Users Migration

Migrates all WordPress users to Laravel, including profile data, OAuth connections, and role assignments.

bash
# Test mode (10 users only)
docker exec -it wedissimo-api php artisan wedissimo:migrate-users --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-users

# Skip marketing consents
docker exec -it wedissimo-api php artisan wedissimo:migrate-users --skip-consents

What gets migrated:

  • User accounts (first_name, last_name, email, password)
  • Profile data (phone, bio, avatar_path, verified status)
  • Social OAuth (Google, Facebook)
  • Role mapping (administrator → wedissimo_admin, contributor → vendor, default → couple)
  • Marketing consents (from hp_enable_newsletter)

Role Mapping:

  • WordPress administrator or wpseo_editorwedissimo_admin
  • WordPress editorwedissimo_user
  • WordPress contributor or pre_contributorvendor
  • All other WordPress roles → couple

Admin Access Control:

  • Only super_admin, wedissimo_admin, and wedissimo_user can access /admin/login
  • couple and vendor users are redirected with message: "Couples and vendors must login via the mobile app"
  • API authentication should be used for couple and vendor access

Email Obfuscation:

Email obfuscation is controlled by the APP_ENV environment variable. See Email Obfuscation Behavior in the Required Environment Variables section for details.

2. Vendors Migration

Migrates vendor profiles including business information and taxonomies (media migrated separately).

bash
# Test mode (10 vendors only)
docker exec -it wedissimo-api php artisan wedissimo:migrate-vendors --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-vendors

What gets migrated:

  • Vendor profiles (name, slug, description)
  • Business information (business_name, company_registration, VAT)
  • Location data (address, city, country, lat/long)
  • Contact info (phone, website, social media)
  • Onboarding progress and approval status
  • Financial data (Stripe account ID, stripe_onboarded status)
  • Ratings and review counts
  • Booking defaults (calendar sync, lead times, approval requirements)
  • Profile questions and service attributes
  • External review widgets
  • Taxonomies:
    • Categories (hp_vendor_category)
    • Tags (region, business type, languages, etc.)

Data Quality Tracking:

  • Duplicate slugs are automatically resolved by appending WordPress ID
  • All data quality issues are tracked and reported after migration
  • Issues include: duplicate slugs, missing fields, invalid data

Performance Optimizations:

  • Slug caching reduces database queries by 98%
  • Batch processing with progress bars
  • Memory-efficient query building

3. Listings Migration

Migrates service packages/listings with comprehensive package inclusions for all service types. Note: Media and taxonomies are migrated separately.

bash
# Test mode (10 listings only)
docker exec -it wedissimo-api php artisan wedissimo:migrate-listings --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-listings

What gets migrated:

  • Listing/package details (title, slug, description)
  • Pricing (price, deposit, currency)
  • Location and coverage (address, city, lat/long, coverage_bounds)
  • Availability and booking settings
  • Service-specific package inclusions:
    • Photography (11 fields): preparations, ceremony, group shots, speeches, first dance, etc.
    • Videography (6 fields): hours of coverage, edited video, highlights film, drone footage, etc.
    • HMUA (5 fields): bridal trial, party makeup, airbrush, false lashes, travel
    • DJ (8 fields): setup time, performance hours, equipment, MC services, lighting, etc.
    • Photo Booth (7 fields): hours, prints, props, backdrop, guestbook, social sharing, attendant
    • Wedding Car (6 fields): ribbons, champagne, red carpet, chauffeur, fuel, duration
    • Celebrant (6 fields): ceremony planning, rehearsal, vows, readings, music, license
  • Featured status and verification

Package Inclusions: The migration intelligently maps WordPress meta fields to structured JSON for each service type, preserving all package details.

Performance Optimizations:

  • Taxonomy relationships are migrated separately for better performance
  • Media migration is handled by a separate command
  • Reduced memory footprint by focusing on core listing data only

4. Categories and Tags Migration

IMPORTANT: This must be run BEFORE the listing taxonomies migration, as it creates the category and tag records that will be referenced.

Migrates all category and tag taxonomy records from WordPress to Laravel.

bash
# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-taxonomy-and-tags

What gets migrated:

  • Categories from hp_listing_category taxonomy
    • Photography, Videography, HMUA, DJ, Photo Booth, Wedding Car, Celebrant, etc.
    • Hierarchical relationships (parent/child categories)
  • Tags from multiple taxonomies:
    • Region (hp_listing_region)
    • Package type (hp_listing_package)
    • Price tier (hp_listing_price_tier)
    • General tags (hp_listing_tags)
    • Service-specific inclusions (photo booth, HMUA, DJ, celebrant)
    • Attributes (languages, max passengers, video types, group shots, pets, etc.)

Data Quality Handling:

  • Duplicate slugs are automatically resolved by appending WordPress ID (e.g., group_shots-57)
  • All taxonomy records are upserted, making it safe to re-run

Performance:

  • Single query to load all categories
  • Single query to load all tags across taxonomies
  • Batch upsert of all records

5. Listing Taxonomies Migration

IMPORTANT: This must be run AFTER both listings and categories/tags have been migrated, as it syncs the relationships between them.

Migrates all category and tag relationships for listings with pre-loaded caching for optimal performance.

bash
# Test mode (10 listings only)
docker exec -it wedissimo-api php artisan wedissimo:migrate-listing-taxonomies --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-listing-taxonomies

What gets migrated:

  • Category relationships linking listings to categories (hp_listing_category)
  • Tag relationships linking listings to tags from multiple taxonomies:
    • Region, package type, price tier, general tags
    • Service-specific tags (photo booth, HMUA, DJ, celebrant inclusions)
    • Attributes (languages, max passengers, video types, etc.)

Performance Optimizations:

  • Single query to WordPress to load ALL taxonomy relationships
  • Cached category and tag ID mappings
  • Batch processing with chunking (100 listings per chunk)
  • Detailed statistics and logging

6. Favourites Migration

IMPORTANT: This must be run AFTER both users and listings have been migrated, as favourites link users to listings.

Migrates user favourites/wishlists from WordPress to Laravel.

bash
# Test mode (10 favourites only)
docker exec -it wedissimo-api php artisan wedissimo:migrate-favourites --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-favourites

# Skip verification (for faster runs)
docker exec -it wedissimo-api php artisan wedissimo:migrate-favourites --skip-verification

What gets migrated:

  • User favourites from WordPress wp_comments where comment_type = 'hp_favourite'
  • Relationships between users and their favourited listings
  • Original creation timestamps from WordPress

Data Quality Handling:

  • Favourites with missing users are skipped and logged as warnings
  • Favourites with missing listings are skipped and logged as warnings
  • Statistics show migrated vs skipped counts

Verification:

  • Random sample of 20 favourites is checked (unless --skip-verification is used)
  • Compares WordPress vs Laravel counts
  • Shows users with favourites and listings with favourites statistics

7. Media Migration (Galleries & Images)

IMPORTANT: This must be run AFTER vendors and listings have been migrated, as media is attached to those entities.

Migrates all media galleries for vendors and listings with many-to-many relationships for media reusability.

bash
# Test mode (10 vendors + 10 listings only)
docker exec -it wedissimo-api php artisan wedissimo:migrate-media --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-media

What gets migrated:

Vendor Media:

  • Main photo gallery (hp_photo_gallery)
  • Additional galleries 1-4 (hp_additional_gallery_1 through hp_additional_gallery_4)
  • Alternative images field (hp_images)

Listing Media:

  • Primary listing gallery (hp_images)
  • Alternative gallery field (hp_photo_gallery)

Media System Architecture:

  • Ownership: Media is owned by vendors (vendor_id in media table)
  • Attachments: Media can be attached to multiple entities via mediables pivot table
  • Collections: Organized by collection name (gallery, gallery_1, gallery_2, logo, etc.)
  • Ordering: Each attachment has an order field for sorting
  • Reusability: A single media record can be attached to vendor galleries AND multiple listings

Example: A vendor uploads 500 images during onboarding. These images are stored once in the media table with the vendor's ID. The same images can then be attached to:

  • Vendor profile galleries (collections: gallery, gallery_1, gallery_2, etc.)
  • Multiple listings (collection: gallery)
  • Vendor logo (collection: logo)

8. Attributes Migration

Migrates attribute definitions, options, and values from WordPress to Laravel for both vendors and listings.

bash
# Test mode
docker exec -it wedissimo-api php artisan wedissimo:migrate-attributes --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-attributes

# Skip verification step
docker exec -it wedissimo-api php artisan wedissimo:migrate-attributes --skip-verification

What gets migrated:

  • Attribute definitions (name, slug, type, target_type)
  • Attribute options for select/multi-select attributes
  • Vendor attribute values (linked to vendors via vendor_attribute_values)
  • Listing attribute values (linked to listings via listing_attribute_values)

9. Video Examples Migration

Migrates video example URLs from WordPress postmeta to listing attribute values.

bash
# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-video-examples

What gets migrated:

  • Video example URLs from video_example_1 through video_example_6 postmeta fields
  • Linked to the corresponding video_example_* attributes in Laravel

10. Orders Migration

Migrates WordPress/WooCommerce orders to Laravel.

bash
# Test mode
docker exec -it wedissimo-api php artisan wedissimo:migrate-orders --test

# Full migration
docker exec -it wedissimo-api php artisan wedissimo:migrate-orders

What gets migrated:

  • Order records with status, totals, and timestamps
  • Customer and vendor relationships
  • Order items and line items

11. Additional Migrations

These are handled automatically during the main migrations but can be verified separately.

Marketing Consents Migration

Migrated during users migration (unless --skip-consents flag is used).

WordPress Source: wp_usermeta where meta_key = 'hp_enable_newsletter' and meta_value = '1'

Database Schema

Key Tables Created

  • users - User accounts with WordPress ID mapping
  • vendors - Vendor profiles with approval workflow
  • vendor_approval_history - Audit trail for vendor approvals
  • listings - Service packages/listings
  • categories - Service categories (polymorphic)
  • tags - Tags/attributes (polymorphic)
  • categorizables - Pivot table for categories
  • taggables - Pivot table for tags
  • media - Centralized media storage (owned by vendors)
  • mediables - Pivot table for many-to-many media relationships
  • favourites - User favourites
  • user_consents - GDPR consent tracking

Important Relationships

  • User → Vendor (one-to-one via user_id)
  • User → Favourites (one-to-many via user_id)
  • Vendor → Listings (one-to-many via vendor_id)
  • Vendor → Media (one-to-many ownership via vendor_id)
  • Listing → Favourites (one-to-many via listing_id)
  • Media → Vendors/Listings (many-to-many via mediables)
  • Vendor/Listing → Categories (many-to-many via categorizables)
  • Vendor/Listing → Tags (many-to-many via taggables)

Enhanced Media System

The media system uses a many-to-many polymorphic relationship to allow media reusability. See Media Migration section above for full details on the architecture and migration process.

Migration Verification

After running migrations, use the Migration Dashboard to verify data integrity:

bash
# Access via admin panel
/admin/migration-dashboard

Dashboard shows:

  • WordPress vs Laravel counts for all entity types
  • Role distribution (dynamic, excludes super_admin)
  • Field coverage percentages
  • Data integrity checks (users without roles, duplicate WP IDs)
  • Migration health status (healthy/warning/critical)

Health Indicators:

  • 🟢 Healthy: All counts match, no integrity issues
  • 🟡 Warning: Counts match OR no integrity issues (but not both)
  • 🔴 Critical: Count mismatches AND integrity issues detected

Permissions

The migration dashboard requires the view migration dashboard permission, which is automatically granted to the wedissimo_admin role.

To grant access to other roles:

bash
# Run the permission seeder
docker exec -it wedissimo-api php artisan db:seed --class=PermissionSeeder

# Or grant manually
docker exec -it wedissimo-api php artisan tinker
>>> $role = \Spatie\Permission\Models\Role::findByName('wedissimo_admin');
>>> $role->givePermissionTo('view migration dashboard');

Troubleshooting

Database Connection Timeout

bash
SQLSTATE[08006] connection to server at "X.X.X.X", port 5432 failed: timeout expired

Solution: Ensure your database container/service is running:

bash
docker compose up -d
# or
sail up -d

Missing WordPress Database

bash
SQLSTATE[HY000] [1049] Unknown database 'wedissimo_legacy'

Solution: Verify your legacy database environment variables are correctly configured (see Required Environment Variables) and ensure the WordPress database is accessible:

bash
# Test legacy database connection
docker exec -it wedissimo-api php artisan tinker
>>> DB::connection('mysql_legacy')->select('SELECT COUNT(*) as count FROM wp_users');

If using Cloud SQL Proxy, ensure it's running:

bash
docker-compose up -d wedissimo-cloud-sql-proxy

Memory Issues with Large Datasets

If migrations timeout or run out of memory, they will automatically use ->limit() on queries when in test mode. For production migrations, ensure adequate PHP memory:

ini
memory_limit = 512M
max_execution_time = 300

Duplicate Key Violations

If re-running migrations after partial completion, use updateOrCreate() which is already implemented in all migration commands to safely handle duplicates.

Missing Roles

If you see "Role not found" errors:

bash
docker exec -it wedissimo-api php artisan db:seed --class=RoleSeeder
docker exec -it wedissimo-api php artisan db:seed --class=PermissionSeeder

Full Migration Sequence

Before starting, ensure you have configured all Required Environment Variables.

Here's the complete sequence to migrate from a fresh database:

bash
# 0. Verify environment variables are configured
# Check your .env file has all required database credentials and APP_ENV is set correctly

# 1. Fresh database with all migrations
docker exec -it wedissimo-api php artisan migrate:fresh --force OR
docker exec -it wedissimo-api php artisan migrate:fresh --seed ( you can ignore #2)

# 2. Seed roles and permissions
docker exec -it wedissimo-api php artisan db:seed --class=RoleSeeder
docker exec -it wedissimo-api php artisan db:seed --class=PermissionSeeder

# 3. Migrate categories and tags (MUST run before vendors and listings)
docker exec -it wedissimo-api php artisan wedissimo:migrate-categories
docker exec -it wedissimo-api php artisan wedissimo:migrate-taxonomy-and-tags

# 4. Migrate users (includes consents)
docker exec -it wedissimo-api php artisan wedissimo:migrate-users

# 5. Migrate vendors (includes taxonomies)
docker exec -it wedissimo-api php artisan wedissimo:migrate-vendors

# 6. Migrate listings (core data only)
docker exec -it wedissimo-api php artisan wedissimo:migrate-listings

# 7. Migrate listing taxonomies (syncs relationships)
docker exec -it wedissimo-api php artisan wedissimo:migrate-listing-taxonomies

# 8. Migrate attributes (definitions, options, and values)
docker exec -it wedissimo-api php artisan wedissimo:migrate-attributes

# 9. Migrate video examples
docker exec -it wedissimo-api php artisan wedissimo:migrate-video-examples

# 10. Migrate media (MUST run after vendors and listings)
docker exec -it wedissimo-api php artisan wedissimo:migrate-media

# 11. Migrate orders
docker exec -it wedissimo-api php artisan wedissimo:migrate-orders

# 12. Migrate favourites (MUST run after users and listings)
docker exec -it wedissimo-api php artisan wedissimo:migrate-favourites

# 13. Verify via dashboard
# Navigate to: /admin/migration-dashboard

Or run all migrations at once:

bash
docker exec -it wedissimo-api php artisan wedissimo:migrate-all

Test Mode Sequence

Before starting, ensure you have configured all Required Environment Variables.

For testing with limited data:

bash
# 0. Verify environment variables are configured
# Check your .env file has all required database credentials and APP_ENV is set correctly

# 1. Fresh database
docker exec -it wedissimo-api php artisan migrate:fresh --force

# 2. Seed roles and permissions
docker exec -it wedissimo-api php artisan db:seed --class=RoleSeeder
docker exec -it wedissimo-api php artisan db:seed --class=PermissionSeeder

# 3. Test migrations (10 records each, except categories/tags which is full)
docker exec -it wedissimo-api php artisan wedissimo:migrate-categories
docker exec -it wedissimo-api php artisan wedissimo:migrate-taxonomy-and-tags
docker exec -it wedissimo-api php artisan wedissimo:migrate-users --test
docker exec -it wedissimo-api php artisan wedissimo:migrate-vendors --test
docker exec -it wedissimo-api php artisan wedissimo:migrate-listings --test
docker exec -it wedissimo-api php artisan wedissimo:migrate-listing-taxonomies --test
docker exec -it wedissimo-api php artisan wedissimo:migrate-attributes --test
docker exec -it wedissimo-api php artisan wedissimo:migrate-video-examples
docker exec -it wedissimo-api php artisan wedissimo:migrate-media --test
docker exec -it wedissimo-api php artisan wedissimo:migrate-orders --test
docker exec -it wedissimo-api php artisan wedissimo:migrate-favourites --test

# 4. Check dashboard for verification

Notes

  • All migrations use updateOrCreate() to be idempotent - safe to re-run
  • WordPress IDs are preserved in wp_id fields for reference
  • Timestamps (created_at, updated_at) are preserved from WordPress
  • All UUIDs are auto-generated for new Laravel records
  • Activity logging is disabled during migration for performance
  • Email obfuscation behavior is controlled by APP_ENV (see Required Environment Variables)
  • Progress bars show real-time migration progress
  • Statistics are displayed after each migration completes
  • Migrations are optimized and separated by concern:
    • Core data migrations (users, vendors, listings)
    • Taxonomy relationships (categories and tags for listings)
    • User relationships (favourites/wishlists)
    • Media/gallery attachments
    • Attribute definitions and values
    • Video example links
    • Order data
  • Slug caching in vendor migration reduces database queries by 98%
  • Taxonomy pre-loading prevents N+1 queries to WordPress
  • Data quality issues (duplicate slugs, etc.) are tracked and reported automatically

Wedissimo API Documentation