diff --git a/includes/class-newspack.php b/includes/class-newspack.php index ac3464af7c..9056771890 100644 --- a/includes/class-newspack.php +++ b/includes/class-newspack.php @@ -114,6 +114,7 @@ private function includes() { include_once NEWSPACK_ABSPATH . 'includes/authors/class-authors-custom-fields.php'; include_once NEWSPACK_ABSPATH . 'includes/optional-modules/class-rss.php'; + include_once NEWSPACK_ABSPATH . 'includes/optional-modules/class-media-partners.php'; include_once NEWSPACK_ABSPATH . 'includes/starter_content/class-starter-content-provider.php'; include_once NEWSPACK_ABSPATH . 'includes/starter_content/class-starter-content-generated.php'; @@ -375,7 +376,6 @@ public static function load_common_assets() { [], NEWSPACK_PLUGIN_VERSION ); - } } Newspack::instance(); diff --git a/includes/optional-modules/class-media-partners.php b/includes/optional-modules/class-media-partners.php new file mode 100644 index 0000000000..cb3ddaa859 --- /dev/null +++ b/includes/optional-modules/class-media-partners.php @@ -0,0 +1,526 @@ + true, + 'labels' => [ + 'name' => esc_html_x( 'Media Partners', 'taxonomy general name', 'newspack-plugin' ), + 'singular_name' => esc_html_x( 'Media Partner', 'taxonomy singular name', 'newspack-plugin' ), + 'search_items' => esc_html__( 'Search Media Partners', 'newspack-plugin' ), + 'all_items' => esc_html__( 'All Media Partners', 'newspack-plugin' ), + 'parent_item' => esc_html__( 'Parent Media Partner', 'newspack-plugin' ), + 'parent_item_colon' => esc_html__( 'Parent Media Partner:', 'newspack-plugin' ), + 'edit_item' => esc_html__( 'Edit Media Partner', 'newspack-plugin' ), + 'view_item' => esc_html__( 'View Media Partner', 'newspack-plugin' ), + 'update_item' => esc_html__( 'Update Media Partner', 'newspack-plugin' ), + 'add_new_item' => esc_html__( 'Add New Media Partner', 'newspack-plugin' ), + 'new_item_name' => esc_html__( 'New Media Partner Name', 'newspack-plugin' ), + 'menu_name' => esc_html__( 'Media Partners' ), + ], + 'public' => true, + 'show_admin_column' => true, + 'show_in_nav_menus' => true, + 'query_var' => true, + 'rewrite' => [ 'slug' => 'partners' ], + 'show_in_rest' => true, + ] + ); + } + + /** + * Render a settings field. + * + * @param string $key The key for the field. + * @param string $label The label for the field. + * @param array $partner The partner data. + * @param string $context The context for the field. + */ + private static function render_settings_field( $key, $label, $partner = [], $context = 'new_partner' ) { + $tag = 'input'; + $value = isset( $partner[ $key ] ) ? $partner[ $key ] : ''; + if ( in_array( $key, [ 'attribution_message' ] ) ) { + $tag = 'textarea'; + } + + ob_start(); + if ( 'textarea' === $tag ) { + ?> + + + + +
+ + +
+ + + + + + __( 'This story also appeared in', 'newspack-plugin' ), + ]; + } + + /** + * Get partner logo upload setting JS script. + */ + private static function get_logo_upload_script() { + ob_start() + ?> + + +
+ + + + + + +
+ + term_id, 'logo', true ); + $logo = ''; + if ( $logo_id ) { + $logo_atts = wp_get_attachment_image_src( $logo_id ); + if ( $logo_atts ) { + $logo = $logo_atts[0]; + } + } + + ?> + + + + + + + + + + + +
+ +
+ + + + + esc_url( get_term_meta( $partner->term_id, 'partner_homepage_url', true ) ), + 'attribution_message' => get_term_meta( $partner->term_id, 'attribution_message', true ), + ]; + if ( ! metadata_exists( 'term', $partner->term_id, 'attribution_message' ) ) { + $partner_settings['attribution_message'] = $defaults['attribution_message']; + } + return $partner_settings; + } + + /** + * Save the meta fields for the Partner taxonomy. + * + * @param int $term_id Term ID. + */ + public static function save_partner_meta_fields( $term_id ) { + if ( ! current_user_can( 'edit_posts' ) ) { + return; + } + + $partner_logo = filter_input( INPUT_POST, 'partner_logo', FILTER_SANITIZE_NUMBER_INT ); + if ( $partner_logo ) { + update_term_meta( $term_id, 'logo', (int) $partner_logo ); + } else { + delete_term_meta( $term_id, 'logo' ); + } + + $partner_url = filter_input( INPUT_POST, 'partner_url', FILTER_SANITIZE_STRING ); + if ( $partner_url ) { + update_term_meta( $term_id, 'partner_homepage_url', esc_url( $partner_url ) ); + } + + $attribution_message = filter_input( INPUT_POST, 'attribution_message', FILTER_SANITIZE_STRING ); + if ( $attribution_message ) { + update_term_meta( $term_id, 'attribution_message', $attribution_message ); + } + } + + /** + * Register the 'partners' shortcode. + * Can be inserted into a post or page to display a list of partners. + */ + public static function add_partners_shortcode() { + add_shortcode( 'partners', [ __CLASS__, 'render_partners_shortcode' ] ); + } + + /** + * Get partner logo, if set to be displayed. + * + * @param WP_Term $partner The partner object. + */ + private static function get_partner_logo( $partner ) { + return get_term_meta( $partner->term_id, 'logo', true ); + } + + /** + * Render the 'partners' shortcode. + */ + public static function render_partners_shortcode() { + $partners = get_terms( + [ + 'taxonomy' => 'partner', + 'hide_empty' => false, + ] + ); + + ob_start(); + + ?> + + term_id, 'partner_homepage_url', true ); + + if ( $partner_logo ) { + $logo_html = ''; + $logo_atts = wp_get_attachment_image_src( $partner_logo, 'full' ); + $logo_alt = $partner->name; + + if ( $partner_url ) { + $logo_alt = sprintf( + /* translators: replaced with the name of the Media Partner */ + __( 'Website for %s', 'newspack-plugin' ), + $partner->name + ); + } + + if ( $logo_atts ) { + $logo_html = '
' . esc_attr( $logo_alt ) . '
'; + } + + if ( $logo_html && $partner_url ) { + $logo_html = '' . $logo_html . ''; + } + + $partner_html .= $logo_html; + } + + $partner_name = $partner->name; + if ( $partner_url ) { + $partner_name = '' . $partner_name . ''; + } + $partner_html .= '

' . $partner_name . '

'; + + $elements[] = $partner_html; + } + + $num_columns = 3; + $current = 0; + $container_closed = true; + foreach ( $elements as $element ) { + if ( 0 == $current ) { + echo '
'; + $container_closed = false; + } + + echo '
'; + echo wp_kses_post( $element ); + echo '
'; + + ++$current; + + if ( $num_columns == $current ) { + echo '

'; + $current = 0; + $container_closed = true; + } + } + + // Close last div if needed. + if ( ! $container_closed ) { + echo '
'; + } + + return ob_get_clean(); + } + + /** + * Filter in a partner logo on posts that have partners. + * + * @param string $content The post content. + * @return string Modified $content. + */ + public static function add_content_partner_logo( $content ) { + $id = get_the_ID(); + $partners = get_the_terms( $id, 'partner' ); + if ( ! $partners ) { + return $content; + } + + $partner_images = []; + $partner_names = []; + foreach ( $partners as $partner ) { + $partner_image_id = self::get_partner_logo( $partner ); + $partner_url = esc_url( get_term_meta( $partner->term_id, 'partner_homepage_url', true ) ); + $image = ''; + $image_alt = $partner->name; + + if ( $partner_url ) { + $image_alt = sprintf( + /* translators: replaced with the name of the Media Partner */ + __( 'Website for %s', 'newspack-plugin' ), + $partner->name + ); + } + + if ( $partner_image_id ) { + $image = wp_get_attachment_image( $partner_image_id, [ 200, 999 ], false, [ 'alt' => esc_attr( $image_alt ) ] ); + if ( $image && $partner_url ) { + $image = '' . $image . ''; + } + } + + $partner_images[] = $image; + + $partner_name = $partner->name; + if ( $partner_url ) { + $partner_name = '' . $partner_name . ''; + } + $partner_names[] = $partner_name; + } + + $partner_settings = self::get_partner_config( $partner ); + + // Skip partners in RSS feed. + $settings = self::get_settings(); + if ( $settings['skip_in_feeds'] && is_feed() ) { + return $content; + } + + ob_start(); + ?> +
+
+
+ ', $partner_images ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> +
+ +
+
+
+
+ + \s*

#', $content, 2 ); + + // Just append it to the top if a good injection spot can't be found.. + if ( 1 === count( $content_halves ) ) { + $content = $partner_html . $content; + } else { + $content = $content_halves[0] . '

' . $partner_html . '

' . $content_halves[1]; + } + + return $content; + } + + /** + * Add global settings UI. + */ + public static function add_global_settings() { + $settings = self::get_settings(); + ?> +

+

+
+ + + +
+ +
+

+ +

+
+
+ get_option( 'newspack_media_partners_skip_in_feeds', false ), + ]; + } + + /** + * Handle settings update. + */ + public static function handle_settings_update() { // phpcs:ignore WordPressVIPMinimum.Hooks.AlwaysReturnInFilter.MissingReturnStatement + $media_partners_settings = filter_input( INPUT_POST, 'media_partners_settings', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); + if ( ! current_user_can( 'manage_options' ) || ! $media_partners_settings ) { + return true; + } + if ( ! wp_verify_nonce( filter_input( INPUT_POST, '_wpnonce_partners-settings', FILTER_SANITIZE_FULL_SPECIAL_CHARS ), 'partners-settings' ) ) { + return true; + } + + $skip_in_feeds = filter_input( INPUT_POST, 'skip_in_feeds', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); + update_option( 'newspack_media_partners_skip_in_feeds', boolval( $skip_in_feeds ) ); + + wp_safe_redirect( admin_url( 'edit-tags.php?taxonomy=partner' ) ); + exit; + } +} +Media_Partners::init(); diff --git a/includes/wizards/class-settings.php b/includes/wizards/class-settings.php index 05c9a3613f..73230224c3 100644 --- a/includes/wizards/class-settings.php +++ b/includes/wizards/class-settings.php @@ -47,9 +47,10 @@ public function __construct() { */ private static function get_settings() { $default_settings = [ - self::MODULE_ENABLED_PREFIX . 'rss' => false, + self::MODULE_ENABLED_PREFIX . 'rss' => false, + self::MODULE_ENABLED_PREFIX . 'media-partners' => false, ]; - return get_option( self::SETTINGS_OPTION_NAME, $default_settings ); + return wp_parse_args( get_option( self::SETTINGS_OPTION_NAME ), $default_settings ); } /** diff --git a/tests/unit-tests/settings.php b/tests/unit-tests/settings.php index a3db0a905d..8730f011ce 100644 --- a/tests/unit-tests/settings.php +++ b/tests/unit-tests/settings.php @@ -24,7 +24,10 @@ public function set_up() { public function test_settings_defaults() { self::assertEquals( Settings::api_get_settings(), - [ 'module_enabled_rss' => false ], + [ + 'module_enabled_rss' => false, + 'module_enabled_media-partners' => false, + ], 'Default settings are as expected.' ); } @@ -38,7 +41,10 @@ public function test_settings_update() { Settings::api_update_settings( $request ); self::assertEquals( Settings::api_get_settings(), - [ 'module_enabled_rss' => true ], + [ + 'module_enabled_rss' => true, + 'module_enabled_media-partners' => false, + ], 'Settings is updated.' ); @@ -46,7 +52,10 @@ public function test_settings_update() { Settings::api_update_settings( $request ); self::assertEquals( Settings::api_get_settings(), - [ 'module_enabled_rss' => true ], + [ + 'module_enabled_rss' => true, + 'module_enabled_media-partners' => false, + ], 'A non-existent setting is not saved.' ); }