diff --git a/includes/class-newspack-popups-inserter.php b/includes/class-newspack-popups-inserter.php index d27d9724..af460ac6 100755 --- a/includes/class-newspack-popups-inserter.php +++ b/includes/class-newspack-popups-inserter.php @@ -53,6 +53,11 @@ public static function popups_for_post() { return [ Newspack_Popups_Model::retrieve_preview_popup( Newspack_Popups::previewed_popup_id() ) ]; } + // Campaigns disabled for this page. + if ( self::assess_has_disabled_popups() ) { + return []; + } + // 1. Get all inline popups. $popups_to_maybe_display = Newspack_Popups_Model::retrieve_inline_popups(); @@ -80,8 +85,8 @@ public static function popups_for_post() { $found_popup = Newspack_Popups_Model::retrieve_popup_by_id( $sitewide_default ); if ( $found_popup && - // Prevent inline sitewide default from being added - all inline popups are there. - 'inline' !== $found_popup['options']['placement'] + // Prevent non-overlay sitewide default from being added. + Newspack_Popups_Model::is_overlay( $found_popup ) ) { array_push( $popups_to_maybe_display, @@ -96,7 +101,7 @@ public static function popups_for_post() { $popups_to_maybe_display_deduped = array_filter( $popups_to_maybe_display, function ( $campaign ) use ( &$has_overlay ) { - if ( 'inline' !== $campaign['options']['placement'] ) { + if ( Newspack_Popups_Model::is_overlay( $campaign ) ) { if ( $has_overlay ) { return false; } else { @@ -108,16 +113,10 @@ function ( $campaign ) use ( &$has_overlay ) { } ); - $popups_to_display = array_filter( + return array_filter( $popups_to_maybe_display_deduped, [ __CLASS__, 'should_display' ] ); - - if ( ! empty( $popups_to_display ) ) { - return $popups_to_display; - } - - return []; } /** @@ -129,6 +128,7 @@ public function __construct() { add_action( 'after_header', [ $this, 'insert_popups_after_header' ] ); // This is a Newspack theme hook. When used with other themes, popups won't be inserted on archive pages. add_action( 'wp_head', [ $this, 'insert_popups_amp_access' ] ); add_action( 'wp_head', [ $this, 'register_amp_scripts' ] ); + add_action( 'before_header', [ $this, 'insert_before_header' ] ); // Always enqueue scripts, since this plugin's scripts are handling pageview sending via GTAG. add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] ); @@ -173,9 +173,8 @@ function() { * Process popups and insert into post and page content if needed. * * @param string $content The content of the post. - * @param bool $enqueue_assets Whether assets should be enqueued. */ - public static function insert_popups_in_content( $content = '', $enqueue_assets = true ) { + public static function insert_popups_in_content( $content = '' ) { // Avoid duplicate execution. if ( true === self::$the_content_has_rendered ) { return $content; @@ -201,13 +200,8 @@ public static function insert_popups_in_content( $content = '', $enqueue_assets return $content; } - // Campaigns disabled for this page. - if ( self::assess_has_disabled_popups() ) { - return $content; - } - // If the current post is a Campaign, ignore. - if ( Newspack_Popups::NEWSPACK_PLUGINS_CPT == get_post_type() ) { + if ( Newspack_Popups::NEWSPACK_POPUPS_CPT == get_post_type() ) { return $content; } @@ -217,7 +211,7 @@ public static function insert_popups_in_content( $content = '', $enqueue_assets return $content; } - $popups = self::popups_for_post(); + $popups = array_filter( self::popups_for_post(), [ 'Newspack_Popups_Model', 'should_be_inserted_in_page_content' ] ); if ( empty( $popups ) ) { return $content; @@ -239,16 +233,21 @@ public static function insert_popups_in_content( $content = '', $enqueue_assets $inline_popups = []; $overlay_popups = []; foreach ( $popups as $popup ) { - if ( 'inline' === $popup['options']['placement'] ) { + if ( Newspack_Popups_Model::is_inline( $popup ) ) { $percentage = intval( $popup['options']['trigger_scroll_progress'] ) / 100; $popup['precise_position'] = $total_length * $percentage; $popup['is_inserted'] = false; $inline_popups[] = $popup; - } else { + } elseif ( Newspack_Popups_Model::is_overlay( $popup ) ) { $overlay_popups[] = $popup; } } + // Return early if there are no popups to insert. This can happen if e.g. the only popup is an above header one. + if ( empty( $inline_popups ) && empty( $overlay_popups ) ) { + return $content; + } + // 2. Iterate overall blocks and insert inline campaigns. $pos = 0; $output = ''; @@ -291,13 +290,19 @@ public static function insert_popups_after_header() { if ( is_singular() ) { return; } + $popups = array_filter( self::popups_for_post(), [ 'Newspack_Popups_Model', 'should_be_inserted_in_page_content' ] ); + foreach ( $popups as $popup ) { + echo Newspack_Popups_Model::generate_popup( $popup ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + } - $popups = self::popups_for_post(); - - if ( ! empty( $popups ) ) { - foreach ( $popups as $popup ) { - echo Newspack_Popups_Model::generate_popup( $popup ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } + /** + * Insert popups markup before header. + */ + public static function insert_before_header() { + $before_header_popups = array_filter( self::popups_for_post(), [ 'Newspack_Popups_Model', 'should_be_inserted_above_page_header' ] ); + foreach ( $before_header_popups as $popup ) { + echo Newspack_Popups_Model::generate_popup( $popup ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } @@ -356,7 +361,7 @@ public static function popup_shortcode( $atts = array() ) { public static function create_single_popup_access_payload( $popup ) { $popup_id_string = Newspack_Popups_Model::canonize_popup_id( esc_attr( $popup['id'] ) ); $frequency = $popup['options']['frequency']; - if ( 'inline' !== $popup['options']['placement'] && 'always' === $frequency ) { + if ( Newspack_Popups_Model::is_overlay( $popup ) && 'always' === $frequency ) { $frequency = 'once'; } return [ diff --git a/includes/class-newspack-popups-model.php b/includes/class-newspack-popups-model.php index b9ac3c65..43b1cafa 100644 --- a/includes/class-newspack-popups-model.php +++ b/includes/class-newspack-popups-model.php @@ -11,6 +11,19 @@ * API endpoints */ final class Newspack_Popups_Model { + /** + * Possible placements of overlay popups. + * + * @var array + */ + protected static $overlay_placements = [ 'top', 'bottom', 'center' ]; + + /** + * Possible placements of inline popups. + * + * @var array + */ + protected static $inline_placements = [ 'inline', 'above_header' ]; /** * Retrieve all Popups (first 100). @@ -20,7 +33,7 @@ final class Newspack_Popups_Model { */ public static function retrieve_popups( $include_unpublished = false ) { $args = [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, 'post_status' => $include_unpublished ? [ 'publish', 'draft' ] : 'publish', 'posts_per_page' => 100, ]; @@ -31,7 +44,7 @@ public static function retrieve_popups( $include_unpublished = false ) { foreach ( $popups as &$popup ) { // UI will not allow for setting inline as sitewide default, but there may be // legacy popups from before this update. - if ( 'inline' !== $popup['options']['placement'] ) { + if ( self::is_overlay( $popup ) ) { $popup['sitewide_default'] = absint( $sitewide_default_id ) === absint( $popup['id'] ); } } @@ -57,7 +70,7 @@ public static function set_sitewide_popup( $id ) { } // Such update will not be permitted by the UI, but it's handled just to be explicit about it. - if ( 'inline' === $popup['options']['placement'] ) { + if ( self::is_inline( $popup ) ) { return new \WP_Error( 'newspack_popups_inline_sitewide', esc_html__( 'An inline Campaign cannot be a sitewide default.', 'newspack-popups' ), @@ -153,7 +166,7 @@ public static function set_popup_options( $id, $options ) { update_post_meta( $id, $key, $value ); break; case 'placement': - if ( ! in_array( $value, [ 'center', 'top', 'bottom', 'inline' ] ) ) { + if ( ! in_array( $value, array_merge( self::$overlay_placements, self::$inline_placements ) ) ) { return new \WP_Error( 'newspack_popups_invalid_option_value', esc_html__( 'Invalid placement value.', 'newspack-popups' ), @@ -165,6 +178,8 @@ public static function set_popup_options( $id, $options ) { } update_post_meta( $id, $key, $value ); break; + case 'trigger_type': + case 'trigger_scroll_progress': case 'utm_suppression': case 'selected_segment_id': update_post_meta( $id, $key, esc_attr( $value ) ); @@ -189,11 +204,12 @@ public static function set_popup_options( $id, $options ) { */ public static function retrieve_inline_popups() { $args = [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, - 'post_status' => 'publish', - 'meta_key' => 'placement', + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, + 'post_status' => 'publish', + 'meta_key' => 'placement', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value - 'meta_value' => 'inline', + 'meta_value' => self::$inline_placements, + 'meta_compare' => 'IN', ]; return self::retrieve_popups_with_query( new WP_Query( $args ) ); @@ -206,13 +222,13 @@ public static function retrieve_inline_popups() { */ public static function retrieve_overlay_test_popups() { $args = [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, 'post_status' => 'publish', 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query [ 'key' => 'placement', - 'value' => 'inline', - 'compare' => '!=', + 'value' => self::$overlay_placements, + 'compare' => 'IN', ], [ 'key' => 'frequency', @@ -237,14 +253,14 @@ public static function retrieve_category_overlay_popup() { } $args = [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, 'posts_per_page' => 1, 'post_status' => 'publish', 'category__in' => array_column( $post_categories, 'term_id' ), 'meta_key' => 'placement', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value - 'meta_value' => 'inline', - 'meta_compare' => '!=', + 'meta_value' => self::$overlay_placements, + 'meta_compare' => 'IN', ]; $popups = self::retrieve_popups_with_query( new WP_Query( $args ) ); @@ -293,7 +309,7 @@ public static function retrieve_preview_popup( $post_id ) { */ public static function retrieve_popup_by_id( $post_id, $include_drafts = false ) { $args = [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, 'posts_per_page' => 1, 'p' => $post_id, ]; @@ -386,18 +402,21 @@ public static function create_popup_object( $campaign_post, $include_categories return $popup; } - switch ( $popup['options']['trigger_type'] ) { - case 'scroll': - $popup['options']['trigger_delay'] = 0; - break; - case 'time': - default: - $popup['options']['trigger_scroll_progress'] = 0; - break; - }; - if ( ! in_array( $popup['options']['placement'], [ 'top', 'bottom' ], true ) ) { - $popup['options']['placement'] = 'center'; + if ( self::is_overlay( $popup ) ) { + switch ( $popup['options']['trigger_type'] ) { + case 'scroll': + $popup['options']['trigger_delay'] = 0; + break; + case 'time': + default: + $popup['options']['trigger_scroll_progress'] = 0; + break; + }; + if ( ! in_array( $popup['options']['placement'], [ 'top', 'bottom' ], true ) ) { + $popup['options']['placement'] = 'center'; + } } + return $popup; } @@ -438,9 +457,51 @@ protected static function get_delay( $popup ) { * @return boolean True if it is an inline popup. */ public static function is_inline( $popup ) { + if ( ! isset( $popup['options'], $popup['options']['placement'] ) ) { + return false; + } return 'inline' === $popup['options']['placement']; } + /** + * Get popups which should be inserted above page header. + * + * @param object $popup The popup object. + * @return boolean True if the popup should be inserted above page header. + */ + public static function should_be_inserted_above_page_header( $popup ) { + if ( self::is_inline( $popup ) ) { + return 'above_header' === $popup['options']['placement']; + } else { + // Insert time-triggered overlay popups above the header, this way they will be + // visible before scrolling below the fold. + return 'time' === $popup['options']['trigger_type']; + } + } + + /** + * Get popups which should be inserted in page content. + * + * @param object $popup The popup object. + * @return boolean True if the popup should be inserted in page content. + */ + public static function should_be_inserted_in_page_content( $popup ) { + return self::should_be_inserted_above_page_header( $popup ) === false; + } + + /** + * Is it an overlay popup or not. + * + * @param object $popup The popup object. + * @return boolean True if it is an overlay popup. + */ + public static function is_overlay( $popup ) { + if ( ! isset( $popup['options'], $popup['options']['placement'] ) ) { + return false; + } + return in_array( $popup['options']['placement'], self::$overlay_placements, true ); + } + /** * Does the popup have newsletter prompt? * @@ -557,7 +618,7 @@ protected static function get_analytics_events( $popup, $body, $element_id ) { $has_link = preg_match( '/base ) { + if ( Newspack_Popups::NEWSPACK_POPUPS_CPT . '_page_' . self::NEWSPACK_POPUPS_SETTINGS_PAGE !== $screen->base ) { return; } diff --git a/includes/class-newspack-popups.php b/includes/class-newspack-popups.php index 3f764d24..01fd6f06 100644 --- a/includes/class-newspack-popups.php +++ b/includes/class-newspack-popups.php @@ -12,8 +12,9 @@ */ final class Newspack_Popups { - const NEWSPACK_PLUGINS_CPT = 'newspack_popups_cpt'; + const NEWSPACK_POPUPS_CPT = 'newspack_popups_cpt'; const NEWSPACK_POPUPS_SITEWIDE_DEFAULT = 'newspack_popups_sitewide_default'; + const NEWSPACK_POPUPS_TAXONOMY = 'newspack_popups_taxonomy'; const NEWSPACK_POPUP_PREVIEW_QUERY_PARAM = 'newspack_popups_preview_id'; @@ -48,10 +49,11 @@ public function __construct() { add_action( 'admin_notices', [ __CLASS__, 'api_config_missing_notice' ] ); add_action( 'init', [ __CLASS__, 'register_cpt' ] ); add_action( 'init', [ __CLASS__, 'register_meta' ] ); + add_action( 'init', [ __CLASS__, 'register_taxonomy' ] ); add_action( 'enqueue_block_editor_assets', [ __CLASS__, 'enqueue_block_editor_assets' ] ); add_filter( 'display_post_states', [ __CLASS__, 'display_post_states' ], 10, 2 ); add_action( 'rest_api_init', [ __CLASS__, 'rest_api_init' ] ); - add_action( 'save_post_' . self::NEWSPACK_PLUGINS_CPT, [ __CLASS__, 'popup_default_fields' ], 10, 3 ); + add_action( 'save_post_' . self::NEWSPACK_POPUPS_CPT, [ __CLASS__, 'popup_default_fields' ], 10, 3 ); if ( filter_input( INPUT_GET, 'newspack_popups_preview_id', FILTER_SANITIZE_STRING ) ) { add_filter( 'show_admin_bar', [ __CLASS__, 'hide_admin_bar_for_preview' ], 10, 2 ); // phpcs:ignore WordPressVIPMinimum.UserExperience.AdminBarRemoval.RemovalDetected @@ -96,7 +98,7 @@ public static function register_cpt() { 'taxonomies' => [ 'category', 'post_tag' ], 'menu_icon' => 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjYTBhNWFhIiBkPSJNMTEuOTkgMTguNTRsLTcuMzctNS43M0wzIDE0LjA3bDkgNyA5LTctMS42My0xLjI3LTcuMzggNS43NHpNMTIgMTZsNy4zNi01LjczTDIxIDlsLTktNy05IDcgMS42MyAxLjI3TDEyIDE2eiIvPjwvc3ZnPgo=', ]; - \register_post_type( self::NEWSPACK_PLUGINS_CPT, $cpt_args ); + \register_post_type( self::NEWSPACK_POPUPS_CPT, $cpt_args ); } /** @@ -107,7 +109,7 @@ public static function register_meta() { 'post', 'trigger_type', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -118,7 +120,7 @@ public static function register_meta() { 'post', 'trigger_scroll_progress', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'integer', 'single' => true, @@ -129,7 +131,7 @@ public static function register_meta() { 'post', 'trigger_delay', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'integer', 'single' => true, @@ -141,7 +143,7 @@ public static function register_meta() { 'post', 'frequency', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -153,7 +155,7 @@ public static function register_meta() { 'post', 'placement', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -165,7 +167,7 @@ public static function register_meta() { 'post', 'utm_suppression', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -177,7 +179,7 @@ public static function register_meta() { 'post', 'background_color', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -189,7 +191,7 @@ public static function register_meta() { 'post', 'overlay_color', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -201,7 +203,7 @@ public static function register_meta() { 'post', 'overlay_opacity', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'integer', 'single' => true, @@ -213,7 +215,7 @@ public static function register_meta() { 'post', 'dismiss_text', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -225,7 +227,7 @@ public static function register_meta() { 'post', 'dismiss_text_alignment', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -237,7 +239,7 @@ public static function register_meta() { 'post', 'display_title', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'boolean', 'single' => true, @@ -249,7 +251,7 @@ public static function register_meta() { 'post', 'selected_segment_id', [ - 'object_subtype' => self::NEWSPACK_PLUGINS_CPT, + 'object_subtype' => self::NEWSPACK_POPUPS_CPT, 'show_in_rest' => true, 'type' => 'string', 'single' => true, @@ -270,6 +272,31 @@ public static function register_meta() { ); } + /** + * Register Campaigns taxonomy. + */ + public static function register_taxonomy() { + $taxonomy_args = [ + 'labels' => [ + 'name' => __( 'Campaign Groups', 'newspack-popups' ), + 'singular_name' => __( 'Campaign Group', 'newspack-popups' ), + 'add_new_item' => __( 'Add Campaign Group', 'newspack-popups' ), + ], + 'hierarchical' => true, + 'public' => false, + 'rewrite' => false, // phpcs:ignore Squiz.PHP.CommentedOutCode.Found [ 'hierarchical' => true, 'slug' => $prefix . '/category' ] + 'show_in_menu' => false, + 'show_in_rest' => true, + 'show_tagcloud' => false, + 'show_ui' => true, + ]; + + register_taxonomy( self::NEWSPACK_POPUPS_TAXONOMY, [ self::NEWSPACK_POPUPS_CPT ], $taxonomy_args ); + + // Better safe than sorry: https://developer.wordpress.org/reference/functions/register_taxonomy/#more-information. + register_taxonomy_for_object_type( self::NEWSPACK_POPUPS_TAXONOMY, [ self::NEWSPACK_POPUPS_CPT ] ); + } + /** * Get preview post permalink. */ @@ -304,7 +331,7 @@ public static function preview_post_permalink() { public static function enqueue_block_editor_assets() { $screen = get_current_screen(); - if ( self::NEWSPACK_PLUGINS_CPT !== $screen->post_type ) { + if ( self::NEWSPACK_POPUPS_CPT !== $screen->post_type ) { if ( 'page' !== $screen->post_type || 'post' !== $screen->post_type ) { // Script for global settings. \wp_enqueue_script( @@ -350,7 +377,7 @@ public static function enqueue_block_editor_assets() { * @param WP_Post $post The current post object. */ public static function display_post_states( $post_states, $post ) { - if ( self::NEWSPACK_PLUGINS_CPT !== $post->post_type ) { + if ( self::NEWSPACK_POPUPS_CPT !== $post->post_type ) { return $post_states; } $post_status_object = get_post_status_object( $post->post_status ); @@ -398,7 +425,7 @@ public static function previewed_popup_id( $url = null ) { */ public static function rest_api_init() { register_rest_field( - [ self::NEWSPACK_PLUGINS_CPT ], + [ self::NEWSPACK_POPUPS_CPT ], 'newspack_popups_is_sitewide_default', [ 'get_callback' => function( $post ) { diff --git a/src/editor/ColorsSidebar.js b/src/editor/ColorsSidebar.js index 3e8c2f04..a87ca9b3 100644 --- a/src/editor/ColorsSidebar.js +++ b/src/editor/ColorsSidebar.js @@ -6,54 +6,40 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { Fragment, useEffect } from '@wordpress/element'; +import { Fragment } from '@wordpress/element'; import { RangeControl } from '@wordpress/components'; import { ColorPaletteControl } from '@wordpress/block-editor'; -/** - * Internal dependencies - */ -import { updateEditorColors } from './utils'; - const ColorsSidebar = ( { background_color, onMetaFieldChange, overlay_opacity, overlay_color, - placement, -} ) => { - const isInline = 'inline' === placement; - - // On component mount. - useEffect(() => { - updateEditorColors( background_color ); - }, [ background_color ]); - - return ( - - onMetaFieldChange( 'background_color', value || '#FFFFFF' ) } - label={ __( 'Background Color' ) } - /> - { ! isInline && ( - - onMetaFieldChange( 'overlay_color', value || '#000000' ) } - label={ __( 'Overlay Color' ) } - /> - onMetaFieldChange( 'overlay_opacity', value ) } - min={ 0 } - max={ 100 } - /> - - ) } - - ); -}; + isOverlay, +} ) => ( + + onMetaFieldChange( 'background_color', value || '#FFFFFF' ) } + label={ __( 'Background Color' ) } + /> + { isOverlay && ( + + onMetaFieldChange( 'overlay_color', value || '#000000' ) } + label={ __( 'Overlay Color' ) } + /> + onMetaFieldChange( 'overlay_opacity', value ) } + min={ 0 } + max={ 100 } + /> + + ) } + +); export default ColorsSidebar; diff --git a/src/editor/EditorAdditions.js b/src/editor/EditorAdditions.js new file mode 100644 index 00000000..2e00c6bf --- /dev/null +++ b/src/editor/EditorAdditions.js @@ -0,0 +1,57 @@ +/** + * Popup-related editor changes. + */ + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { updateEditorColors } from './utils'; + +const EditorAdditions = () => { + const meta = useSelect( select => select( 'core/editor' ).getEditedPostAttribute( 'meta' ) ); + const { dismiss_text, dismiss_text_alignment, background_color } = meta; + + // Update editor colors to match popup colors. + useEffect(() => { + updateEditorColors( background_color ); + }, [ background_color ]); + + // Render a preview of the dismiss button at the end of the block content area. + useEffect(() => { + if ( ! dismiss_text ) { + return; + } + + const alignClass = 'has-text-align-' + ( dismiss_text_alignment || 'center' ); + + let dismissButtonPreview = document.querySelector( + '.newspack-popups__not-interested-button-preview' + ); + + if ( ! dismissButtonPreview ) { + const rootContainer = document.querySelector( + '.block-editor-block-list__layout.is-root-container' + ); + + if ( rootContainer ) { + dismissButtonPreview = document.createElement( 'div' ); + rootContainer.appendChild( dismissButtonPreview ); + } + } + + if ( dismissButtonPreview ) { + dismissButtonPreview.className = + 'newspack-popups__not-interested-button-preview wp-block ' + alignClass; + dismissButtonPreview.textContent = dismiss_text; + } + }, [ dismiss_text, dismiss_text_alignment ]); + return null; +}; + +export default EditorAdditions; diff --git a/src/editor/FrequencySidebar.js b/src/editor/FrequencySidebar.js index 2f5e974c..2ce9c1b5 100644 --- a/src/editor/FrequencySidebar.js +++ b/src/editor/FrequencySidebar.js @@ -9,7 +9,7 @@ import { __ } from '@wordpress/i18n'; import { Fragment } from '@wordpress/element'; import { SelectControl, TextControl } from '@wordpress/components'; -const FrequencySidebar = ( { frequency, onMetaFieldChange, placement, utm_suppression } ) => { +const FrequencySidebar = ( { frequency, onMetaFieldChange, isOverlay, utm_suppression } ) => { return ( diff --git a/src/editor/Sidebar.js b/src/editor/Sidebar.js index 956b1596..8e3dc849 100644 --- a/src/editor/Sidebar.js +++ b/src/editor/Sidebar.js @@ -17,12 +17,12 @@ const Sidebar = ( { trigger_scroll_progress, trigger_delay, trigger_type, + isOverlay, + isInlinePlacement, } ) => { - const isInline = 'inline' === placement; - const updatePlacement = value => { onMetaFieldChange( 'placement', value ); - if ( value !== 'inline' && frequency === 'always' ) { + if ( ! isInlinePlacement( value ) && frequency === 'always' ) { onMetaFieldChange( 'frequency', 'once' ); } }; @@ -31,32 +31,33 @@ const Sidebar = ( { { - if ( value ) { - return updatePlacement( 'inline' ); - } - updatePlacement( 'center' ); - } } + checked={ ! isOverlay } + onChange={ value => updatePlacement( value ? 'inline' : 'center' ) } /> - onMetaFieldChange( 'display_title', value ) } + - { ! isInline && ( + { isOverlay && ( - ) } - { isInline && ( + { placement === 'inline' && ( ) } + onMetaFieldChange( 'display_title', value ) } + /> ); }; diff --git a/src/editor/StatusSidebar.js b/src/editor/StatusSidebar.js index fdf1c541..94620bb6 100644 --- a/src/editor/StatusSidebar.js +++ b/src/editor/StatusSidebar.js @@ -15,12 +15,11 @@ const StatusSidebar = ( { frequency, newspack_popups_is_sitewide_default, onMetaFieldChange, - placement, + isOverlay, removeNotice, onSitewideDefaultChange, } ) => { const isTest = 'test' === frequency; - const isInline = 'inline' === placement; const createTestNotice = () => { createNotice( @@ -62,11 +61,11 @@ const StatusSidebar = ( { onMetaFieldChange( 'frequency', 'once' ); } } /> - { ! isInline && ( + { isOverlay && ( onSitewideDefaultChange( value ) } /> ) } diff --git a/src/editor/index.js b/src/editor/index.js index 6c478bea..c4c6a76e 100644 --- a/src/editor/index.js +++ b/src/editor/index.js @@ -6,8 +6,8 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; +import { withSelect, withDispatch } from '@wordpress/data'; import { registerPlugin } from '@wordpress/plugins'; import { PluginDocumentSettingPanel, PluginPostStatusInfo } from '@wordpress/edit-post'; @@ -22,6 +22,7 @@ import SegmentationSidebar from './SegmentationSidebar'; import DismissSidebar from './DismissSidebar'; import ColorsSidebar from './ColorsSidebar'; import Preview from './Preview'; +import EditorAdditions from './EditorAdditions'; import './style.scss'; // Action dispatchers for the sidebar components. @@ -39,36 +40,18 @@ const mapDispatchToProps = dispatch => { }; }; -// Connect data to components. -const StatusSidebarWithData = compose( [ - withSelect( optionsFieldsSelector ), - withDispatch( mapDispatchToProps ), -] )( StatusSidebar ); - -const SidebarWithData = compose( [ +const connectData = compose( [ withSelect( optionsFieldsSelector ), withDispatch( mapDispatchToProps ), -] )( Sidebar ); +] ); -const FrequencySidebarWithData = compose( [ - withSelect( optionsFieldsSelector ), - withDispatch( mapDispatchToProps ), -] )( FrequencySidebar ); - -const SegmentationSidebarWithData = compose( [ - withSelect( optionsFieldsSelector ), - withDispatch( mapDispatchToProps ), -] )( SegmentationSidebar ); - -const DismissSidebarWithData = compose( [ - withSelect( optionsFieldsSelector ), - withDispatch( mapDispatchToProps ), -] )( DismissSidebar ); - -const ColorsSidebarWithData = compose( [ - withSelect( optionsFieldsSelector ), - withDispatch( mapDispatchToProps ), -] )( ColorsSidebar ); +// Connect data to components. +const StatusSidebarWithData = connectData( StatusSidebar ); +const SidebarWithData = connectData( Sidebar ); +const FrequencySidebarWithData = connectData( FrequencySidebar ); +const SegmentationSidebarWithData = connectData( SegmentationSidebar ); +const DismissSidebarWithData = connectData( DismissSidebar ); +const ColorsSidebarWithData = connectData( ColorsSidebar ); // Register components. registerPlugin( 'newspack-popups-status', { render: StatusSidebarWithData } ); @@ -133,6 +116,11 @@ registerPlugin( 'newspack-popups-colors', { icon: null, } ); +registerPlugin( 'newspack-popups-editor', { + render: EditorAdditions, + icon: null, +} ); + // Add a button in post status section const PluginPostStatusInfoTest = () => ( diff --git a/src/editor/style.scss b/src/editor/style.scss index 65419e79..0938feac 100644 --- a/src/editor/style.scss +++ b/src/editor/style.scss @@ -1,7 +1,12 @@ -.block-editor-post-preview__button-toggle { +.block-editor-post-preview__button-toggle, +.edit-post-post-visibility { display: none; } +.editor-post-title__input::placeholder { + color: var( --newspack-popups-editor-placeholder-color, #7d7d7d ) !important; +} + .newspack-popups { &__status-options { margin: 1rem 0; @@ -10,4 +15,10 @@ margin-top: 4px; } } + + &__not-interested-button-preview { + cursor: not-allowed; + font-size: 0.7em; + text-decoration: underline; + } } diff --git a/src/editor/utils.js b/src/editor/utils.js index 20018a87..7b76fbd1 100644 --- a/src/editor/utils.js +++ b/src/editor/utils.js @@ -21,6 +21,11 @@ export const optionsFieldsSelector = select => { utm_suppression, selected_segment_id, } = meta || {}; + + const isInlinePlacement = placementValue => + [ 'inline', 'above_header' ].indexOf( placementValue ) >= 0; + const isOverlay = ! isInlinePlacement( placement ); + return { background_color, dismiss_text, @@ -38,6 +43,8 @@ export const optionsFieldsSelector = select => { trigger_type, utm_suppression, selected_segment_id, + isInlinePlacement, + isOverlay, }; }; @@ -64,8 +71,8 @@ export const updateEditorColors = backgroundColor => { if ( ! backgroundColor ) { return; } - const blackColor = '#000'; - const whiteColor = '#fff'; + const blackColor = '#000000'; + const whiteColor = '#ffffff'; const backgroundColorRGB = hexToRGB( backgroundColor ); const blackRGB = hexToRGB( blackColor ); @@ -84,22 +91,19 @@ export const updateEditorColors = backgroundColor => { const foregroundColor = contrastRatio > 5 ? blackColor : whiteColor; - const editorStylesEl = document.querySelector( '.edit-post-visual-editor.editor-styles-wrapper' ); + const editorStylesEl = document.querySelector( '.editor-styles-wrapper' ); const editorPostTitleEl = document.querySelector( '.wp-block.editor-post-title__block .editor-post-title__input' ); - const editorPostTitlePlaceholderEl = document.querySelector( - '.wp-block.editor-post-title__block .editor-post-title__input::placeholder' - ); - if ( editorStylesEl ) { editorStylesEl.style.backgroundColor = backgroundColor; editorStylesEl.style.color = foregroundColor; } if ( editorPostTitleEl ) { editorPostTitleEl.style.color = foregroundColor; - } - if ( editorPostTitlePlaceholderEl ) { - editorPostTitlePlaceholderEl.style.color = foregroundColor; + editorPostTitleEl.style.setProperty( + '--newspack-popups-editor-placeholder-color', + `${ foregroundColor }80` + ); } }; diff --git a/tests/test-api.php b/tests/test-api.php index 7b481177..0e1363e7 100644 --- a/tests/test-api.php +++ b/tests/test-api.php @@ -63,7 +63,7 @@ public static function wpSetUpBeforeClass() { // phpcs:ignore Squiz.Commenting.F public static function create_test_popup( $options, $post_content = 'Faucibus placerat senectus metus molestie varius tincidunt.' ) { // phpcs:ignore Squiz.Commenting.FunctionComment.Missing $popup_id = self::factory()->post->create( [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, 'post_title' => 'Platea fames', 'post_content' => $post_content, ] diff --git a/tests/test-insertion.php b/tests/test-insertion.php index 2e22363f..73f77059 100755 --- a/tests/test-insertion.php +++ b/tests/test-insertion.php @@ -21,7 +21,7 @@ public function setUp() { // phpcs:ignore Squiz.Commenting.FunctionComment.Missi ); self::$popup_id = self::factory()->post->create( [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, 'post_title' => 'Platea fames', 'post_content' => self::$popup_content, ] @@ -29,7 +29,14 @@ public function setUp() { // phpcs:ignore Squiz.Commenting.FunctionComment.Missi // Set the popup as sitewide default. Newspack_Popups_Model::set_sitewide_popup( self::$popup_id ); // Set popup frequency from default 'test'. - Newspack_Popups_Model::set_popup_options( self::$popup_id, [ 'frequency' => 'once' ] ); + Newspack_Popups_Model::set_popup_options( + self::$popup_id, + [ + 'frequency' => 'once', + 'trigger_type' => 'scroll', + 'trigger_scroll_progress' => 0, + ] + ); // Reset internal duplicate-prevention. Newspack_Popups_Inserter::$the_content_has_rendered = false; } diff --git a/tests/test-model.php b/tests/test-model.php index 17e1e892..53892590 100644 --- a/tests/test-model.php +++ b/tests/test-model.php @@ -14,7 +14,7 @@ class ModelTest extends WP_UnitTestCase { public static function wpSetUpBeforeClass() { // phpcs:ignore Squiz.Commenting.FunctionComment.Missing self::$popup_id = self::factory()->post->create( [ - 'post_type' => Newspack_Popups::NEWSPACK_PLUGINS_CPT, + 'post_type' => Newspack_Popups::NEWSPACK_POPUPS_CPT, 'post_title' => 'Platea fames', 'post_content' => 'Faucibus placerat senectus.', ]