Skip to content
Merged
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
DB_USER: root
DB_PASS: root
DB_HOST: localhost
INSTALL_PLUGINS: "admin-menu-editor autoptimize beaver-builder-lite-version block-visibility contact-form-7 classic-editor custom-post-type-ui debloat elementor forminator jetpack-boost woocommerce wordpress-seo wpforms-lite litespeed-cache wp-crontrol wp-super-cache w3-total-cache wp-fastest-cache wp-optimize sg-cachepress" # Don't include this repository's Plugin here.
INSTALL_PLUGINS: "admin-menu-editor autoptimize beaver-builder-lite-version block-visibility contact-form-7 classic-editor custom-post-type-ui debloat elementor forminator jetpack-boost mailchimp-for-wp woocommerce wordpress-seo wpforms-lite litespeed-cache wp-crontrol wp-super-cache w3-total-cache wp-fastest-cache wp-optimize sg-cachepress" # Don't include this repository's Plugin here.
INSTALL_PLUGINS_URLS: "https://downloads.wordpress.org/plugin/convertkit-for-woocommerce.1.6.4.zip http://cktestplugins.wpengine.com/wp-content/uploads/2024/01/convertkit-action-filter-tests.zip http://cktestplugins.wpengine.com/wp-content/uploads/2024/11/disable-doing-it-wrong-notices.zip http://cktestplugins.wpengine.com/wp-content/uploads/2025/03/uncode-js_composer.7.8.zip http://cktestplugins.wpengine.com/wp-content/uploads/2025/03/uncode-core.zip" # URLs to specific third party Plugins
INSTALL_THEMES_URLS: "http://cktestplugins.wpengine.com/wp-content/uploads/2025/03/uncode.zip http://cktestplugins.wpengine.com/wp-content/uploads/2025/04/Divi.zip"
CONVERTKIT_API_KEY: ${{ secrets.CONVERTKIT_API_KEY }} # ConvertKit API Key, stored in the repository's Settings > Secrets
Expand Down
94 changes: 94 additions & 0 deletions admin/importers/class-convertkit-admin-importer-mc4wp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
/**
* ConvertKit Admin Importer MC4WP class.
*
* @package ConvertKit
* @author ConvertKit
*/

/**
* Import and migrate data from Mailchimp (MC4WP) to Kit.
*
* @package ConvertKit
* @author ConvertKit
*/
class ConvertKit_Admin_Importer_MC4WP extends ConvertKit_Admin_Importer {

/**
* Holds the shortcode name for MC4WP forms.
*
* @since 3.1.0
*
* @var string
*/
public $shortcode_name = 'mc4wp_form';

/**
* Holds the ID attribute name for MC4WP forms.
*
* @since 3.1.0
*
* @var string
*/
public $shortcode_id_attribute = 'id';

/**
* Returns an array of post IDs that contain the MC4WP form shortcode.
*
* @since 3.1.0
*
* @return array
*/
public function get_forms_in_posts() {

global $wpdb;

// Search post_content for [mc4wp_form] shortcode and return array of post IDs.
$results = $wpdb->get_col(
$wpdb->prepare(
"
SELECT ID
FROM {$wpdb->posts}
WHERE post_status = %s
AND post_content LIKE %s
",
'publish',
'%[' . $this->shortcode_name . '%'
)
);

return $results ? $results : array();

}

/**
* Returns an array of MC4WP form IDs and titles.
*
* @since 3.1.0
*
* @return array
*/
public function get_forms() {

$posts = new WP_Query(
array(
'post_type' => 'mc4wp-form',
'post_status' => 'publish',
'update_post_cache' => false,
)
);

if ( ! $posts->post_count ) {
return array();
}

$forms = array();
foreach ( $posts->posts as $form ) {
$forms[ $form->ID ] = $form->post_title;
}

return $forms;

}

}
148 changes: 148 additions & 0 deletions admin/importers/class-convertkit-admin-importer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php
/**
* ConvertKit Admin Importer class.
*
* @package ConvertKit
* @author ConvertKit
*/

/**
* Import and migrate data from third party Form plugins to Kit.
*
* @package ConvertKit
* @author ConvertKit
*/
abstract class ConvertKit_Admin_Importer {

/**
* Holds the shortcode name for the third party Form plugin.
*
* @since 3.1.0
*
* @var string
*/
public $shortcode_name = '';

/**
* Holds the ID attribute name for the third party Form plugin.
*
* @since 3.1.0
*
* @var string
*/
public $shortcode_id_attribute = '';

/**
* Returns an array of third party form IDs and titles.
*
* @since 3.1.0
*
* @return array
*/
abstract public function get_forms();

/**
* Returns an array of post IDs that contain the third party form shortcode.
*
* @since 3.1.0
*
* @return array
*/
abstract public function get_forms_in_posts();

/**
* Returns whether any third party forms exist.
*
* @since 3.1.0
*
* @return bool
*/
public function has_forms() {

return count( $this->get_forms() ) > 0;

}

/**
* Returns whether any third party forms exist in posts.
*
* @since 3.1.0
*
* @return bool
*/
public function has_forms_in_posts() {

return count( $this->get_forms_in_posts() ) > 0;

}

/**
* Replaces the third party form shortcode with the Kit form shortcode.
*
* @since 3.1.0
*
* @param int $third_party_form_id The ID of the third party form.
* @param int $form_id The ID of the Kit form.
*/
public function replace_shortcodes_in_posts( $third_party_form_id, $form_id ) {

// Get Posts that contain the third party Form Shortcode.
$posts = $this->get_forms_in_posts();

// Bail if no Posts contain the third party Form Shortcode.
if ( empty( $posts ) ) {
return;
}

// Iterate through Posts and replace the third party Form Shortcode with the Kit Form Shortcode.
foreach ( $posts as $post_id ) {
// Get Post content.
$post_content = get_post_field( 'post_content', $post_id );

// Replace the third party Form Shortcode with the Kit Form Shortcode.
$post_content = $this->replace_shortcodes_in_content( $post_content, $third_party_form_id, $form_id );

// Update the Post content.
wp_update_post(
array(
'ID' => $post_id,
'post_content' => $post_content,
),
false,
false // Don't fire after action hooks.
);

}

}

/**
* Replaces the third party form shortcode with the Kit form shortcode in the given string.
*
* @since 3.1.0
*
* @param string $content Content containing third party Form Shortcodes.
* @param int $third_party_form_id Third Party Form ID.
* @param int $form_id Kit Form ID.

* @return string
*/
public function replace_shortcodes_in_content( $content, $third_party_form_id, $form_id ) {

$pattern = '/\[' // Start regex with an opening square bracket.
. preg_quote( $this->shortcode_name, '/' ) // Match the shortcode name, escaping any regex special chars.
. '[^\]]*?' // Match any characters that are not a closing square bracket, non-greedy.
. '\b' . preg_quote( $this->shortcode_id_attribute, '/' ) // Match the id attribute word boundary and escape as needed.
. '\s*=\s*' // Match optional whitespace around an equals sign.
. '(?:"' . preg_quote( (string) $third_party_form_id, '/' ) . '"|' . preg_quote( (string) $third_party_form_id, '/' ) . ')' // Match the form ID, quoted or unquoted.
. '[^\]]*?\]/i'; // Match any other characters (non-greedy) up to the closing square bracket, case-insensitive.

return preg_replace(
$pattern,
'[convertkit_form id="' . $form_id . '"]',
$content
);

}

}
43 changes: 43 additions & 0 deletions admin/section/class-convertkit-admin-section-tools.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public function register_notices( $notices ) {
'import_configuration_invalid_file_type' => __( 'The uploaded configuration file isn\'t valid.', 'convertkit' ),
'import_configuration_empty' => __( 'The uploaded configuration file contains no settings.', 'convertkit' ),
'import_configuration_success' => __( 'Configuration imported successfully.', 'convertkit' ),
'migrate_mc4wp_configuration_success' => __( 'MC4WP forms migrated successfully.', 'convertkit' ),
)
);

Expand All @@ -75,6 +76,7 @@ private function maybe_perform_actions() {
$this->maybe_download_system_info();
$this->maybe_export_configuration();
$this->maybe_import_configuration();
$this->maybe_migrate_mc4wp_configuration();

}

Expand Down Expand Up @@ -314,6 +316,41 @@ private function maybe_import_configuration() {

}

/**
* Replaces MC4WP Form Shortcodes with Kit Form Shortcodes, if the user submitted the
* MC4WP Migrate Configuration section.
*
* @since 3.1.0
*/
private function maybe_migrate_mc4wp_configuration() {

// Bail if nonce verification fails.
if ( ! isset( $_REQUEST['_convertkit_settings_tools_nonce'] ) ) {
return;
}

if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_convertkit_settings_tools_nonce'] ), 'convertkit-settings-tools' ) ) {
return;
}

// Bail if no MC4WP Form IDs were submitted.
if ( ! isset( $_REQUEST['_wp_convertkit_integration_mc4wp_settings'] ) ) {
return;
}

// Initialise the importer.
$mc4wp = new ConvertKit_Admin_Importer_MC4WP();

// Iterate through the MC4WP Form IDs and replace the shortcodes with the Kit Form Shortcodes.
foreach ( array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['_wp_convertkit_integration_mc4wp_settings'] ) ) as $mc4wp_form_id => $kit_form_id ) {
$mc4wp->replace_shortcodes_in_posts( (int) $mc4wp_form_id, (int) $kit_form_id );
}

// Redirect to Tools screen.
$this->redirect_with_success_notice( 'migrate_mc4wp_configuration_success' );

}

/**
* Outputs the Debug Log and System Info view.
*
Expand All @@ -332,6 +369,12 @@ public function render() {
$log = new ConvertKit_Log( CONVERTKIT_PLUGIN_PATH );
$system_info = $this->get_system_info();

// Get Forms.
$forms = new ConvertKit_Resource_Forms();

// Get Importers.
$mc4wp = new ConvertKit_Admin_Importer_MC4WP();

// Output view.
require_once CONVERTKIT_PLUGIN_PATH . '/views/backend/settings/tools.php';

Expand Down
Loading