Public preview Live on WordPress.org. Founding-customer pricing on Pro. See Founding Pricing →
migro.dev / developers

Migro Developer Reference

Hooks, filters, actions, and AJAX endpoints for extending Migro in your WordPress theme or custom plugin.

v2.4 Requires write access to theme or a custom plugin

Code-level access required

All hooks on this page require write access to a WordPress theme's functions.php or a custom plugin. They cannot be triggered from the browser or wp-admin UI.

Filters

Filters let you intercept and modify data during runtime configuration or onboarding.

filters
// Add or remove supported post types
add_filter( 'migro_supported_post_types', function( $post_types ) {
    $post_types[] = 'my_custom_type';
    return $post_types;
});

// Override which migration engine class is used
add_filter( 'migro_migration_engine_class', function( $class ) {
    return 'My_Custom_Engine';
});

// Disable SSL verification (local development only)
add_filter( 'migro_ssl_verify', '__return_false' );

// Change the admin menu title
add_filter( 'migro_admin_menu_title', function() {
    return 'Deploy Content';
});

// Modify the features list shown in the UI
add_filter( 'migro_migration_features', function( $features ) {
    $features[] = 'my_feature';
    return $features;
});

// Hide or show the Beta promo banner in the Free tier
add_filter( 'migro_show_beta_banner', '__return_false' );

// Modify the steps in the Setup Onboarding Wizard
add_filter( 'migro_setup_wizard_steps', function( $steps ) {
    $steps[] = array(
        'id' => 'custom_settings',
        'title' => 'Custom Settings'
    );
    return $steps;
});

// Filter the remote plugin status code during onboarding health checks
add_filter( 'migro_remote_plugin_status', function( $status, $connection ) {
    if ( $connection['site_url'] === 'https://trusted-site.local' ) {
        return 'active';
    }
    return $status;
}, 10, 2 );

Actions

Actions trigger custom callbacks during migration executions, UI rendering, or background cron updates.

actions
// Inject custom navigation tabs into the Migro Admin Panel
add_action( 'migro_admin_nav_tabs', function( $active_tab ) {
    $class = ($active_tab === 'custom_tab') ? 'nav-tab-active' : '';
    echo '<a href="?page=migro-content-migrator&tab=custom_tab" class="nav-tab ' . $class . '">Custom Tool</a>';
});

// Render the panel view for your custom navigation tab
add_action( 'migro_admin_tab_panels', function( $active_tab ) {
    if ( $active_tab === 'custom_tab' ) {
        echo '<div class="migro-panel"><h2>Custom Admin panel</h2></div>';
    }
});

// Runs after the plugin activates
add_action( 'migro_plugin_activation', function( $plugin_basename ) {
    // Perform custom database creation or logging
});

// Runs after the plugin deactivates
add_action( 'migro_plugin_deactivation', function() {
    // Perform custom cleanup
});

// Register additional classes or extensions
add_action( 'migro_load_extensions', function( $plugin ) {
    // register your custom migrator extension
});

// Triggered when a batch of content items completes migration
add_action( 'migro_migration_batch_complete', function( $batch_results, $direction, $connection ) {
    // Notify Slack, Teams, or log to system files
}, 10, 3 );

// Triggered when a scheduled background migration finishes running
add_action( 'migro_schedule_run_complete', function( $schedule_id, $stats, $success ) {
    // Handle scheduled run telemetry or send emails
}, 10, 3 );

// Triggered before a migration starts to register custom schemas on destinations
add_action( 'migro_pre_migration_register_cpts', function( $post_types, $connection ) {
    // Register custom CPT parameters remotely
}, 10, 2 );

// Fired after a local post (and its ACF/Yoast metadata) is synced via pull
add_action( 'migro_after_post_migrate_local', function( $result, $result_id, $remote_post, $remote_meta, $connection, $pdo, $options ) {
    // Update local post flags or custom third-party options
}, 10, 7 );

// Fired after a local post's images and attachments are successfully resolved and downloaded
add_action( 'migro_after_image_migrate_local', function( $result, $final_content, $result_id, $remote_post_id, $connection, $options ) {
    // Inject custom path parameters or update custom page builder hooks
}, 10, 6 );

// Fired after a remote post (and its ACF/Yoast metadata) is pushed
add_action( 'migro_after_post_migrate_remote', function( $result, $local_post_id, $remote_post_id, $local_meta, $connection, $pdo, $options ) {
    // Execute custom SQL on remote server
}, 10, 7 );

// Fired after a remote post's images and attachments are resolved and stored on target server
add_action( 'migro_after_image_migrate_remote', function( $result, $final_content, $local_post_id, $remote_post_id, $connection, $pdo, $prefix, $options ) {
    // Execute remote attachment post-processing
}, 10, 8 );

// Add scripts or styles to the setup wizard header
add_action( 'migro_setup_wizard_head_scripts', function() {
    echo '<style>.migro-setup-card { border-top-color: var(--teal-600); }</style>';
});

// Add steps to the setup wizard
add_action( 'migro_setup_wizard_after_welcome', function( $step ) {
    // render additional wizard content
});

AI Extension Points v2.4+

Hook into AI Enhancements without modifying core. Use the mock filters during testing to avoid real provider calls; use the readiness filter to force-disable AI on a particular site (e.g. staging clones).

ai filters
// Force-disable AI features regardless of provider configuration
add_filter( 'migro_ai_provider_available', '__return_false' );

// Treat Yoast Premium AI as inactive (use Migro's generator instead)
add_filter( 'migro_ai_yoast_premium_active', '__return_false' );

// Inject a mock alt-text response during automated tests
add_filter( 'migro_ai_mock_generate_alt', function( $alt, $attachment_id, $context ) {
    return 'A descriptive mock alt for attachment #' . $attachment_id;
}, 10, 3 );

// Inject mock Yoast meta during tests
add_filter( 'migro_ai_mock_generate_yoast', function( $meta, $post_id ) {
    return array(
        'title'       => 'Mock SEO title',
        'description' => 'Mock meta description for testing.',
    );
}, 10, 2 );

Alt Text Sync Hooks

The sync runs at priority 20 on the same image-migrate hooks as the AI generator, so you can chain your own callback after both.

alt sync
// Runs after BOTH AI generation (priority 10) and inline reconciliation (priority 20)
add_action( 'migro_after_image_migrate_local', function( &$result, &$final_content, $local_id, $remote_id, $connection, $options ) {
    // $final_content now has AI-generated alts written into inline HTML
}, 30, 6 );

AJAX Endpoints

These endpoints are available for custom integrations. All require a valid nonce and edit_posts capability.

  • migro_test_connection: Test database and API connectivity
  • migro_load_content: Load available posts from the remote or local site
  • migro_start: Begin a migration
  • migro_get_logs: Fetch migration log entries
  • migro_get_post_types: Get available post types
  • migro_quick_migrate: Trigger a Quick Migrate for a single post
  • migro_get_backups: List available backups
  • migro_restore_backup: Restore a backup
  • migro_delete_backup: Delete a backup

Translations & i18n Standards

If you are extending Migro or translating the interface, follow the plugin's i18n standards to maintain POT scanner compliance.

The JS centralized translation rule

No JavaScript file in the plugin except admin/assets/js/messages.js may call localization helpers like __() directly. All translatable strings used in client-side scripts are registered inside messages.js and accessed via the global window-scoped object:

// Standard access inside custom JS:
console.log( Migro_Messages.connection_success );

Translation Validation Gate

Before submitting translations (.po/.mo files), run them through bin/i18n-lint.py. It validates:

  • Placeholder consistency: All dynamic specifiers (%s, %d) in source match target exactly.
  • HTML safety: Tags like <a> and <strong> are correctly formed.
  • Console tokens: Bracket indicators ([CHECKMARK], [WARNING]) are preserved to protect terminal logs.