diff --git a/includes/blocks/class-convertkit-block-form-builder.php b/includes/blocks/class-convertkit-block-form-builder.php index 51e06c32a..af9b14d7f 100644 --- a/includes/blocks/class-convertkit-block-form-builder.php +++ b/includes/blocks/class-convertkit-block-form-builder.php @@ -98,7 +98,8 @@ public function maybe_subscribe() { $custom_fields = $form_data['custom_fields']; } - // Get Tag and Sequence IDs, if any were specified. + // Get Form, Tag and Sequence IDs, if any were specified. + $form_id = array_key_exists( 'form_id', $form_data ) ? $form_data['form_id'] : false; $tag_id = array_key_exists( 'tag_id', $form_data ) ? $form_data['tag_id'] : false; $sequence_id = array_key_exists( 'sequence_id', $form_data ) ? $form_data['sequence_id'] : false; @@ -116,6 +117,7 @@ public function maybe_subscribe() { 'email' => $form_data['email'], 'first_name' => $form_data['first_name'], 'custom_fields' => $custom_fields, + 'form_id' => $form_id, 'tag_id' => $tag_id, 'sequence_id' => $sequence_id, 'api_result' => 'error', @@ -154,6 +156,7 @@ public function maybe_subscribe() { 'email' => $form_data['email'], 'first_name' => $form_data['first_name'], 'custom_fields' => $custom_fields, + 'form_id' => $form_id, 'tag_id' => $tag_id, 'sequence_id' => $sequence_id, 'api_result' => 'error', @@ -172,6 +175,7 @@ public function maybe_subscribe() { 'email' => $form_data['email'], 'first_name' => $form_data['first_name'], 'custom_fields' => $custom_fields, + 'form_id' => $form_id, 'tag_id' => $tag_id, 'sequence_id' => $sequence_id, 'api_result' => 'success', @@ -183,6 +187,31 @@ public function maybe_subscribe() { $subscriber = new ConvertKit_Subscriber(); $subscriber->set( $result['subscriber']['id'] ); + // If a form was specified, add the subscriber to the form. + if ( $form_id ) { + $result = $api->add_subscriber_to_form( + $form_id, + $result['subscriber']['id'], + get_permalink( absint( $form_data['post_id'] ) ) + ); + + if ( $form_data['store_entries'] ) { + $entries->upsert( + array( + 'post_id' => $form_data['post_id'], + 'email' => $form_data['email'], + 'first_name' => $form_data['first_name'], + 'custom_fields' => $custom_fields, + 'form_id' => $form_id, + 'tag_id' => $tag_id, + 'sequence_id' => $sequence_id, + 'api_result' => is_wp_error( $result ) ? 'error' : 'success', + 'api_error' => is_wp_error( $result ) ? $result->get_error_message() : '', + ) + ); + } + } + // If a tag was specified, add the subscriber to the tag. if ( $tag_id ) { $result = $api->tag_subscriber( $tag_id, $result['subscriber']['id'] ); @@ -194,6 +223,7 @@ public function maybe_subscribe() { 'email' => $form_data['email'], 'first_name' => $form_data['first_name'], 'custom_fields' => $custom_fields, + 'form_id' => $form_id, 'tag_id' => $tag_id, 'sequence_id' => $sequence_id, 'api_result' => is_wp_error( $result ) ? 'error' : 'success', @@ -214,6 +244,7 @@ public function maybe_subscribe() { 'email' => $form_data['email'], 'first_name' => $form_data['first_name'], 'custom_fields' => $custom_fields, + 'form_id' => $form_id, 'tag_id' => $tag_id, 'sequence_id' => $sequence_id, 'api_result' => is_wp_error( $result ) ? 'error' : 'success', @@ -363,6 +394,10 @@ public function get_attributes() { 'type' => 'string', 'default' => $this->get_default_value( 'text_if_subscribed' ), ), + 'form_id' => array( + 'type' => 'string', + 'default' => $this->get_default_value( 'form_id' ), + ), 'tag_id' => array( 'type' => 'string', 'default' => $this->get_default_value( 'tag_id' ), @@ -441,6 +476,20 @@ public function get_fields() { return false; } + // Get Kit Forms. + $forms = new ConvertKit_Resource_Forms( 'block_form_builder' ); + $forms_options = array(); + if ( $forms->exist() ) { + foreach ( $forms->get() as $form ) { + // Legacy forms don't include a `format` key, so define them as inline. + $forms_options[ $form['id'] ] = sprintf( + '%s [%s]', + sanitize_text_field( $form['name'] ), + ( ! empty( $form['format'] ) ? sanitize_text_field( $form['format'] ) : 'inline' ) + ); + } + } + // Get Kit Tags. $tags = new ConvertKit_Resource_Tags( 'block_form_builder' ); $tags_options = array(); @@ -480,6 +529,12 @@ public function get_fields() { 'type' => 'text', 'description' => __( 'The text to display if the visitor is already subscribed.', 'convertkit' ), ), + 'form_id' => array( + 'label' => __( 'Form', 'convertkit' ), + 'type' => 'select', + 'description' => __( 'The Kit form to add the subscriber to. Useful if you want to send an incentive email.', 'convertkit' ), + 'values' => $forms_options, + ), 'tag_id' => array( 'label' => __( 'Tag', 'convertkit' ), 'type' => 'select', @@ -514,6 +569,7 @@ public function get_panels() { 'general' => array( 'label' => __( 'General', 'convertkit' ), 'fields' => array( + 'form_id', 'tag_id', 'sequence_id', 'redirect', @@ -536,6 +592,7 @@ public function get_panels() { public function get_default_values() { return array( + 'form_id' => '', 'tag_id' => '', 'sequence_id' => '', 'redirect' => '', @@ -700,6 +757,7 @@ private function add_form_to_block_content( $content, $atts, $post_id ) { 'convertkit[post_id]' => absint( $post_id ), 'convertkit[store_entries]' => $atts['store_entries'] ? '1' : '0', 'convertkit[redirect]' => esc_url( $atts['redirect'] ), + 'convertkit[form_id]' => absint( $atts['form_id'] ), 'convertkit[tag_id]' => absint( $atts['tag_id'] ), 'convertkit[sequence_id]' => absint( $atts['sequence_id'] ), '_wpnonce' => wp_create_nonce( 'convertkit_block_form_builder' ), diff --git a/includes/blocks/form-builder/block.json b/includes/blocks/form-builder/block.json index 9c7c3b3ec..f8e60ea92 100644 --- a/includes/blocks/form-builder/block.json +++ b/includes/blocks/form-builder/block.json @@ -17,12 +17,24 @@ "redirect": { "type": "string" }, + "store_entries": { + "type": "boolean" + }, "display_form_if_subscribed": { "type": "boolean" }, "text_if_subscribed": { "type": "string" }, + "form_id": { + "type": "string" + }, + "tag_id": { + "type": "string" + }, + "sequence_id": { + "type": "string" + }, "fontSize": { "type": "string" }, diff --git a/includes/class-convertkit-form-entries.php b/includes/class-convertkit-form-entries.php index 040afd0a7..eb0d2a15d 100644 --- a/includes/class-convertkit-form-entries.php +++ b/includes/class-convertkit-form-entries.php @@ -43,6 +43,7 @@ public function create_database_table() { `first_name` varchar(191) NOT NULL DEFAULT '', `email` varchar(191) NOT NULL DEFAULT '', `custom_fields` text, + `form_id` int(11) NOT NULL, `tag_id` int(11) NOT NULL, `sequence_id` int(11) NOT NULL, `created_at` datetime NOT NULL, @@ -53,6 +54,7 @@ public function create_database_table() { KEY `post_id` (`post_id`), KEY `first_name` (`first_name`), KEY `email` (`email`), + KEY `form_id` (`form_id`), KEY `tag_id` (`tag_id`), KEY `sequence_id` (`sequence_id`), KEY `api_result` (`api_result`) @@ -74,6 +76,7 @@ public function create_database_table() { * string $first_name First Name. * string $email Email. * array $custom_fields Custom Fields. + * int $form_id Form ID. * int $tag_id Tag ID. * int $sequence_id Sequence ID. * string $api_result Result (success,error). @@ -124,6 +127,7 @@ public function add( $entry ) { * string $first_name First Name. * string $email Email. * array $custom_fields Custom Fields. + * int $form_id Form ID. * int $tag_id Tag ID. * int $sequence_id Sequence ID. * string $api_result Result (success,error). @@ -168,6 +172,9 @@ public function update( $id, $entry ) { * string $first_name First Name. * string $email Email. * array $custom_fields Custom Fields. + * int $form_id Form ID. + * int $tag_id Tag ID. + * int $sequence_id Sequence ID. * datetime $created_at Created At. * datetime $api_request_sent Request Sent to API. * string $api_result Result (success,test_mode,pending,error). diff --git a/includes/class-convertkit-setup.php b/includes/class-convertkit-setup.php index ecd8f4ce7..8f47b8835 100644 --- a/includes/class-convertkit-setup.php +++ b/includes/class-convertkit-setup.php @@ -60,6 +60,13 @@ public function update() { return; } + /** + * 3.0.4: Add form_id to entries database table. + */ + if ( version_compare( $current_version, '3.0.4', '<' ) ) { + $this->add_form_id_column_and_key_to_form_entries_database_table(); + } + /** * 3.0.0: Migrate reCAPTCHA settings from Restrict Content to General settings. * Install entries database table. @@ -157,6 +164,44 @@ public function update() { } + /** + * Adds form_id column and key to form entries database table. + * + * @since 3.0.4 + */ + private function add_form_id_column_and_key_to_form_entries_database_table() { + + global $wpdb; + + // Check if the column exists. + $exists = $wpdb->get_var( + $wpdb->prepare( + 'SELECT COLUMN_NAME + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = %s + AND table_schema = %s + AND column_name = %s', + $wpdb->prefix . 'kit_form_entries', + $wpdb->dbname, + 'form_id' + ) + ); + + // If the column exists, don't add it again. + if ( $exists === 'form_id' ) { + return; + } + + // Add the form_id column and key. + $wpdb->query( + $wpdb->prepare( 'ALTER TABLE %i ADD COLUMN `form_id` int(11) NOT NULL AFTER `custom_fields`', $wpdb->prefix . 'kit_form_entries' ) + ); + $wpdb->query( + $wpdb->prepare( 'ALTER TABLE %i ADD KEY `form_id` (`form_id`)', $wpdb->prefix . 'kit_form_entries' ) + ); + + } + /** * 3.0.0: Migrate reCAPTCHA settings from Restrict Content settings to General settings. * diff --git a/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php b/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php index 6a6587b32..d7060bc5c 100644 --- a/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php +++ b/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php @@ -239,6 +239,113 @@ public function testFormBuilderBlockWithTextCustomization(EndToEndTester $I) ); } + /** + * Test the Form Builder block works when added and a Form is specified + * to subscribe the subscriber to. + * + * @since 3.0.4 + * + * @param EndToEndTester $I Tester. + */ + public function testFormBuilderBlockWithFormEnabled(EndToEndTester $I) + { + // Setup Plugin and Resources. + $I->setupKitPlugin($I); + $I->setupKitPluginResources($I); + + // Add a Page using the Gutenberg editor. + $I->addGutenbergPage( + $I, + title: 'Kit: Page: Form Builder: Block: Form Enabled' + ); + + // Configure metabox's Form setting = None, ensuring we only test the block in Gutenberg. + $I->configureMetaboxSettings( + $I, + 'wp-convertkit-meta-box', + [ + 'form' => [ 'select2', 'None' ], + ] + ); + + // Add block to Page. + $I->addGutenbergBlock( + $I, + blockName: 'Kit Form Builder', + blockProgrammaticName: 'convertkit-form-builder', + blockConfiguration: [ + 'form_id' => [ 'select', $_ENV['CONVERTKIT_API_FORM_NAME'] ], + ] + ); + + // Confirm the block template was used as the default. + $this->seeFormBuilderBlock($I); + $this->seeFormBuilderButtonBlock($I); + $this->seeFormBuilderField( + $I, + fieldType: 'text', + fieldName: 'first_name', + fieldID: 'first_name', + label: 'First name', + container: 'div[data-type="convertkit/form-builder"]' + ); + $this->seeFormBuilderField( + $I, + fieldType: 'email', + fieldName: 'email', + fieldID: 'email', + label: 'Email address', + container: 'div[data-type="convertkit/form-builder"]' + ); + + // Publish and view the Page on the frontend site. + $I->publishAndViewGutenbergPage($I); + + // Confirm that the Form is output in the DOM. + $this->seeFormBuilderField( + $I, + fieldType: 'text', + fieldName: 'first_name', + fieldID: 'first_name', + label: 'First name', + container: 'div.wp-block-convertkit-form-builder' + ); + $this->seeFormBuilderField( + $I, + fieldType: 'email', + fieldName: 'email', + fieldID: 'email', + label: 'Email address', + container: 'div.wp-block-convertkit-form-builder' + ); + + // Generate email address for this test. + $emailAddress = $I->generateEmailAddress(); + + // Submit form. + $I->fillField('input[name="convertkit[first_name]"]', 'First'); + $I->fillField('input[name="convertkit[email]"]', $emailAddress); + $I->click('div.wp-block-convertkit-form-builder button[type="submit"]'); + $I->waitForElementVisible('body.page'); + + // Confirm that the email address was added to Kit. + $I->waitForElementVisible('body.page'); + $I->wait(3); + $subscriber = $I->apiCheckSubscriberExists( + $I, + emailAddress: $emailAddress, + firstName: 'First' + ); + + // Confirm that the subscriber has the form. + $I->apiCheckSubscriberHasForm( + $I, + subscriberID: $subscriber['id'], + formID: $_ENV['CONVERTKIT_API_FORM_ID'], + referrer: $_ENV['WORDPRESS_URL'] . $I->grabFromCurrentUrl() + ); + } + /** * Test the Form Builder block works when added and a Tag is specified * to subscribe the subscriber to. diff --git a/tests/EndToEnd/general/other/UpgradePathsCest.php b/tests/EndToEnd/general/other/UpgradePathsCest.php index 09ab701f3..af97ded84 100644 --- a/tests/EndToEnd/general/other/UpgradePathsCest.php +++ b/tests/EndToEnd/general/other/UpgradePathsCest.php @@ -215,6 +215,58 @@ public function testCreateFormEntriesTable(EndToEndTester $I) $I->seeTableInDatabase('wp_kit_form_entries'); } + /** + * Tests that the form_id column is added to the form entries table when upgrading to 3.0.4 or later. + * + * @since 3.0.4 + * + * @param EndToEndTester $I Tester. + */ + public function testUpdateFormEntriesTableAddsFormIDColumn(EndToEndTester $I) + { + // Create the form entries table as if it were created in 3.0.3 or older, + // without the form_id column. + $I->importSql( + [ + "CREATE TABLE IF NOT EXISTS wp_kit_form_entries ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `post_id` int(11) NOT NULL, + `first_name` varchar(191) NOT NULL DEFAULT '', + `email` varchar(191) NOT NULL DEFAULT '', + `custom_fields` text, + `tag_id` int(11) NOT NULL, + `sequence_id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `api_result` varchar(191) NOT NULL DEFAULT 'success', + `api_error` text, + PRIMARY KEY (`id`), + KEY `post_id` (`post_id`), + KEY `first_name` (`first_name`), + KEY `email` (`email`), + KEY `tag_id` (`tag_id`), + KEY `sequence_id` (`sequence_id`), + KEY `api_result` (`api_result`) + ) AUTO_INCREMENT=1", + ] + ); + + // Confirm the form entries table is created. + $I->seeTableInDatabase('wp_kit_form_entries'); + + // Setup Kit Plugin. + $I->setupKitPlugin($I); + + // Define an installation version older than 3.0.3. + $I->haveOptionInDatabase('convertkit_version', '3.0.0'); + + // Activate the Plugin. + $I->activateKitPlugin($I, false); + + // Confirm the form entries table now has the form_id column. + $I->seeColumnInDatabase('wp_kit_form_entries', 'form_id'); + } + /** * Deactivate and reset Plugin(s) after each test, if the test passes. * We don't use _after, as this would provide a screenshot of the Plugin diff --git a/tests/Support/Helper/KitPlugin.php b/tests/Support/Helper/KitPlugin.php index fee3ed6de..3b3a978ed 100644 --- a/tests/Support/Helper/KitPlugin.php +++ b/tests/Support/Helper/KitPlugin.php @@ -1016,4 +1016,27 @@ public function truncateDbTable($table) { $this->getModule(\lucatume\WPBrowser\Module\WPDb::class)->_getDbh()->query('TRUNCATE TABLE ' . $table); } + + /** + * Helper method to assert that the given column exists in the given table. + * + * @since 3.0.4 + * + * @param string $table Table name. + * @param string $column Column name. + */ + public function seeColumnInDatabase(string $table, string $column): void + { + $wpDb = $this->getModule(\lucatume\WPBrowser\Module\WPDb::class); + $dbh = $wpDb->_getDbh(); + + $stmt = $dbh->prepare("SHOW COLUMNS FROM {$table} LIKE ?"); + $stmt->execute([ $column ]); + $result = $stmt->fetch(); + + $this->assertNotEmpty( + $result, + "Failed asserting that column '{$column}' exists in table '{$table}'." + ); + } } diff --git a/wp-convertkit.php b/wp-convertkit.php index cffe19d17..e3e9e0c53 100644 --- a/wp-convertkit.php +++ b/wp-convertkit.php @@ -9,7 +9,7 @@ * Plugin Name: Kit (formerly ConvertKit) * Plugin URI: https://kit.com/ * Description: Display Kit (formerly ConvertKit) email subscription forms, landing pages, products, broadcasts and more. - * Version: 3.0.3 + * Version: 3.0.4 * Author: Kit * Author URI: https://kit.com/ * Text Domain: convertkit @@ -27,7 +27,7 @@ define( 'CONVERTKIT_PLUGIN_FILE', plugin_basename( __FILE__ ) ); define( 'CONVERTKIT_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'CONVERTKIT_PLUGIN_PATH', __DIR__ ); -define( 'CONVERTKIT_PLUGIN_VERSION', '3.0.3' ); +define( 'CONVERTKIT_PLUGIN_VERSION', '3.0.4' ); define( 'CONVERTKIT_OAUTH_CLIENT_ID', 'HXZlOCj-K5r0ufuWCtyoyo3f688VmMAYSsKg1eGvw0Y' ); define( 'CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI', 'https://app.kit.com/wordpress/redirect' );