diff --git a/includes/class-blocks.php b/includes/class-blocks.php
index eccc0fafa8..24e4b19dcf 100644
--- a/includes/class-blocks.php
+++ b/includes/class-blocks.php
@@ -40,7 +40,7 @@ public static function enqueue_block_editor_assets() {
[
'has_newsletters' => class_exists( 'Newspack_Newsletters_Subscription' ),
'has_reader_activation' => Reader_Activation::is_enabled(),
- 'newsletters_url' => Wizards::get_wizard( 'engagement' )->newsletters_settings_url(),
+ 'newsletters_url' => Wizards::get_wizard( 'newsletters' )->newsletters_settings_url(),
'has_google_oauth' => Google_OAuth::is_oauth_configured(),
'google_logo_svg' => file_get_contents( dirname( NEWSPACK_PLUGIN_FILE ) . '/src/blocks/reader-registration/icons/google.svg' ),
'reader_activation_terms' => Reader_Activation::get_setting( 'terms_text' ),
diff --git a/includes/class-newspack.php b/includes/class-newspack.php
index 7e8efc3c0e..2c5c80e899 100644
--- a/includes/class-newspack.php
+++ b/includes/class-newspack.php
@@ -147,6 +147,10 @@ private function includes() {
// Advertising Wizard.
include_once NEWSPACK_ABSPATH . 'includes/wizards/advertising/class-advertising-display-ads.php';
include_once NEWSPACK_ABSPATH . 'includes/wizards/advertising/class-advertising-sponsors.php';
+
+ // Audience Wizard.
+ include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-configuration.php';
+ include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-campaigns.php';
// Network Wizard.
include_once NEWSPACK_ABSPATH . 'includes/wizards/class-network-wizard.php';
diff --git a/includes/class-wizards.php b/includes/class-wizards.php
index ebb04d532b..5c06fa3cc3 100644
--- a/includes/class-wizards.php
+++ b/includes/class-wizards.php
@@ -55,6 +55,8 @@ public static function init() {
),
'advertising-display-ads' => new Advertising_Display_Ads(),
'advertising-sponsors' => new Advertising_Sponsors(),
+ 'audience-configuration' => new Audience_Configuration(),
+ 'audience-campaigns' => new Audience_Campaigns(),
'listings' => new Listings_Wizard(),
'network' => new Network_Wizard(),
'newsletters' => new Newsletters_Wizard(),
diff --git a/includes/reader-activation/class-reader-activation.php b/includes/reader-activation/class-reader-activation.php
index 06abbcf2e6..cff9842dc8 100644
--- a/includes/reader-activation/class-reader-activation.php
+++ b/includes/reader-activation/class-reader-activation.php
@@ -507,7 +507,7 @@ public static function get_prerequisites_status() {
'description' => __( 'Connect to your ESP to register readers with their email addresses and send newsletters.', 'newspack-plugin' ),
'instructions' => __( 'Connect to your email service provider (ESP) and enable at least one subscription list.', 'newspack-plugin' ),
'help_url' => 'https://help.newspack.com/engagement/reader-activation-system',
- 'href' => \admin_url( '/admin.php?page=newspack-engagement-wizard#/newsletters' ),
+ 'href' => \admin_url( 'edit.php?post_type=newspack_nl_cpt&page=newspack-newsletters' ),
'action_text' => __( 'ESP settings' ),
],
'emails' => [
@@ -536,7 +536,7 @@ public static function get_prerequisites_status() {
'description' => __( 'Connecting to a Google reCAPTCHA account enables enhanced anti-spam for all Newspack sign-up blocks.', 'newspack-plugin' ),
'instructions' => __( 'Enable reCAPTCHA and enter your account credentials.', 'newspack-plugin' ),
'help_url' => 'https://help.newspack.com/engagement/reader-activation-system',
- 'href' => \admin_url( '/admin.php?page=newspack-connections-wizard&scrollTo=recaptcha' ),
+ 'href' => \admin_url( '/admin.php?page=newspack-settings&scrollTo=newspack-settings-recaptcha' ),
'action_text' => __( 'reCAPTCHA settings' ),
],
'reader_revenue' => [
@@ -550,6 +550,7 @@ public static function get_prerequisites_status() {
'description' => __( 'Setting suggested donation amounts is required for enabling a streamlined donation experience.', 'newspack-plugin' ),
'instructions' => __( 'Set platform to "Newspack" or "News Revenue Hub" and configure your default donation settings. If using News Revenue Hub, set an Organization ID and a Donor Landing Page in News Revenue Hub Settings.', 'newspack-plugin' ),
'help_url' => 'https://help.newspack.com/engagement/reader-activation-system',
+ // @TODO: Update when platform is added.
'href' => \admin_url( '/admin.php?page=newspack-reader-revenue-wizard' ),
'action_text' => __( 'Reader Revenue settings' ),
],
@@ -562,7 +563,7 @@ public static function get_prerequisites_status() {
'label' => __( 'Reader Activation Campaign', 'newspack-plugin' ),
'description' => __( 'Building a set of prompts with default segments and settings allows for an improved experience optimized for Reader Activation.', 'newspack-plugin' ),
'help_url' => 'https://help.newspack.com/engagement/reader-activation-system',
- 'href' => self::is_ras_campaign_configured() ? \admin_url( '/admin.php?page=newspack-popups-wizard#/campaigns' ) : \admin_url( '/admin.php?page=newspack-engagement-wizard#/reader-activation/campaign' ),
+ 'href' => self::is_ras_campaign_configured() ? admin_url( '/admin.php?page=newspack-audience-campaigns' ) : admin_url( '/admin.php?page=newspack-audience-configuration#/campaign' ),
'action_enabled' => self::is_ras_ready_to_configure(),
'action_text' => __( 'Reader Activation campaign', 'newspack-plugin' ),
'disabled_text' => __( 'Waiting for all settings to be ready', 'newspack-plugin' ),
diff --git a/includes/wizards/audience/class-audience-campaigns.php b/includes/wizards/audience/class-audience-campaigns.php
new file mode 100644
index 0000000000..123414cb6a
--- /dev/null
+++ b/includes/wizards/audience/class-audience-campaigns.php
@@ -0,0 +1,66 @@
+is_wizard_page() ) {
+ return;
+ }
+
+ parent::enqueue_scripts_and_styles();
+
+ wp_enqueue_script( 'newspack-wizards' );
+ }
+
+ /**
+ * Add Audience top-level and Campaigns subpage to the /wp-admin menu.
+ */
+ public function add_page() {
+ add_submenu_page(
+ $this->parent_slug,
+ $this->get_name(),
+ esc_html__( 'Campaigns', 'newspack-plugin' ),
+ $this->capability,
+ $this->slug,
+ [ $this, 'render_wizard' ]
+ );
+ }
+}
diff --git a/includes/wizards/audience/class-audience-configuration.php b/includes/wizards/audience/class-audience-configuration.php
new file mode 100644
index 0000000000..0f360d9ffd
--- /dev/null
+++ b/includes/wizards/audience/class-audience-configuration.php
@@ -0,0 +1,320 @@
+is_wizard_page() ) {
+ return;
+ }
+ parent::enqueue_scripts_and_styles();
+ $data = [
+ 'has_memberships' => class_exists( 'WC_Memberships' ),
+ 'reader_activation_url' => admin_url( 'admin.php?page=newspack-audience-configuration#/' ),
+ 'esp_metadata_fields' => Reader_Activation\Sync\Metadata::get_default_fields(),
+ ];
+
+ if ( method_exists( 'Newspack\Newsletters\Subscription_Lists', 'get_add_new_url' ) ) {
+ $data['new_subscription_lists_url'] = Newsletters\Subscription_Lists::get_add_new_url();
+ }
+
+ if ( method_exists( 'Newspack_Newsletters_Subscription', 'get_lists' ) ) {
+ $data['available_newsletter_lists'] = Newspack_Newsletters_Subscription::get_lists();
+ }
+
+ $newspack_popups = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'newspack-popups' );
+
+ if ( $newspack_popups->is_configured() ) {
+ $data['preview_query_keys'] = $newspack_popups->preview_query_keys();
+ $data['preview_post'] = $newspack_popups->preview_post();
+ $data['preview_archive'] = $newspack_popups->preview_archive();
+ }
+
+ $data['is_skipped_campaign_setup'] = get_option( static::SKIP_CAMPAIGN_SETUP_OPTION, '' );
+
+ wp_enqueue_script( 'newspack-wizards' );
+
+ wp_localize_script(
+ 'newspack-wizards',
+ 'newspackAudienceConfiguration',
+ $data
+ );
+ }
+
+ /**
+ * Add Audience top-level and Configuration subpage to the /wp-admin menu.
+ */
+ public function add_page() {
+ // svg source - https://wphelpers.dev/icons/people
+ // SVG generated via https://boxy-svg.com/ with path width/height 20px.
+ $icon = 'data:image/svg+xml;base64,' . base64_encode(
+ ''
+ );
+ add_menu_page(
+ $this->get_name(),
+ __( 'Audience', 'newspack-plugin' ),
+ $this->capability,
+ $this->slug,
+ [ $this, 'render_wizard' ],
+ $icon
+ );
+ add_submenu_page(
+ $this->slug,
+ $this->get_name(),
+ __( 'Configuration', 'newspack-plugin' ),
+ $this->capability,
+ $this->slug,
+ [ $this, 'render_wizard' ]
+ );
+ }
+
+ /**
+ * Register the endpoints needed for the wizard screens.
+ */
+ public function register_api_endpoints() {
+ register_rest_route(
+ NEWSPACK_API_NAMESPACE,
+ '/wizard/' . $this->slug . '/reader-activation',
+ [
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => [ $this, 'api_get_reader_activation_settings' ],
+ 'permission_callback' => [ $this, 'api_permissions_check' ],
+ ]
+ );
+ register_rest_route(
+ NEWSPACK_API_NAMESPACE,
+ '/wizard/' . $this->slug . '/reader-activation',
+ [
+ 'methods' => WP_REST_Server::EDITABLE,
+ 'callback' => [ $this, 'api_update_reader_activation_settings' ],
+ 'permission_callback' => [ $this, 'api_permissions_check' ],
+ ]
+ );
+ register_rest_route(
+ NEWSPACK_API_NAMESPACE,
+ '/wizard/' . $this->slug . '/reader-activation/activate',
+ [
+ 'methods' => WP_REST_Server::EDITABLE,
+ 'callback' => [ $this, 'api_activate_reader_activation' ],
+ 'permission_callback' => [ $this, 'api_permissions_check' ],
+ ]
+ );
+ register_rest_route(
+ NEWSPACK_API_NAMESPACE,
+ '/wizard/' . $this->slug . '/reader-activation/skip-campaign-setup',
+ [
+ 'methods' => WP_REST_Server::EDITABLE,
+ 'callback' => function( $request ) {
+ $skip = $request->get_param( 'skip' );
+ $skip_campaign_setup = update_option( static::SKIP_CAMPAIGN_SETUP_OPTION, $skip );
+ return rest_ensure_response(
+ [
+ 'skipped' => $skip,
+ 'updated' => $skip_campaign_setup,
+ ]
+ );
+ },
+ 'permission_callback' => [ $this, 'api_permissions_check' ],
+ ]
+ );
+ }
+
+ /**
+ * Get reader activation settings.
+ *
+ * @return WP_REST_Response
+ */
+ public function api_get_reader_activation_settings() {
+ return rest_ensure_response(
+ [
+ 'config' => Reader_Activation::get_settings(),
+ 'prerequisites_status' => Reader_Activation::get_prerequisites_status(),
+ 'memberships' => self::get_memberships_settings(),
+ 'can_esp_sync' => Reader_Activation\ESP_Sync::can_esp_sync( true ),
+ ]
+ );
+ }
+
+ /**
+ * Update reader activation settings.
+ *
+ * @param WP_REST_Request $request Request object.
+ *
+ * @return WP_REST_Response
+ */
+ public function api_update_reader_activation_settings( $request ) {
+ $args = $request->get_params();
+ foreach ( $args as $key => $value ) {
+ Reader_Activation::update_setting( $key, $value );
+ }
+
+ // Update Memberships options.
+ if ( isset( $args['memberships_require_all_plans'] ) ) {
+ Memberships::set_require_all_plans_setting( (bool) $args['memberships_require_all_plans'] );
+ }
+
+ // Update Memberships options.
+ if ( isset( $args['memberships_show_on_subscription_tab'] ) ) {
+ Memberships::set_show_on_subscription_tab_setting( (bool) $args['memberships_show_on_subscription_tab'] );
+ }
+
+ return rest_ensure_response(
+ [
+ 'config' => Reader_Activation::get_settings(),
+ 'prerequisites_status' => Reader_Activation::get_prerequisites_status(),
+ 'memberships' => self::get_memberships_settings(),
+ 'can_esp_sync' => Reader_Activation\ESP_Sync::can_esp_sync( true ),
+ ]
+ );
+ }
+
+ /**
+ * Activate reader activation and publish RAS prompts/segments.
+ *
+ * @param WP_REST_Request $request WP Rest Request object.
+ * @return WP_REST_Response
+ */
+ public function api_activate_reader_activation( WP_REST_Request $request ) {
+ $skip_activation = $request->get_param( 'skip_activation' ) ?? false;
+ $response = $skip_activation ? true : Reader_Activation::activate();
+
+ if ( is_wp_error( $response ) ) {
+ return new WP_REST_Response( [ 'message' => $response->get_error_message() ], 400 );
+ }
+
+ if ( true === $response ) {
+ Reader_Activation::update_setting( 'enabled', true );
+ }
+
+ return rest_ensure_response( $response );
+ }
+
+ /**
+ * Get memberships settings.
+ *
+ * @return array
+ */
+ private static function get_memberships_settings() {
+ return [
+ 'edit_gate_url' => Memberships::get_edit_gate_url(),
+ 'gate_status' => get_post_status( Memberships::get_gate_post_id() ),
+ 'plans' => Memberships::get_plans(),
+ 'require_all_plans' => Memberships::get_require_all_plans_setting(),
+ 'show_on_subscription_tab' => Memberships::get_show_on_subscription_tab_setting(),
+ ];
+ }
+
+ /**
+ * Parent file filter. Used to determine active menu items.
+ *
+ * @param string $parent_file Parent file to be overridden.
+ * @return string
+ */
+ public function parent_file( $parent_file ) {
+ global $pagenow, $typenow;
+
+ $cpts = [
+ Memberships::GATE_CPT,
+ Emails::POST_TYPE,
+ ];
+
+ if ( in_array( $pagenow, [ 'post.php', 'post-new.php' ] ) && in_array( $typenow, $cpts ) ) {
+ return $this->slug;
+ }
+
+ return $parent_file;
+ }
+
+ /**
+ * Submenu file filter. Used to determine active submenu items.
+ *
+ * @param string $submenu_file Submenu file to be overridden.
+ * @return string
+ */
+ public function submenu_file( $submenu_file ) {
+ global $pagenow, $typenow;
+
+ $cpts = [
+ Memberships::GATE_CPT,
+ Emails::POST_TYPE,
+ ];
+
+ if ( in_array( $pagenow, [ 'post.php', 'post-new.php' ] ) && in_array( $typenow, $cpts ) ) {
+ return $this->slug;
+ }
+
+ return $submenu_file;
+ }
+}
diff --git a/includes/wizards/class-engagement-wizard.php b/includes/wizards/class-engagement-wizard.php
index f7e6bdcf77..2738d5873a 100644
--- a/includes/wizards/class-engagement-wizard.php
+++ b/includes/wizards/class-engagement-wizard.php
@@ -85,51 +85,6 @@ public function register_api_endpoints() {
'sanitize_callback' => 'sanitize_text_field',
]
);
- register_rest_route(
- NEWSPACK_API_NAMESPACE,
- '/wizard/' . $this->slug . '/reader-activation',
- [
- 'methods' => \WP_REST_Server::READABLE,
- 'callback' => [ $this, 'api_get_reader_activation_settings' ],
- 'permission_callback' => [ $this, 'api_permissions_check' ],
- ]
- );
- register_rest_route(
- NEWSPACK_API_NAMESPACE,
- '/wizard/' . $this->slug . '/reader-activation',
- [
- 'methods' => \WP_REST_Server::EDITABLE,
- 'callback' => [ $this, 'api_update_reader_activation_settings' ],
- 'permission_callback' => [ $this, 'api_permissions_check' ],
- ]
- );
- register_rest_route(
- NEWSPACK_API_NAMESPACE,
- '/wizard/' . $this->slug . '/reader-activation/activate',
- [
- 'methods' => \WP_REST_Server::EDITABLE,
- 'callback' => [ $this, 'api_activate_reader_activation' ],
- 'permission_callback' => [ $this, 'api_permissions_check' ],
- ]
- );
- register_rest_route(
- NEWSPACK_API_NAMESPACE,
- '/wizard/' . $this->slug . '/reader-activation/skip-campaign-setup',
- [
- 'methods' => \WP_REST_Server::EDITABLE,
- 'callback' => function( $request ) {
- $skip = $request->get_param( 'skip' );
- $skip_campaign_setup = update_option( static::SKIP_CAMPAIGN_SETUP_OPTION, $skip );
- return rest_ensure_response(
- [
- 'skipped' => $skip,
- 'updated' => $skip_campaign_setup,
- ]
- );
- },
- 'permission_callback' => [ $this, 'api_permissions_check' ],
- ]
- );
$meta_pixel = new Meta_Pixel();
register_rest_route(
@@ -192,91 +147,6 @@ public function register_api_endpoints() {
);
}
- /**
- * Get memberships settings.
- *
- * @return array
- */
- private static function get_memberships_settings() {
- return [
- 'edit_gate_url' => Memberships::get_edit_gate_url(),
- 'gate_status' => \get_post_status( Memberships::get_gate_post_id() ),
- 'plans' => Memberships::get_plans(),
- 'require_all_plans' => Memberships::get_require_all_plans_setting(),
- 'show_on_subscription_tab' => Memberships::get_show_on_subscription_tab_setting(),
- ];
- }
-
- /**
- * Get reader activation settings.
- *
- * @return WP_REST_Response
- */
- public function api_get_reader_activation_settings() {
- return rest_ensure_response(
- [
- 'config' => Reader_Activation::get_settings(),
- 'prerequisites_status' => Reader_Activation::get_prerequisites_status(),
- 'memberships' => self::get_memberships_settings(),
- 'can_esp_sync' => Reader_Activation\ESP_Sync::can_esp_sync( true ),
- ]
- );
- }
-
- /**
- * Update reader activation settings.
- *
- * @param WP_REST_Request $request Request object.
- *
- * @return WP_REST_Response
- */
- public function api_update_reader_activation_settings( $request ) {
- $args = $request->get_params();
- foreach ( $args as $key => $value ) {
- Reader_Activation::update_setting( $key, $value );
- }
-
- // Update Memberships options.
- if ( isset( $args['memberships_require_all_plans'] ) ) {
- Memberships::set_require_all_plans_setting( (bool) $args['memberships_require_all_plans'] );
- }
-
- // Update Memberships options.
- if ( isset( $args['memberships_show_on_subscription_tab'] ) ) {
- Memberships::set_show_on_subscription_tab_setting( (bool) $args['memberships_show_on_subscription_tab'] );
- }
-
- return rest_ensure_response(
- [
- 'config' => Reader_Activation::get_settings(),
- 'prerequisites_status' => Reader_Activation::get_prerequisites_status(),
- 'memberships' => self::get_memberships_settings(),
- 'can_esp_sync' => Reader_Activation\ESP_Sync::can_esp_sync( true ),
- ]
- );
- }
-
- /**
- * Activate reader activation and publish RAS prompts/segments.
- *
- * @param WP_REST_Request $request WP Rest Request object.
- * @return WP_REST_Response
- */
- public function api_activate_reader_activation( WP_REST_Request $request ) {
- $skip_activation = $request->get_param( 'skip_activation' ) ?? false;
- $response = $skip_activation ? true : Reader_Activation::activate();
-
- if ( \is_wp_error( $response ) ) {
- return new \WP_REST_Response( [ 'message' => $response->get_error_message() ], 400 );
- }
-
- if ( true === $response ) {
- Reader_Activation::update_setting( 'enabled', true );
- }
-
- return rest_ensure_response( $response );
- }
-
/**
* Update the Related Posts Max Age setting.
*
@@ -356,35 +226,6 @@ public function enqueue_scripts_and_styles() {
true
);
- $data = [
- 'has_memberships' => class_exists( 'WC_Memberships' ),
- 'reader_activation_url' => \admin_url( 'admin.php?page=newspack-engagement-wizard#/reader-activation' ),
- 'esp_metadata_fields' => Reader_Activation\Sync\Metadata::get_default_fields(),
- ];
-
- if ( method_exists( 'Newspack\Newsletters\Subscription_Lists', 'get_add_new_url' ) ) {
- $data['new_subscription_lists_url'] = \Newspack\Newsletters\Subscription_Lists::get_add_new_url();
- }
-
- if ( method_exists( 'Newspack_Newsletters_Subscription', 'get_lists' ) ) {
- $data['available_newsletter_lists'] = \Newspack_Newsletters_Subscription::get_lists();
- }
-
- $newspack_popups = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'newspack-popups' );
- if ( $newspack_popups->is_configured() ) {
- $data['preview_query_keys'] = $newspack_popups->preview_query_keys();
- $data['preview_post'] = $newspack_popups->preview_post();
- $data['preview_archive'] = $newspack_popups->preview_archive();
- }
-
- $data['is_skipped_campaign_setup'] = get_option( static::SKIP_CAMPAIGN_SETUP_OPTION, '' );
-
- \wp_localize_script(
- 'newspack-engagement-wizard',
- 'newspack_engagement_wizard',
- $data
- );
-
\wp_register_style(
'newspack-engagement-wizard',
Newspack::plugin_url() . '/dist/engagement.css',
@@ -411,15 +252,4 @@ public static function sanitize_categories( $categories ) {
}
return $sanitized;
}
-
- /**
- * Set the newsletters settings url
- *
- * @param string $url URL to the Newspack Newsletters settings page.
- *
- * @return string URL to the Newspack Newsletters settings page.
- */
- public function newsletters_settings_url( $url = '' ) {
- return admin_url( 'admin.php?page=newspack-engagement-wizard#/newsletters' );
- }
}
diff --git a/src/admin/style.scss b/src/admin/style.scss
index c36357de9b..9a73bc1b59 100644
--- a/src/admin/style.scss
+++ b/src/admin/style.scss
@@ -130,6 +130,16 @@ h1 {
/**
* Wizards
*/
+// Only apply styles if there are sections and is immediate descendent.
+.newspack-wizard__content:has(> .newspack-wizard__sections) {
+ margin: 0;
+ max-width: 100%;
+ padding: 0 0 32px;
+
+ * {
+ box-sizing: border-box;
+ }
+}
.newspack-wizard-page {
#screen-meta-links {
position: absolute;
diff --git a/src/wizards/engagement/components/active-campaign.js b/src/wizards/audience/components/active-campaign.js
similarity index 100%
rename from src/wizards/engagement/components/active-campaign.js
rename to src/wizards/audience/components/active-campaign.js
diff --git a/src/wizards/engagement/components/mailchimp.js b/src/wizards/audience/components/mailchimp.js
similarity index 100%
rename from src/wizards/engagement/components/mailchimp.js
rename to src/wizards/audience/components/mailchimp.js
diff --git a/src/wizards/engagement/components/metadata-fields.js b/src/wizards/audience/components/metadata-fields.js
similarity index 100%
rename from src/wizards/engagement/components/metadata-fields.js
rename to src/wizards/audience/components/metadata-fields.js
diff --git a/src/wizards/engagement/components/prerequisite.tsx b/src/wizards/audience/components/prerequisite.tsx
similarity index 68%
rename from src/wizards/engagement/components/prerequisite.tsx
rename to src/wizards/audience/components/prerequisite.tsx
index b11c25be77..9431f28ba8 100644
--- a/src/wizards/engagement/components/prerequisite.tsx
+++ b/src/wizards/audience/components/prerequisite.tsx
@@ -7,10 +7,8 @@ import { ExternalLink } from '@wordpress/components';
/**
* Internal dependencies
*/
-import { PrequisiteProps } from './types';
import { ActionCard, Button, Grid, TextControl } from '../../../components/src';
import { HANDOFF_KEY } from '../../../components/src/consts';
-import type { Config, ConfigKey } from './types';
/**
* Expandable ActionCard for RAS prerequisites checklist.
@@ -62,15 +60,27 @@ export default function Prerequisite( {
{ fieldKeys.map( fieldName => {
- if ( ! prerequisite.fields || ! prerequisite.fields[ fieldName ] ) {
+ if (
+ ! prerequisite.fields ||
+ ! prerequisite.fields[ fieldName ]
+ ) {
return undefined;
}
return (
);
} ) }
@@ -82,7 +92,8 @@ export default function Prerequisite( {
fieldKeys.forEach( fieldName => {
if ( config[ fieldName ] ) {
// @ts-ignore - not sure what's the issue here.
- dataToSave[ fieldName ] = config[ fieldName ];
+ dataToSave[ fieldName ] =
+ config[ fieldName ];
}
} );
saveConfig( dataToSave );
@@ -92,10 +103,21 @@ export default function Prerequisite( {
{ inFlight
? __( 'Saving…', 'newspack-plugin' )
: sprintf(
- // Translators: Save or Update settings.
- __( '%s settings', 'newspack-plugin' ),
- isValid ? __( 'Update', 'newspack-plugin' ) : __( 'Save', 'newspack-plugin' )
- ) }
+ // Translators: Save or Update settings.
+ __(
+ '%s settings',
+ 'newspack-plugin'
+ ),
+ isValid
+ ? __(
+ 'Update',
+ 'newspack-plugin'
+ )
+ : __(
+ 'Save',
+ 'newspack-plugin'
+ )
+ ) }
@@ -106,7 +128,9 @@ export default function Prerequisite( {
href && prerequisite.action_text && (
- { ( ! prerequisite.hasOwnProperty( 'action_enabled' ) ||
+ { ( ! prerequisite.hasOwnProperty(
+ 'action_enabled'
+ ) ||
prerequisite.action_enabled ) && (
- ) }
- { prerequisite.hasOwnProperty( 'action_enabled' ) && ! prerequisite.action_enabled && (
-
) }
+ { prerequisite.hasOwnProperty( 'action_enabled' ) &&
+ ! prerequisite.action_enabled && (
+
+ ) }
)
@@ -159,7 +195,9 @@ export default function Prerequisite( {
let status = __( 'Pending', 'newspack-plugin' );
if ( isValid ) {
status = `${ __( 'Ready', 'newspack-plugin' ) } ${
- prerequisite.is_skipped ? `(${ __( 'Skipped', 'newspack-plugin' ) })` : ''
+ prerequisite.is_skipped
+ ? `(${ __( 'Skipped', 'newspack-plugin' ) })`
+ : ''
}`;
}
if ( prerequisite.is_unavailable ) {
diff --git a/src/wizards/audience/components/prompt.tsx b/src/wizards/audience/components/prompt.tsx
new file mode 100644
index 0000000000..7715b89320
--- /dev/null
+++ b/src/wizards/audience/components/prompt.tsx
@@ -0,0 +1,563 @@
+/* eslint-disable no-nested-ternary */
+
+/**
+ * WordPress dependencies
+ */
+import { __, sprintf } from '@wordpress/i18n';
+import {
+ BaseControl,
+ CheckboxControl,
+ ExternalLink,
+ Path,
+ SVG,
+ TextareaControl,
+} from '@wordpress/components';
+import apiFetch from '@wordpress/api-fetch';
+import { Fragment, useEffect, useState } from '@wordpress/element';
+
+/**
+ * External dependencies
+ */
+import { stringify } from 'qs';
+
+/**
+ * Internal dependencies
+ */
+import {
+ ActionCard,
+ Button,
+ Grid,
+ ImageUpload,
+ Notice,
+ TextControl,
+ WebPreview,
+ hooks,
+} from '../../../components/src';
+
+type Attachment = {
+ id?: number;
+ source_url?: string;
+ url: string;
+};
+
+// Note: Schema and types for the `prompt` prop is defined in Newspack Campaigns: https://github.com/Automattic/newspack-popups/blob/trunk/includes/schemas/class-prompts.php
+export default function Prompt( {
+ inFlight,
+ prompt,
+ setInFlight,
+ setPrompts,
+}: PromptProps ) {
+ const [ values, setValues ] = useState<
+ InputValues | Record< string, never >
+ >( {} );
+ const [ error, setError ] = useState< false | { message: string } >(
+ false
+ );
+ const [ isDirty, setIsDirty ] = useState< boolean >( false );
+ const [ success, setSuccess ] = useState< false | string >( false );
+ const [ image, setImage ] = useState< null | Attachment >( null );
+ const [ isSavingFromPreview, setIsSavingFromPreview ] = useState( false );
+
+ useEffect( () => {
+ if ( Array.isArray( prompt?.user_input_fields ) ) {
+ const fields = { ...values };
+ prompt.user_input_fields.forEach( ( field: InputField ) => {
+ fields[ field.name ] = field.value || field.default;
+ } );
+ setValues( fields );
+ }
+
+ if ( prompt.featured_image_id ) {
+ setInFlight( true );
+ apiFetch< Attachment >( {
+ path: `/wp/v2/media/${ prompt.featured_image_id }`,
+ } )
+ .then( ( attachment: Attachment ) => {
+ if ( attachment?.source_url || attachment?.url ) {
+ setImage( {
+ url: attachment.source_url || attachment.url,
+ } );
+ }
+ } )
+ .catch( setError )
+ .finally( () => {
+ setInFlight( false );
+ } );
+ }
+ }, [ prompt ] );
+
+ // Clear success message after a few seconds.
+ useEffect( () => {
+ setTimeout( () => setSuccess( false ), 5000 );
+ }, [ success ] );
+
+ const previewIcon = (
+
+ );
+
+ const getPreviewUrl = ( {
+ options,
+ slug,
+ }: {
+ options: PromptOptions;
+ slug: string;
+ } ) => {
+ const { placement, trigger_type: triggerType } = options;
+ const previewQueryKeys =
+ window.newspackAudienceConfiguration.preview_query_keys;
+ const abbreviatedKeys = { preset: slug, values };
+ const optionsKeys = Object.keys(
+ options
+ ) as Array< PromptOptionsBaseKey >;
+ optionsKeys.forEach( key => {
+ if ( previewQueryKeys.hasOwnProperty( key ) ) {
+ // @ts-ignore To be fixed in the future perhaps.
+ abbreviatedKeys[ previewQueryKeys[ key ] ] = options[ key ];
+ }
+ } );
+
+ let previewURL = '/';
+ if (
+ 'archives' === placement &&
+ window.newspackAudienceConfiguration?.preview_archive
+ ) {
+ previewURL = window.newspackAudienceConfiguration.preview_archive;
+ } else if (
+ ( 'inline' === placement || 'scroll' === triggerType ) &&
+ window &&
+ window.newspackAudienceConfiguration?.preview_post
+ ) {
+ previewURL = window.newspackAudienceConfiguration?.preview_post;
+ }
+
+ return `${ previewURL }?${ stringify( { ...abbreviatedKeys } ) }`;
+ };
+
+ const unblock = hooks.usePrompt(
+ isDirty,
+ __( 'You have unsaved changes. Discard changes?', 'newspack-plugin' )
+ );
+
+ const savePrompt = ( slug: string, data: InputValues ) => {
+ return new Promise< void >( ( res, rej ) => {
+ if ( unblock ) {
+ unblock();
+ }
+ setError( false );
+ setSuccess( false );
+ setInFlight( true );
+ apiFetch< [ PromptType ] >( {
+ path: '/newspack-popups/v1/reader-activation/campaign',
+ method: 'post',
+ data: {
+ slug,
+ data,
+ },
+ } )
+ .then( ( fetchedPrompts: Array< PromptType > ) => {
+ setPrompts( fetchedPrompts );
+ setSuccess( __( 'Prompt saved.', 'newspack-plugin' ) );
+ setIsDirty( false );
+ res();
+ } )
+ .catch( err => {
+ setError( err );
+ rej( err );
+ } )
+ .finally( () => {
+ setInFlight( false );
+ } );
+ } );
+ };
+
+ const helpInfo = prompt.help_info || null;
+
+ return (
+
+ {
+
+
+ { prompt.user_input_fields.map(
+ ( field: InputField ) => (
+ // @ts-ignore TS doesn't like Fragments when used in a map function in this way.
+
+ { 'array' === field.type &&
+ Array.isArray( field.options ) && (
+
+ { field.options.map( option => (
+
+ -1
+ }
+ onChange={ (
+ value: boolean
+ ) => {
+ const toUpdate =
+ {
+ ...values,
+ };
+ if (
+ ! value &&
+ toUpdate[
+ field
+ .name
+ // @ts-ignore To be fixed in the future perhaps.
+ ].indexOf(
+ option.id
+ ) > -1
+ ) {
+ toUpdate[
+ field.name
+ // @ts-ignore To be fixed in the future perhaps.
+ ].value =
+ toUpdate[
+ field
+ .name
+ // @ts-ignore To be fixed in the future perhaps.
+ ].splice(
+ toUpdate[
+ field
+ .name
+ // @ts-ignore To be fixed in the future perhaps.
+ ].indexOf(
+ option.id
+ ),
+ 1
+ );
+ }
+ if (
+ value &&
+ toUpdate[
+ field
+ .name
+ // @ts-ignore To be fixed in the future perhaps.
+ ].indexOf(
+ option.id
+ ) === -1
+ ) {
+ toUpdate[
+ field
+ .name
+ // @ts-ignore To be fixed in the future perhaps.
+ ].push(
+ option.id
+ );
+ }
+ setValues(
+ toUpdate
+ );
+ setIsDirty(
+ true
+ );
+ } }
+ />
+
+ ) ) }
+
+ ) }
+ { 'string' === field.type &&
+ field.max_length &&
+ Array.isArray( values ) &&
+ 150 < field.max_length && (
+ {
+ if (
+ value.length >
+ // @ts-ignore There's a check for max_length above.
+ field.max_length
+ ) {
+ return;
+ }
+
+ const toUpdate = {
+ ...values,
+ };
+ toUpdate[ field.name ] =
+ value;
+ setValues( toUpdate );
+ setIsDirty( true );
+ } }
+ placeholder={
+ typeof field.default ===
+ 'string'
+ ? field.default
+ : ''
+ }
+ rows={ 10 }
+ // @ts-ignore TS still does not see it as a string.
+ value={
+ typeof values[
+ field.name
+ ] === 'string'
+ ? values[ field.name ]
+ : ''
+ }
+ />
+ ) }
+ { 'string' === field.type &&
+ field.max_length &&
+ 150 >= field.max_length && (
+ {
+ if (
+ value.length >
+ // @ts-ignore There's a check for max_length above.
+ field.max_length
+ ) {
+ return;
+ }
+
+ const toUpdate = {
+ ...values,
+ };
+ toUpdate[ field.name ] =
+ value;
+ setValues( toUpdate );
+ setIsDirty( true );
+ } }
+ placeholder={ field.default }
+ value={
+ values[ field.name ] || ''
+ }
+ />
+ ) }
+ { 'int' === field.type &&
+ 'featured_image_id' === field.name && (
+
+ {
+ const toUpdate = {
+ ...values,
+ };
+ toUpdate[ field.name ] =
+ attachment?.id || 0;
+ if (
+ toUpdate[
+ field.name
+ ] !==
+ values[ field.name ]
+ ) {
+ }
+ setValues( toUpdate );
+ setIsDirty( true );
+ if ( attachment?.url ) {
+ setImage(
+ attachment
+ );
+ } else {
+ setImage( null );
+ }
+ } }
+ />
+
+ ) }
+
+ )
+ ) }
+ { error && (
+
+ ) }
+ { success && (
+
+ ) }
+
+
+ void;
+ } ) => (
+
+ ) }
+ />
+
+
+ { helpInfo && (
+
+ { helpInfo.screenshot && (
+

+ ) }
+ { helpInfo.description && (
+
+ { ' ' }
+ { helpInfo.url && (
+
+ { __(
+ 'Learn more',
+ 'newspack-plugin'
+ ) }
+
+ ) }
+
+ ) }
+ { helpInfo.recommendations && (
+ <>
+
+ { __(
+ 'We recommend',
+ 'newspack-plugin'
+ ) }
+
+
+ { helpInfo.recommendations.map(
+ ( recommendation, index ) => (
+ -
+
+
+ )
+ ) }
+
+ >
+ ) }
+
+ ) }
+
+ }
+
+ );
+}
diff --git a/src/wizards/engagement/components/types.ts b/src/wizards/audience/types/index.d.ts
similarity index 79%
rename from src/wizards/engagement/components/types.ts
rename to src/wizards/audience/types/index.d.ts
index dc577e72e3..0e2fa50cca 100644
--- a/src/wizards/engagement/components/types.ts
+++ b/src/wizards/audience/types/index.d.ts
@@ -2,7 +2,7 @@
* Types for the Prequisite component.
*/
-export type PromptOptionsBase = {
+type PromptOptionsBase = {
background_color: string;
display_title: boolean;
hide_border: boolean;
@@ -26,27 +26,7 @@ export type PromptOptionsBase = {
utm_suppression: string;
};
-export type PromptOptionsBaseKey = keyof PromptOptionsBase;
-
-declare global {
- interface Window {
- // Localized data on engagement wizard script.
- newspack_engagement_wizard: {
- has_reader_activation: boolean;
- has_memberships: boolean;
- new_subscription_lists_url: string;
- reader_activation_url: string;
- preview_query_keys: {
- [ K in PromptOptionsBaseKey ]: string;
- };
- preview_post: string;
- preview_archive: string;
- };
- newspack_reader_revenue: {
- can_use_name_your_price: boolean;
- };
- }
-}
+type PromptOptionsBaseKey = keyof PromptOptionsBase;
// Available transactional email slugs.
type EmailSlugs =
@@ -57,7 +37,7 @@ type EmailSlugs =
| 'reader-activation-delete-account';
// RAS config inherited from RAS wizard view.
-export type Config = {
+type Config = {
enabled?: boolean;
enabled_account_link?: boolean;
account_link_menu_locations?: [ 'tertiary-menu' ];
@@ -88,10 +68,10 @@ export type Config = {
contact_email_address?: string;
};
-export type ConfigKey = keyof Config;
+type ConfigKey = keyof Config;
// Props for the Prequisite component.
-export type PrequisiteProps = {
+type PrequisiteProps = {
config: Config;
getSharedProps: (
configKey: string,
@@ -131,7 +111,7 @@ export type PrequisiteProps = {
};
};
-export type InputField = {
+type InputField = {
name: string;
type: string;
label: string;
@@ -147,7 +127,7 @@ export type InputField = {
};
// Schema is defined in Newspack Campaigns: https://github.com/Automattic/newspack-popups/blob/trunk/includes/schemas/class-prompts.php
-export type PromptType = {
+type PromptType = {
status: string;
slug: string;
title: string;
@@ -157,7 +137,7 @@ export type PromptType = {
{
id: number;
name: string;
- }
+ },
];
options: PromptOptions;
user_input_fields: [ InputField ];
@@ -170,7 +150,7 @@ export type PromptType = {
ready?: boolean;
};
-export type PromptOptions = PromptOptionsBase & {
+type PromptOptions = PromptOptionsBase & {
post_types: Array< string >;
archive_page_types: Array< string >;
additional_classes: string;
@@ -178,46 +158,45 @@ export type PromptOptions = PromptOptionsBase & {
{
id: number;
name: string;
- }
+ },
];
excluded_tags: [
{
id: number;
name: string;
- }
+ },
];
categories: [
{
id: number;
name: string;
- }
+ },
];
tags: [
{
id: number;
name: string;
- }
+ },
];
campaign_groups: [
{
id: number;
name: string;
- }
+ },
];
};
-export type Attachment = {
- id?: number;
- source_url?: string;
- url: string;
-};
-
-export type InputValues = {
- [ fieldName: string ]: string | number | Array< string > | Array< number > | boolean;
+type InputValues = {
+ [ fieldName: string ]:
+ | string
+ | number
+ | Array< string >
+ | Array< number >
+ | boolean;
};
// Props for the Prompt component.
-export type PromptProps = {
+type PromptProps = {
inFlight: boolean;
setInFlight: ( inFlight: boolean ) => void;
prompt: PromptType;
diff --git a/src/wizards/audience/views/campaigns/index.js b/src/wizards/audience/views/campaigns/index.js
new file mode 100644
index 0000000000..f59abe7bbe
--- /dev/null
+++ b/src/wizards/audience/views/campaigns/index.js
@@ -0,0 +1,23 @@
+/**
+ * Configuration
+ */
+
+/**
+ * WordPress dependencies.
+ */
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import { withWizard } from '../../../../components/src';
+
+function AudienceCampaigns() {
+ return (
+
+ { __( 'Audience Campaigns - Coming Soon!', 'newspack-plugin' ) }
+
+ );
+}
+
+export default withWizard( AudienceCampaigns );
diff --git a/src/wizards/engagement/views/reader-activation/campaign.js b/src/wizards/audience/views/configuration/campaign.js
similarity index 71%
rename from src/wizards/engagement/views/reader-activation/campaign.js
rename to src/wizards/audience/views/configuration/campaign.js
index 34ea029edb..d70d1f52b6 100644
--- a/src/wizards/engagement/views/reader-activation/campaign.js
+++ b/src/wizards/audience/views/configuration/campaign.js
@@ -1,4 +1,4 @@
-/* global newspack_engagement_wizard */
+/* global newspackAudienceConfiguration */
/**
* WordPress dependencies
@@ -10,10 +10,10 @@ import { useEffect, useState } from '@wordpress/element';
/**
* Internal dependencies
*/
+import WizardsTab from '../../../wizards-tab';
import {
Button,
Notice,
- SectionHeader,
Waiting,
withWizardScreen,
utils,
@@ -25,7 +25,8 @@ import './style.scss';
const { useHistory } = Router;
export default withWizardScreen( () => {
- const { is_skipped_campaign_setup, reader_activation_url } = newspack_engagement_wizard;
+ const { is_skipped_campaign_setup, reader_activation_url } =
+ newspackAudienceConfiguration;
const [ inFlight, setInFlight ] = useState( false );
const [ error, setError ] = useState( false );
@@ -71,18 +72,21 @@ export default withWizardScreen( () => {
setSkipped( { ...skipped, status: 'pending' } );
try {
const request = await apiFetch( {
- path: '/newspack/v1/wizard/newspack-engagement-wizard/reader-activation/skip-campaign-setup',
+ path: '/newspack/v1/wizard/newspack-audience-configuration/reader-activation/skip-campaign-setup',
method: 'POST',
data: { skip: ! skipped.isSkipped },
} );
if ( ! request.updated ) {
- setError( { message: __( 'Server not updated', 'newspack-plugin' ) } );
+ setError( {
+ message: __( 'Server not updated', 'newspack-plugin' ),
+ } );
setSkipped( { isSkipped: false, status: '' } );
return;
}
setSkipped( { isSkipped: Boolean( request.skipped ), status: '' } );
- newspack_engagement_wizard.is_skipped_campaign_setup = request.skipped ? '1' : '';
- history.push( '/reader-activation/complete' );
+ newspackAudienceConfiguration.is_skipped_campaign_setup =
+ request.skipped ? '1' : '';
+ history.push( '/complete' );
} catch ( err ) {
setError( err );
setSkipped( { isSkipped: false, status: '' } );
@@ -101,17 +105,22 @@ export default withWizardScreen( () => {
}, [ prompts ] );
return (
-
-
+
{ error && (
) }
@@ -134,27 +143,37 @@ export default withWizardScreen( () => {
-
-
+
);
} );
diff --git a/src/wizards/engagement/views/reader-activation/complete.js b/src/wizards/audience/views/configuration/complete.js
similarity index 74%
rename from src/wizards/engagement/views/reader-activation/complete.js
rename to src/wizards/audience/views/configuration/complete.js
index e04124527b..a04a2746ab 100644
--- a/src/wizards/engagement/views/reader-activation/complete.js
+++ b/src/wizards/audience/views/configuration/complete.js
@@ -1,4 +1,4 @@
-/* global newspack_engagement_wizard */
+/* global newspackAudienceConfiguration */
/**
* WordPress dependencies
@@ -11,9 +11,9 @@ import { useEffect, useRef, useState } from '@wordpress/element';
/**
* Internal dependencies
*/
+import WizardsTab from '../../../wizards-tab';
import {
Button,
- SectionHeader,
withWizardScreen,
Card,
Notice,
@@ -71,7 +71,7 @@ export default withWizardScreen( () => {
const [ activationSteps, setActivationSteps ] = useState(
Object.values( DEFAULT_ACTIVATION_STEPS )
);
- const { reader_activation_url, is_skipped_campaign_setup = '' } = newspack_engagement_wizard;
+ const { reader_activation_url, is_skipped_campaign_setup = '' } = newspackAudienceConfiguration;
const isSkippedCampaignSetup = is_skipped_campaign_setup === '1';
useEffect( () => {
@@ -125,7 +125,7 @@ export default withWizardScreen( () => {
try {
setCompleted(
await apiFetch( {
- path: '/newspack/v1/wizard/newspack-engagement-wizard/reader-activation/activate',
+ path: '/newspack/v1/wizard/newspack-audience-configuration/reader-activation/activate',
method: 'post',
data: {
skip_activation: isSkippedCampaignSetup,
@@ -139,9 +139,9 @@ export default withWizardScreen( () => {
return (
-
(
+ description={
<>
{ __(
'An easy way to let your readers register for your site, sign up for newsletters, or become donors and paid members. ',
@@ -153,46 +153,48 @@ export default withWizardScreen( () => {
{ __( 'Learn more', 'newspack-plugin' ) }
>
- ) }
- />
- { inFlight && (
-
-
-
- ) }
- { ! inFlight && (
-
- { __( "You're all set to enable Reader Activation!", 'newspack-plugin' ) }
- { __( 'This is what will happen next:', 'newspack-plugin' ) }
-
-
-
-
-
- { error && (
-
+
+ { inFlight && (
+
+
- ) }
+
+ ) }
+ { ! inFlight && (
+
+ { __( "You're all set to enable Reader Activation!", 'newspack-plugin' ) }
+ { __( 'This is what will happen next:', 'newspack-plugin' ) }
+
+
+
+
+
+ { error && (
+
+ ) }
-
- activate() }>
- { __( 'Enable Reader Activation', 'newspack-plugin' ) }
-
+
+ activate() }>
+ { __( 'Enable Reader Activation', 'newspack-plugin' ) }
+
+
-
- ) }
-
-
- { __( 'Back', 'newspack-plugin' ) }
-
-
+ ) }
+
+
+ { __( 'Back', 'newspack-plugin' ) }
+
+
+
);
} );
diff --git a/src/wizards/audience/views/configuration/index.js b/src/wizards/audience/views/configuration/index.js
new file mode 100644
index 0000000000..356717b50a
--- /dev/null
+++ b/src/wizards/audience/views/configuration/index.js
@@ -0,0 +1,72 @@
+/**
+ * Configuration
+ */
+
+/**
+ * WordPress dependencies.
+ */
+import { __ } from '@wordpress/i18n';
+import { Component, Fragment } from '@wordpress/element';
+
+/**
+ * Internal dependencies.
+ */
+import Main from './settings';
+import Campaign from './campaign';
+import Complete from './complete';
+import { withWizard } from '../../../../components/src';
+import Router from '../../../../components/src/proxied-imports/router';
+
+const { HashRouter, Redirect, Route, Switch } = Router;
+
+class AudienceConfiguration extends Component {
+ /**
+ * Render
+ */
+ render() {
+ const { pluginRequirements, wizardApiFetch } = this.props;
+
+ const props = {
+ headerText: __(
+ 'Audience Development / Configuration',
+ 'newspack-plugin'
+ ),
+ tabbedNavigation: [],
+ wizardApiFetch,
+ };
+ return (
+
+
+
+ { pluginRequirements }
+ }
+ />
+ (
+
+ ) }
+ />
+ }
+ />
+
+
+
+
+ );
+ }
+}
+
+export default withWizard( AudienceConfiguration );
+
\ No newline at end of file
diff --git a/src/wizards/engagement/views/reader-activation/index.js b/src/wizards/audience/views/configuration/settings.js
similarity index 61%
rename from src/wizards/engagement/views/reader-activation/index.js
rename to src/wizards/audience/views/configuration/settings.js
index e7a68efad9..9fe6f4f30e 100644
--- a/src/wizards/engagement/views/reader-activation/index.js
+++ b/src/wizards/audience/views/configuration/settings.js
@@ -1,4 +1,4 @@
-/* global newspack_engagement_wizard */
+/* global newspackAudienceConfiguration */
/**
* WordPress dependencies
*/
@@ -21,6 +21,7 @@ import {
Waiting,
withWizardScreen,
} from '../../../../components/src';
+import WizardsTab from '../../../wizards-tab';
import Prerequisite from '../../components/prerequisite';
import ActiveCampaign from '../../components/active-campaign';
import MetadataFields from '../../components/metadata-fields';
@@ -47,7 +48,7 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
setError( false );
setInFlight( true );
apiFetch( {
- path: '/newspack/v1/wizard/newspack-engagement-wizard/reader-activation',
+ path: '/newspack/v1/wizard/newspack-audience-configuration/reader-activation',
} )
.then( ( { config: fetchedConfig, prerequisites_status, memberships, can_esp_sync } ) => {
setPrerequisites( prerequisites_status );
@@ -62,7 +63,7 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
setError( false );
setInFlight( true );
wizardApiFetch( {
- path: '/newspack/v1/wizard/newspack-engagement-wizard/reader-activation',
+ path: '/newspack/v1/wizard/newspack-audience-configuration/reader-activation',
method: 'post',
quiet: true,
data,
@@ -85,7 +86,7 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
}, [] );
useEffect( () => {
apiFetch( {
- path: '/newspack/v1/wizard/newspack-engagement-wizard/newsletters',
+ path: '/newspack/v1/wizard/newspack-newsletters/settings',
} ).then( data => {
setIsMailchimp(
data?.settings?.newspack_newsletters_service_provider?.value === 'mailchimp'
@@ -160,30 +161,39 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
};
return (
- <>
- (
- <>
- { __(
- 'Newspack’s Reader Activation system is a set of features that aim to increase reader loyalty, promote engagement, and drive revenue. ',
- 'newspack-plugin'
- ) }
-
- { __( 'Learn more', 'newspack-plugin' ) }
-
- >
- ) }
- />
+
+ { __(
+ "Newspack's Reader Activation system is a set of features that aim to increase reader loyalty, promote engagement, and drive revenue. ",
+ 'newspack-plugin'
+ ) }
+
+ { __( 'Learn more', 'newspack-plugin' ) }
+
+ >
+ }
+ >
{ error && (
) }
{ 0 < missingPlugins.length && (
) }
@@ -197,7 +207,13 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
/>
) }
{ prerequisites && allReady && config.enabled && (
-
+
) }
{ ! prerequisites && (
<>
@@ -228,56 +244,88 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
{ config.enabled && (
<>
- setShowAdvanced( ! showAdvanced ) }>
+ setShowAdvanced( ! showAdvanced ) }
+ >
{ sprintf(
// Translators: Show or Hide advanced settings.
__( '%s Advanced Settings', 'newspack-plugin' ),
- showAdvanced ? __( 'Hide', 'newspack-plugin' ) : __( 'Show', 'newspack-plugin' )
+ showAdvanced
+ ? __( 'Hide', 'newspack-plugin' )
+ : __( 'Show', 'newspack-plugin' )
) }
>
) }
{ showAdvanced && (
- { newspack_engagement_wizard.has_memberships && membershipsConfig ? (
+ { newspackAudienceConfiguration.has_memberships &&
+ membershipsConfig ? (
<>
- { membershipsConfig?.plans && 1 < membershipsConfig.plans.length && (
-
- setMembershipsConfig( { ...membershipsConfig, require_all_plans: value } )
- }
- toggleChecked={ membershipsConfig.require_all_plans }
- />
- ) }
+ { membershipsConfig?.plans &&
+ 1 < membershipsConfig.plans.length && (
+
+ setMembershipsConfig( {
+ ...membershipsConfig,
+ require_all_plans: value,
+ } )
+ }
+ toggleChecked={
+ membershipsConfig.require_all_plans
+ }
+ />
+ ) }
- setMembershipsConfig( { ...membershipsConfig, show_on_subscription_tab: value } )
+ setMembershipsConfig( {
+ ...membershipsConfig,
+ show_on_subscription_tab: value,
+ } )
+ }
+ toggleChecked={
+ membershipsConfig.show_on_subscription_tab
}
- toggleChecked={ membershipsConfig.show_on_subscription_tab }
/>
>
@@ -286,7 +334,10 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
{ emails?.length > 0 && (
<>
{
titleLink={ email.edit_link }
href={ email.edit_link }
description={ email.description }
- actionText={ __( 'Edit', 'newspack-plugin' ) }
+ actionText={ __(
+ 'Edit',
+ 'newspack-plugin'
+ ) }
isSmall
/>
) ) }
@@ -307,35 +361,55 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
>
) }
-
+
updateConfig( 'use_custom_lists', value ) }
+ toggleOnChange={ value =>
+ updateConfig( 'use_custom_lists', value )
+ }
/>
{ config.use_custom_lists && (
updateConfig( 'newsletter_lists', selected ) }
+ onChange={ selected =>
+ updateConfig( 'newsletter_lists', selected )
+ }
/>
) }
{
) }
hasGreyHeader={ true }
isMedium
- title={ __( 'Sync contacts to ESP', 'newspack-plugin' ) }
+ title={ __(
+ 'Sync contacts to ESP',
+ 'newspack-plugin'
+ ) }
toggleChecked={ config.sync_esp }
- toggleOnChange={ value => updateConfig( 'sync_esp', value ) }
+ toggleOnChange={ value =>
+ updateConfig( 'sync_esp', value )
+ }
>
{ config.sync_esp && (
<>
- { 0 < Object.keys(espSyncErrors).length && (
+ { 0 < Object.keys( espSyncErrors ).length && (
) }
{ isMailchimp && (
{
if ( key === 'audienceId' ) {
- updateConfig( 'mailchimp_audience_id', value );
+ updateConfig(
+ 'mailchimp_audience_id',
+ value
+ );
}
- if ( key === 'readerDefaultStatus' ) {
- updateConfig( 'mailchimp_reader_default_status', value );
+ if (
+ key === 'readerDefaultStatus'
+ ) {
+ updateConfig(
+ 'mailchimp_reader_default_status',
+ value
+ );
}
} }
/>
) }
{ isActiveCampaign && (
{
if ( key === 'masterList' ) {
- updateConfig( 'active_campaign_master_list', value );
+ updateConfig(
+ 'active_campaign_master_list',
+ value
+ );
}
} }
/>
) }
{
>
) }
+ {/* TODO: Add Platform from `/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/`*/}
+ {/* TODO: Add Stripe Setup from `/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/stripe-setup`*/}
+ {/* TODO: Add Saleforce Settings from `/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/salesforce`*/}
{
if ( config.sync_esp ) {
- if (isMailchimp && config.mailchimp_audience_id === '') {
+ if (
+ isMailchimp &&
+ config.mailchimp_audience_id === ''
+ ) {
// eslint-disable-next-line no-alert
- alert( __( 'Please select a Mailchimp Audience ID.', 'newspack-plugin' ) );
- return
+ alert(
+ __(
+ 'Please select a Mailchimp Audience ID.',
+ 'newspack-plugin'
+ )
+ );
+ return;
}
- if (isActiveCampaign && config.active_campaign_master_list === '') {
+ if (
+ isActiveCampaign &&
+ config.active_campaign_master_list ===
+ ''
+ ) {
// eslint-disable-next-line no-alert
- alert( __( 'Please select an ActiveCampaign Master List.', 'newspack-plugin' ) );
- return
+ alert(
+ __(
+ 'Please select an ActiveCampaign Master List.',
+ 'newspack-plugin'
+ )
+ );
+ return;
}
}
saveConfig( {
newsletters_label: config.newsletters_label, // TODO: Deprecate this in favor of user input via the prompt copy wizard.
- mailchimp_audience_id: config.mailchimp_audience_id,
- mailchimp_reader_default_status: config.mailchimp_reader_default_status,
- active_campaign_master_list: config.active_campaign_master_list,
- memberships_require_all_plans: membershipsConfig.require_all_plans,
- memberships_show_on_subscription_tab: membershipsConfig.show_on_subscription_tab,
+ mailchimp_audience_id:
+ config.mailchimp_audience_id,
+ mailchimp_reader_default_status:
+ config.mailchimp_reader_default_status,
+ active_campaign_master_list:
+ config.active_campaign_master_list,
+ memberships_require_all_plans:
+ membershipsConfig.require_all_plans,
+ memberships_show_on_subscription_tab:
+ membershipsConfig.show_on_subscription_tab,
use_custom_lists: config.use_custom_lists,
newsletter_lists: config.newsletter_lists,
sync_esp: config.sync_esp,
@@ -428,11 +553,14 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
} }
disabled={ inFlight }
>
- { __( 'Save advanced settings', 'newspack-plugin' ) }
+ { __(
+ 'Save Settings',
+ 'newspack-plugin'
+ ) }
) }
- >
+
);
} );
diff --git a/src/wizards/engagement/views/reader-activation/style.scss b/src/wizards/audience/views/configuration/style.scss
similarity index 100%
rename from src/wizards/engagement/views/reader-activation/style.scss
rename to src/wizards/audience/views/configuration/style.scss
diff --git a/src/wizards/engagement/components/prompt.tsx b/src/wizards/engagement/components/prompt.tsx
deleted file mode 100644
index f51a2e27b7..0000000000
--- a/src/wizards/engagement/components/prompt.tsx
+++ /dev/null
@@ -1,373 +0,0 @@
-/* eslint-disable no-nested-ternary */
-
-/**
- * WordPress dependencies
- */
-import { __, sprintf } from '@wordpress/i18n';
-import {
- BaseControl,
- CheckboxControl,
- ExternalLink,
- Path,
- SVG,
- TextareaControl,
-} from '@wordpress/components';
-import apiFetch from '@wordpress/api-fetch';
-import { Fragment, useEffect, useState } from '@wordpress/element';
-
-/**
- * External dependencies
- */
-import { stringify } from 'qs';
-
-/**
- * Internal dependencies
- */
-import {
- Attachment,
- InputField,
- InputValues,
- PromptOptions,
- PromptProps,
- PromptType,
- PromptOptionsBaseKey,
-} from './types';
-import {
- ActionCard,
- Button,
- Grid,
- ImageUpload,
- Notice,
- TextControl,
- WebPreview,
- hooks,
-} from '../../../components/src';
-
-// Note: Schema and types for the `prompt` prop is defined in Newspack Campaigns: https://github.com/Automattic/newspack-popups/blob/trunk/includes/schemas/class-prompts.php
-export default function Prompt( { inFlight, prompt, setInFlight, setPrompts }: PromptProps ) {
- const [ values, setValues ] = useState< InputValues | Record< string, never > >( {} );
- const [ error, setError ] = useState< false | { message: string } >( false );
- const [ isDirty, setIsDirty ] = useState< boolean >( false );
- const [ success, setSuccess ] = useState< false | string >( false );
- const [ image, setImage ] = useState< null | Attachment >( null );
- const [ isSavingFromPreview, setIsSavingFromPreview ] = useState( false );
-
- useEffect( () => {
- if ( Array.isArray( prompt?.user_input_fields ) ) {
- const fields = { ...values };
- prompt.user_input_fields.forEach( ( field: InputField ) => {
- fields[ field.name ] = field.value || field.default;
- } );
- setValues( fields );
- }
-
- if ( prompt.featured_image_id ) {
- setInFlight( true );
- apiFetch< Attachment >( {
- path: `/wp/v2/media/${ prompt.featured_image_id }`,
- } )
- .then( ( attachment: Attachment ) => {
- if ( attachment?.source_url || attachment?.url ) {
- setImage( { url: attachment.source_url || attachment.url } );
- }
- } )
- .catch( setError )
- .finally( () => {
- setInFlight( false );
- } );
- }
- }, [ prompt ] );
-
- // Clear success message after a few seconds.
- useEffect( () => {
- setTimeout( () => setSuccess( false ), 5000 );
- }, [ success ] );
-
- const previewIcon = (
-
- );
-
- const getPreviewUrl = ( { options, slug }: { options: PromptOptions; slug: string } ) => {
- const { placement, trigger_type: triggerType } = options;
- const previewQueryKeys = window.newspack_engagement_wizard.preview_query_keys;
- const abbreviatedKeys = { preset: slug, values };
- const optionsKeys = Object.keys( options ) as Array< PromptOptionsBaseKey >;
- optionsKeys.forEach( key => {
- if ( previewQueryKeys.hasOwnProperty( key ) ) {
- // @ts-ignore To be fixed in the future perhaps.
- abbreviatedKeys[ previewQueryKeys[ key ] ] = options[ key ];
- }
- } );
-
- let previewURL = '/';
- if ( 'archives' === placement && window.newspack_engagement_wizard?.preview_archive ) {
- previewURL = window.newspack_engagement_wizard.preview_archive;
- } else if (
- ( 'inline' === placement || 'scroll' === triggerType ) &&
- window &&
- window.newspack_engagement_wizard?.preview_post
- ) {
- previewURL = window.newspack_engagement_wizard?.preview_post;
- }
-
- return `${ previewURL }?${ stringify( { ...abbreviatedKeys } ) }`;
- };
-
- const unblock = hooks.usePrompt(
- isDirty,
- __( 'You have unsaved changes. Discard changes?', 'newspack-plugin' )
- );
-
- const savePrompt = ( slug: string, data: InputValues ) => {
- return new Promise< void >( ( res, rej ) => {
- if ( unblock ) {
- unblock();
- }
- setError( false );
- setSuccess( false );
- setInFlight( true );
- apiFetch< [ PromptType ] >( {
- path: '/newspack-popups/v1/reader-activation/campaign',
- method: 'post',
- data: {
- slug,
- data,
- },
- } )
- .then( ( fetchedPrompts: Array< PromptType > ) => {
- setPrompts( fetchedPrompts );
- setSuccess( __( 'Prompt saved.', 'newspack-plugin' ) );
- setIsDirty( false );
- res();
- } )
- .catch( err => {
- setError( err );
- rej( err );
- } )
- .finally( () => {
- setInFlight( false );
- } );
- } );
- };
-
- const helpInfo = prompt.help_info || null;
-
- return (
-
- {
-
-
- { prompt.user_input_fields.map( ( field: InputField ) => (
- // @ts-ignore TS doesn't like Fragments when used in a map function in this way.
-
- { 'array' === field.type && Array.isArray( field.options ) && (
-
- { field.options.map( option => (
-
- -1 }
- onChange={ ( value: boolean ) => {
- const toUpdate = { ...values };
- // @ts-ignore To be fixed in the future perhaps.
- if ( ! value && toUpdate[ field.name ].indexOf( option.id ) > -1 ) {
- // @ts-ignore To be fixed in the future perhaps.
- toUpdate[ field.name ].value = toUpdate[ field.name ].splice(
- // @ts-ignore To be fixed in the future perhaps.
- toUpdate[ field.name ].indexOf( option.id ),
- 1
- );
- }
- // @ts-ignore To be fixed in the future perhaps.
- if ( value && toUpdate[ field.name ].indexOf( option.id ) === -1 ) {
- // @ts-ignore To be fixed in the future perhaps.
- toUpdate[ field.name ].push( option.id );
- }
- setValues( toUpdate );
- setIsDirty( true );
- } }
- />
-
- ) ) }
-
- ) }
- { 'string' === field.type && field.max_length && 150 < field.max_length && (
- {
- // @ts-ignore There's a check for max_length above.
- if ( value.length > field.max_length ) {
- return;
- }
-
- const toUpdate = { ...values };
- toUpdate[ field.name ] = value;
- setValues( toUpdate );
- setIsDirty( true );
- } }
- placeholder={ typeof field.default === 'string' ? field.default : '' }
- rows={ 10 }
- // @ts-ignore TS still does not see it as a string.
- value={ typeof values[ field.name ] === 'string' ? values[ field.name ] : '' }
- />
- ) }
- { 'string' === field.type && field.max_length && 150 >= field.max_length && (
- {
- // @ts-ignore There's a check for max_length above.
- if ( value.length > field.max_length ) {
- return;
- }
-
- const toUpdate = { ...values };
- toUpdate[ field.name ] = value;
- setValues( toUpdate );
- setIsDirty( true );
- } }
- placeholder={ field.default }
- value={ values[ field.name ] || '' }
- />
- ) }
- { 'int' === field.type && 'featured_image_id' === field.name && (
-
- {
- const toUpdate = { ...values };
- toUpdate[ field.name ] = attachment?.id || 0;
- if ( toUpdate[ field.name ] !== values[ field.name ] ) {
- }
- setValues( toUpdate );
- setIsDirty( true );
- if ( attachment?.url ) {
- setImage( attachment );
- } else {
- setImage( null );
- }
- } }
- />
-
- ) }
-
- ) ) }
- { error && (
-
- ) }
- { success &&
}
-
- {
- setIsSavingFromPreview( false );
- savePrompt( prompt.slug, values );
- } }
- disabled={ inFlight }
- >
- { inFlight
- ? __( 'Saving…', 'newspack-plugin' )
- : sprintf(
- // Translators: Save or Update settings.
- __( '%s prompt settings', 'newspack-plugin' ),
- prompt.ready
- ? __( 'Update', 'newspack-plugin' )
- : __( 'Save', 'newspack-plugin' )
- ) }
-
- void } ) => (
- showPreview() }
- >
- { __( 'Preview prompt', 'newspack-plugin' ) }
-
- ) }
- />
-
-
- { helpInfo && (
-
- { helpInfo.screenshot &&

}
- { helpInfo.description && (
-
- { ' ' }
- { helpInfo.url && (
-
- { __( 'Learn more', 'newspack-plugin' ) }
-
- ) }
-
- ) }
- { helpInfo.recommendations && (
- <>
-
- { __( 'We recommend', 'newspack-plugin' ) }
-
-
- { helpInfo.recommendations.map( ( recommendation, index ) => (
- -
-
-
- ) ) }
-
- >
- ) }
-
- ) }
-
- }
-
- );
-}
diff --git a/src/wizards/engagement/index.js b/src/wizards/engagement/index.js
index a640b19148..f307a94e1e 100644
--- a/src/wizards/engagement/index.js
+++ b/src/wizards/engagement/index.js
@@ -15,13 +15,7 @@ import { __ } from '@wordpress/i18n';
*/
import { withWizard } from '../../components/src';
import Router from '../../components/src/proxied-imports/router';
-import {
- ReaderActivation,
- ReaderActivationCampaign,
- ReaderActivationComplete,
- Social,
- RelatedContent,
-} from './views';
+import { Social, RelatedContent } from './views';
const { HashRouter, Redirect, Route, Switch } = Router;
@@ -79,14 +73,8 @@ class EngagementWizard extends Component {
const { relatedPostsEnabled, relatedPostsError, relatedPostsMaxAge, relatedPostsUpdated } =
this.state;
- const defaultPath = '/reader-activation';
+ const defaultPath = '/social';
const tabbed_navigation = [
- {
- label: __( 'Reader Activation', 'newspack-plugin' ),
- path: '/reader-activation',
- exact: true,
- activeTabPaths: ['/reader-activation/*'],
- },
{
label: __( 'Social', 'newspack-plugin' ),
path: '/social',
@@ -107,43 +95,6 @@ class EngagementWizard extends Component {
{ pluginRequirements }
- (
-
- ) }
- />
- (
-
- ) }
- />
- (
-
- ) }
- />
= {
/**
* `page` param with `newspack-*`.
@@ -48,6 +46,24 @@ const components: Record< string, any > = {
)
),
},
+ 'newspack-audience-configuration': {
+ label: __( 'Audience Configuration', 'newspack-plugin' ),
+ component: lazy(
+ () =>
+ import(
+ /* webpackChunkName: "audience-wizards" */ './audience/views/configuration'
+ )
+ ),
+ },
+ 'newspack-audience-campaigns': {
+ label: __( 'Audience Campaigns', 'newspack-plugin' ),
+ component: lazy(
+ () =>
+ import(
+ /* webpackChunkName: "audience-wizards" */ './audience/views/campaigns'
+ )
+ ),
+ },
} as const;
const AdminPageLoader = ( { label }: { label: string } ) => {
@@ -82,7 +98,7 @@ const AdminPages = () => {
);
};
-if ( rootElement && ALLOWED_PAGES.includes( pageParam ) ) {
+if ( rootElement && pageParam in components ) {
render( , rootElement );
} else {
// eslint-disable-next-line no-console
diff --git a/src/wizards/newspack/views/dashboard/style.scss b/src/wizards/newspack/views/dashboard/style.scss
index 6970389f0f..990867f699 100644
--- a/src/wizards/newspack/views/dashboard/style.scss
+++ b/src/wizards/newspack/views/dashboard/style.scss
@@ -9,16 +9,6 @@
background-color: colors.$primary-600;
}
-.newspack-wizard__content {
- margin: 0;
- max-width: 100%;
- padding: 0 0 32px;
-
- * {
- box-sizing: border-box;
- }
-}
-
.newspack-dashboard__brand-header {
padding: 40px 0;
diff --git a/src/wizards/newspack/views/settings/connections/index.tsx b/src/wizards/newspack/views/settings/connections/index.tsx
index 0af37e0bf7..74cfc86dba 100644
--- a/src/wizards/newspack/views/settings/connections/index.tsx
+++ b/src/wizards/newspack/views/settings/connections/index.tsx
@@ -34,12 +34,17 @@ function Connections() {
{ /* APIs; google */ }
- { connections.sections.apis.dependencies?.googleOAuth && }
+ { connections.sections.apis.dependencies?.googleOAuth && (
+
+ ) }
{ /* reCAPTCHA */ }
-
+
@@ -55,7 +60,10 @@ function Connections() {
{ /* Custom Events */ }
;
title: string;
};
+ newspackAudienceConfiguration: {
+ has_reader_activation: boolean;
+ has_memberships: boolean;
+ new_subscription_lists_url: string;
+ reader_activation_url: string;
+ preview_query_keys: {
+ [ K in PromptOptionsBaseKey ]: string;
+ };
+ preview_post: string;
+ preview_archive: string;
+ };
+ newspack_reader_revenue: {
+ can_use_name_your_price: boolean;
+ };
}
}
diff --git a/src/wizards/wizards-section.tsx b/src/wizards/wizards-section.tsx
index d1409837a5..04234854ee 100644
--- a/src/wizards/wizards-section.tsx
+++ b/src/wizards/wizards-section.tsx
@@ -10,10 +10,11 @@ import { SectionHeader } from '../components/src';
/**
* Section component.
*
- * @param props Component props.
- * @param props.title Section title.
- * @param props.description Section description.
- * @param props.children Section children.
+ * @param props Component props.
+ * @param props.title Section title.
+ * @param props.description Section description.
+ * @param props.children Section children.
+ * @param props.scrollToAnchor Scroll to anchor.
*
* @return Component.
*/
@@ -21,15 +22,18 @@ export default function WizardSection( {
title,
description,
children = null,
+ scrollToAnchor = null,
}: {
title?: string;
description?: string;
children: React.ReactNode;
+ scrollToAnchor?: string | null;
} ) {
return (
{ title && (
{ title }
+ { description && { description }
}
{ children }
);