Skip to content

Commit

Permalink
epic: consolidate newsletter editor data and UI (#1658)
Browse files Browse the repository at this point in the history
* feat: make "Send To" UI autocomplete instead of dropdowns (#1577)

* feat: autocomplete "Send To" UI for CC + AC

* fix: sent post statuses for AC

* feat: autocomplete send-to UI for Mailchimp

* fix: support _n() contacts in AC + CC

* refactor: standardize "sent" status checks for all ESPs

* fix: function name for CC

* fix: set list_type for audiences

* fix: extra parentheses for AC

* feat: show suggestions on focus

* style: move external "Manage" links to button

* feat: design updates for autocomplete UI

* fix: send to summary

* fix: contact counts in send to summary

* fix: mailchimp and selected list styles

* fix: remove ID from AC segments

* fix: logic for contact count in send to summary

* fix: parse contact counts as int to avoid "1 contacts" output

* fix: translation strings for contact counts in summaries

* refactor: standardize use of renderSelectedSummary functions

* fix: translatable send-to summaries

* fix: allow 0 to be shown

* fix: grammar

* Update src/service-providers/active_campaign/ProviderSidebar.js

Co-authored-by: leogermani <[email protected]>

* Update src/service-providers/active_campaign/ProviderSidebar.js

Co-authored-by: leogermani <[email protected]>

* Update src/service-providers/constant_contact/ProviderSidebar.js

Co-authored-by: leogermani <[email protected]>

* Update src/service-providers/constant_contact/ProviderSidebar.js

Co-authored-by: leogermani <[email protected]>

* Update src/service-providers/mailchimp/ProviderSidebar.js

Co-authored-by: leogermani <[email protected]>

* Update src/service-providers/mailchimp/ProviderSidebar.js

Co-authored-by: leogermani <[email protected]>

* fix: translatable strings in SendTo component’s selected item label

---------

Co-authored-by: leogermani <[email protected]>

* fix(editor): render notice on sync error (#1606)

* fix(mailchimp): improve sync error messages (#1619)

* fix(activecampaign): default message on request error (#1618)

* feat: cross-ESP send-lists

* refactor: move API namespace and permission callback to main class

* feat: support send lists in provider classes

* feat: refactor editor JS to use new standardized data

* fix: ensure Newsletters plugin blocks are grouped under Newspack category (#1630)

* feat: send list classes (#1629)

* feat: cross-ESP send-lists

* refactor: move API namespace and permission callback to main class

* refactor: feedback from code review

* fix: add missing get/set methods for count and parent_id

* refactor: more consistent naming for set_count method

* refactor: maintain exception but with WP_Error handling

* docs: add more explanation about Send_Lists

Co-authored-by: leogermani <[email protected]>

* test: improve tests for matching methods

* refactor: set values on protected $config var

* docs: tweak wording of explanation

---------

Co-authored-by: leogermani <[email protected]>

* feat: support send lists in ESP classes (#1631)

* feat: cross-ESP send-lists

* refactor: move API namespace and permission callback to main class

* feat: support send lists in provider classes

* fix: use getter methods for Send_List classes

* chore: clean up register_rest_route configs and permission callbacks

* fix: improve error handling for get_send_list methods

* fix: add error handling to send-lists API handler

* fix: return Send_List objects as arrays from provider methods

* fix: avoid unnecessary send-list API requests

* chore: remove unneeded methods

* fix: fatal error due to get_send_lists returning Send_List arrays instead of objects

* Revert "fix: fatal error due to get_send_lists returning Send_List arrays instead of objects"

This reverts commit 3ff1e65.

* fix: allow get_send_list methods to return either Send_List[] or arrays

* fix: correct type for supportedESPs fallback value

* fix(mc): subscriber send count in pre-send modal summary

* fix: formatting error

* fix: ensure supported_esps is an array, not an object

* fix: missed callable

* fix: cc error handling

* fix: better error handling for retrieve/sync request errors

* refactor: unify retrieve error handling across all ESPs

* refactor: throw error for missing MC creds, too

* test: update expected exception message

* refactor: consolidate ESP data getters into Redux store

* docs: update inline docs for Redux store

* fix: move SendTo to Sidebar component; avoid parallel retrieve requests

* refactor: always prefetch sublists on list select

* fix: account for missing selected list or sublist info

* fix: default sender/send-to for saved layouts

* fix: campaign_defaults meta field name

* fix: don't overwrite fetched lists/sublists info on retrieve

* fix: force release

* feat: add link to campaign in provider (#1661)

* fix: parse legacy layout defaults (#1663)

* fix: handle legacy layout defaults for MC

* fix: legacy layout defaults for AC + CC

* fix: senderName + senderEmail for AC

---------

Co-authored-by: leogermani <[email protected]>
Co-authored-by: Miguel Peixe <[email protected]>
Co-authored-by: Miguel Peixe <[email protected]>
  • Loading branch information
4 people authored Oct 14, 2024
1 parent 3255f0b commit 0ae5cc5
Show file tree
Hide file tree
Showing 59 changed files with 4,042 additions and 2,461 deletions.
12 changes: 1 addition & 11 deletions includes/class-newspack-newsletters-ads.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,11 @@ public static function rest_api_init() {
[
'callback' => [ __CLASS__, 'get_ads_config' ],
'methods' => 'GET',
'permission_callback' => [ __CLASS__, 'permission_callback' ],
'permission_callback' => [ 'Newspack_Newsletters', 'api_authoring_permissions_check' ],
]
);
}

/**
* Check capabilities for using the API for authoring tasks.
*
* @param WP_REST_Request $request API request object.
* @return bool|WP_Error
*/
public static function permission_callback( $request ) {
return current_user_can( 'edit_posts' );
}

/**
* Register custom fields.
*/
Expand Down
30 changes: 21 additions & 9 deletions includes/class-newspack-newsletters-editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct() {
add_action( 'the_post', [ __CLASS__, 'strip_editor_modifications' ] );
add_action( 'after_setup_theme', [ __CLASS__, 'newspack_font_sizes' ], 11 );
add_action( 'enqueue_block_editor_assets', [ __CLASS__, 'enqueue_block_editor_assets' ] );
add_filter( 'block_categories_all', [ __CLASS__, 'add_custom_block_category' ] );
add_filter( 'allowed_block_types_all', [ __CLASS__, 'newsletters_allowed_block_types' ], 10, 2 );
add_action( 'rest_post_query', [ __CLASS__, 'maybe_filter_excerpt_length' ], 10, 2 );
add_action( 'rest_post_query', [ __CLASS__, 'maybe_exclude_sponsored_posts' ], 10, 2 );
Expand Down Expand Up @@ -249,6 +250,24 @@ public static function newspack_font_sizes() {
);
}

/**
* Add the "Newspack" block category.
*
* @param array $block_categories Default block categories.
* @return array
*/
public static function add_custom_block_category( $block_categories ) {
array_unshift(
$block_categories,
[
'slug' => 'newspack',
'title' => 'Newspack',
]
);

return $block_categories;
}

/**
* Restrict block types for Newsletter CPT.
*
Expand Down Expand Up @@ -302,14 +321,9 @@ public static function enqueue_block_editor_assets() {
$mjml_handling_post_types = array_values( array_diff( self::get_email_editor_cpts(), [ Newspack_Newsletters_Ads::CPT ] ) );
$provider = Newspack_Newsletters::get_service_provider();
$conditional_tag_support = false;
$error_message = false;

if ( $provider && ( self::is_editing_newsletter() || self::is_editing_newsletter_ad() ) ) {
$conditional_tag_support = $provider::get_conditional_tag_support();

// Fetch async error messages to display on editor load.
$transient_name = $provider->get_transient_name( get_the_ID() );
$error_message = get_transient( $transient_name );
}

$email_editor_data = [
Expand All @@ -324,12 +338,9 @@ public static function enqueue_block_editor_assets() {
'byline_connector_label' => __( 'and ', 'newspack-newsletters' ),
],
'supported_social_icon_services' => Newspack_Newsletters_Renderer::get_supported_social_icons_services(),
'supported_esps' => Newspack_Newsletters::get_supported_providers(),
];

if ( $error_message ) {
$email_editor_data['error_message'] = $error_message;
}

if ( self::is_editing_email() ) {
wp_register_style(
'newspack-newsletters',
Expand Down Expand Up @@ -371,6 +382,7 @@ public static function enqueue_block_editor_assets() {
'is_service_provider_configured' => Newspack_Newsletters::is_service_provider_configured(),
'service_provider' => Newspack_Newsletters::service_provider(),
'user_test_emails' => self::get_current_user_test_emails(),
'labels' => $provider ? $provider::get_labels() : [],
]
);
wp_register_style(
Expand Down
65 changes: 64 additions & 1 deletion includes/class-newspack-newsletters-layouts.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static function register_meta() {
\register_meta( 'post', 'font_body', $meta_default_params );
\register_meta( 'post', 'background_color', $meta_default_params );
\register_meta( 'post', 'custom_css', $meta_default_params );
\register_meta( 'post', 'layout_defaults', $meta_default_params );
\register_meta( 'post', 'campaign_defaults', $meta_default_params );
}

/**
Expand Down Expand Up @@ -191,5 +191,68 @@ public static function get_default_layouts() {
}
return $layouts;
}

/**
* Get all layouts.
*/
public static function get_layouts() {
$layouts_query = new WP_Query(
[
'post_type' => self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT,
'posts_per_page' => -1,
]
);
$user_layouts = array_map(
function ( $post ) {
$post->meta = [
'background_color' => get_post_meta( $post->ID, 'background_color', true ),
'font_body' => get_post_meta( $post->ID, 'font_body', true ),
'font_header' => get_post_meta( $post->ID, 'font_header', true ),
'custom_css' => get_post_meta( $post->ID, 'custom_css', true ),
'campaign_defaults' => get_post_meta( $post->ID, 'campaign_defaults', true ),
];

// Migrate layout defaults from legacy meta, if it exists.
$campaign_defaults = $post->meta['campaign_defaults'];
$legacy_meta = json_decode( get_post_meta( $post->ID, 'layout_defaults', true ), true );
if ( empty( $campaign_defaults ) && ! empty( $legacy_meta ) ) {
$campaign_defaults = [];
if ( ! empty( $legacy_meta['senderName'] ) ) {
$campaign_defaults['senderName'] = $legacy_meta['senderName'];
}
if ( ! empty( $legacy_meta['senderEmail'] ) ) {
$campaign_defaults['senderEmail'] = $legacy_meta['senderEmail'];
}
$provider = Newspack_Newsletters::get_service_provider();
$campaign_info = $provider->extract_campaign_info( $legacy_meta['newsletterData'] ?? null );
if ( ! empty( $campaign_info['list_id'] ) ) {
$campaign_defaults['send_list_id'] = $campaign_info['list_id'];
}
if ( ! empty( $campaign_info['sublist_id'] ) ) {
$campaign_defaults['send_sublist_id'] = $campaign_info['sublist_id'];
}
if ( ! empty( $campaign_info['senderName'] ) ) {
$campaign_defaults['senderName'] = $campaign_info['senderName'];
}
if ( ! empty( $campaign_info['senderEmail'] ) ) {
$campaign_defaults['senderEmail'] = $campaign_info['senderEmail'];
}
if ( ! empty( $campaign_defaults ) ) {
$campaign_defaults = wp_json_encode( $campaign_defaults );
update_post_meta( $post->ID, 'campaign_defaults', $campaign_defaults );
$post->meta['campaign_defaults'] = $campaign_defaults;
}
}

return $post;
},
$layouts_query->get_posts()
);
return array_merge(
$user_layouts,
self::get_default_layouts(),
apply_filters( 'newspack_newsletters_templates', [] )
);
}
}
Newspack_Newsletters_Layouts::instance();
2 changes: 1 addition & 1 deletion includes/class-newspack-newsletters-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ public static function update_option_newspack_newsletters_public_posts_slug( $ol
/**
* Update settings.
*
* @param string $settings Update.
* @param array $settings Update.
*/
public static function update_settings( $settings ) {
foreach ( $settings as $key => $value ) {
Expand Down
34 changes: 11 additions & 23 deletions includes/class-newspack-newsletters-subscription.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
* Manages Settings Subscription Class.
*/
class Newspack_Newsletters_Subscription {

const API_NAMESPACE = 'newspack-newsletters/v1';

const EMAIL_VERIFIED_META = 'newspack_newsletters_email_verified';
const EMAIL_VERIFIED_REQUEST = 'newspack_newsletters_email_verification_request';
const EMAIL_VERIFIED_CONFIRM = 'newspack_newsletters_email_verification';
Expand Down Expand Up @@ -62,7 +59,7 @@ public static function init() {
*/
public static function register_api_endpoints() {
register_rest_route(
self::API_NAMESPACE,
Newspack_Newsletters::API_NAMESPACE,
'/lists_config',
[
'methods' => \WP_REST_Server::READABLE,
Expand All @@ -71,21 +68,21 @@ public static function register_api_endpoints() {
]
);
register_rest_route(
self::API_NAMESPACE,
Newspack_Newsletters::API_NAMESPACE,
'/lists',
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ __CLASS__, 'api_get_lists' ],
'permission_callback' => [ __CLASS__, 'api_permission_callback' ],
'permission_callback' => [ 'Newspack_Newsletters', 'api_administration_permissions_check' ],
]
);
register_rest_route(
self::API_NAMESPACE,
Newspack_Newsletters::API_NAMESPACE,
'/lists',
[
'methods' => \WP_REST_Server::EDITABLE,
'callback' => [ __CLASS__, 'api_update_lists' ],
'permission_callback' => [ __CLASS__, 'api_permission_callback' ],
'permission_callback' => [ 'Newspack_Newsletters', 'api_administration_permissions_check' ],
'args' => [
'lists' => [
'type' => 'array',
Expand Down Expand Up @@ -113,15 +110,6 @@ public static function register_api_endpoints() {
);
}

/**
* Whether the current user can manage subscription lists.
*
* @return bool Whether the current user can manage subscription lists.
*/
public static function api_permission_callback() {
return current_user_can( 'manage_options' );
}

/**
* API method to retrieve the current lists configuration.
*
Expand Down Expand Up @@ -229,7 +217,7 @@ function ( $list ) {
public static function get_lists_config() {
$provider = Newspack_Newsletters::get_service_provider();
if ( empty( $provider ) ) {
return new WP_Error( 'newspack_newsletters_invalid_provider', __( 'Provider is not set.' ) );
return new WP_Error( 'newspack_newsletters_invalid_provider', __( 'Provider is not set.', 'newspack-newsletters' ) );
}

$saved_lists = Subscription_Lists::get_configured_for_current_provider();
Expand Down Expand Up @@ -262,11 +250,11 @@ public static function get_lists_config() {
public static function update_lists( $lists ) {
$provider = Newspack_Newsletters::get_service_provider();
if ( empty( $provider ) ) {
return new WP_Error( 'newspack_newsletters_invalid_provider', __( 'Provider is not set.' ) );
return new WP_Error( 'newspack_newsletters_invalid_provider', __( 'Provider is not set.', 'newspack-newsletters' ) );
}
$lists = self::sanitize_lists( $lists );
if ( empty( $lists ) ) {
return new WP_Error( 'newspack_newsletters_invalid_lists', __( 'Invalid list configuration.' ) );
return new WP_Error( 'newspack_newsletters_invalid_lists', __( 'Invalid list configuration.', 'newspack-newsletters' ) );
}

return Subscription_Lists::update_lists( $lists );
Expand Down Expand Up @@ -321,16 +309,16 @@ public static function has_subscription_management() {
*/
public static function get_contact_data( $email_address, $return_details = false ) {
if ( ! $email_address || empty( $email_address ) ) {
return new WP_Error( 'newspack_newsletters_invalid_email', __( 'Missing email address.' ) );
return new WP_Error( 'newspack_newsletters_invalid_email', __( 'Missing email address.', 'newspack-newsletters' ) );
}

$provider = Newspack_Newsletters::get_service_provider();
if ( empty( $provider ) ) {
return new WP_Error( 'newspack_newsletters_invalid_provider', __( 'Provider is not set.' ) );
return new WP_Error( 'newspack_newsletters_invalid_provider', __( 'Provider is not set.', 'newspack-newsletters' ) );
}

if ( ! method_exists( $provider, 'get_contact_data' ) ) {
return new WP_Error( 'newspack_newsletters_not_implemented', __( 'Provider does not handle the contact-exists check.' ) );
return new WP_Error( 'newspack_newsletters_not_implemented', __( 'Provider does not handle the contact-exists check.', 'newspack-newsletters' ) );
}

return $provider->get_contact_data( $email_address, $return_details );
Expand Down
Loading

0 comments on commit 0ae5cc5

Please sign in to comment.