From 2d7e857e96409dd40ec502c65669f19c7f08308c Mon Sep 17 00:00:00 2001
From: Rasmy Nguyen
Date: Wed, 18 Dec 2024 15:52:11 -0500
Subject: [PATCH 01/12] feat(corrections): add base code and feature flag
---
includes/class-newspack.php | 1 +
includes/corrections/class-corrections.php | 314 +++++++++++++++++++++
2 files changed, 315 insertions(+)
create mode 100644 includes/corrections/class-corrections.php
diff --git a/includes/class-newspack.php b/includes/class-newspack.php
index 429d858e2f..f4e4bb8926 100644
--- a/includes/class-newspack.php
+++ b/includes/class-newspack.php
@@ -125,6 +125,7 @@ private function includes() {
include_once NEWSPACK_ABSPATH . 'includes/tracking/class-twitter-pixel.php';
include_once NEWSPACK_ABSPATH . 'includes/revisions-control/class-revisions-control.php';
include_once NEWSPACK_ABSPATH . 'includes/authors/class-authors-custom-fields.php';
+ include_once NEWSPACK_ABSPATH . 'includes/corrections/class-corrections.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';
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
new file mode 100644
index 0000000000..032b01647a
--- /dev/null
+++ b/includes/corrections/class-corrections.php
@@ -0,0 +1,314 @@
+ -1,
+ 'meta_key' => self::CORRECTION_ACTIVE_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ 'meta_value' => 1, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
+ 'fields' => 'ids',
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ ]
+ );
+
+ ob_start();
+ foreach ( $post_ids as $post_id ) :
+ $corrections = get_post_meta( $post_id, self::CORRECTION_META, true );
+ if ( empty( $corrections ) ) {
+ continue;
+ }
+
+ ?>
+
+
+
+ ID, self::CORRECTION_ACTIVE_META, true );
+ $existing_corrections = get_post_meta( $post->ID, self::CORRECTION_META, true );
+ if ( ! is_array( $existing_corrections ) ) {
+ $existing_corrections = [];
+ }
+ ?>
+
+
+
+
+
+
+ [
+ 'flags' => FILTER_REQUIRE_ARRAY,
+ 'filter' => FILTER_SANITIZE_STRING,
+ ],
+ 'reveal_correction_date' => [
+ 'flags' => FILTER_REQUIRE_ARRAY,
+ 'filter' => FILTER_SANITIZE_STRING,
+ ],
+ ]
+ );
+
+ $corrections = [];
+ foreach ( $corrections_data['reveal_correction'] as $index => $correction_text ) {
+ $corrections[] = [
+ 'correction' => sanitize_textarea_field( $correction_text ),
+ 'date' => ! empty( $corrections_data['reveal_correction_date'][ $index ] ) ? sanitize_text_field( $corrections_data['reveal_correction_date'][ $index ] ) : gmdate( 'Y-m-d' ),
+ ];
+ }
+
+ update_post_meta( $post_id, self::CORRECTION_ACTIVE_META, $is_active );
+ update_post_meta( $post_id, self::CORRECTION_META, $corrections );
+ }
+
+ /**
+ * Outputs corrections on the post content.
+ *
+ * @param string $content The post content.
+ *
+ * @return string The post content with corrections.
+ */
+ public static function output_corrections_on_post( $content ) {
+ if ( is_admin() || ! is_single() ) {
+ return $content;
+ }
+
+ $corrections_active = get_post_meta( get_the_ID(), self::CORRECTION_ACTIVE_META, true );
+ if ( ! $corrections_active ) {
+ return $content;
+ }
+
+ $corrections = get_post_meta( get_the_ID(), self::CORRECTION_META ) ?? [];
+ $has_valid_correction = false;
+ foreach ( $corrections as $correction ) {
+ if ( ! empty( trim( $correction['correction'] ) ) ) {
+ $has_valid_correction = true;
+ break;
+ }
+ }
+
+ if ( ! $has_valid_correction ) {
+ return $content;
+ }
+
+ ob_start();
+ ?>
+
+
+
+
Date: Wed, 18 Dec 2024 16:28:34 -0500
Subject: [PATCH 02/12] feat: add corrections custom post type
---
includes/corrections/class-corrections.php | 74 +++++++++++++++++++++-
1 file changed, 71 insertions(+), 3 deletions(-)
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
index 032b01647a..651eed1ff0 100644
--- a/includes/corrections/class-corrections.php
+++ b/includes/corrections/class-corrections.php
@@ -11,6 +11,11 @@
* Class to handle Corrections and Clarifications.
*/
class Corrections {
+ /**
+ * Post type for corrections.
+ */
+ const POST_TYPE = 'np_correction';
+
/**
* Meta key for storing corrections.
*/
@@ -28,10 +33,11 @@ public static function init() {
if ( ! self::is_enabled() ) {
return;
}
+ add_action( 'init', [ __CLASS__, 'register_post_type' ] );
+ add_action( 'init', [ __CLASS__, 'add_corrections_shortcode' ] );
add_action( 'add_meta_boxes', [ __CLASS__, 'add_corrections_metabox' ] );
add_action( 'save_post', [ __CLASS__, 'save_corrections_metabox' ] );
add_filter( 'the_content', [ __CLASS__, 'output_corrections_on_post' ] );
- add_action( 'init', [ __CLASS__, 'add_corrections_shortcode' ] );
}
/**
@@ -46,6 +52,68 @@ public static function is_enabled() {
return defined( 'NEWSPACK_CORRECTIONS_ENABLED' ) && NEWSPACK_CORRECTIONS_ENABLED;
}
+ /**
+ * Registers the corrections post type.
+ *
+ * @return void
+ */
+ public static function register_post_type() {
+ $supports = [
+ 'author',
+ 'editor',
+ 'title',
+ 'revisions',
+ ];
+
+ $labels = [
+ 'name' => _x( 'Corrections', 'post type general name', 'newspack-plugin' ),
+ 'singular_name' => _x( 'Correction', 'post type singular name', 'newspack-plugin' ),
+ 'menu_name' => _x( 'Corrections', 'admin menu', 'newspack-plugin' ),
+ 'name_admin_bar' => _x( 'Correction', 'add new on admin bar', 'newspack-plugin' ),
+ 'add_new' => _x( 'Add New', 'correction', 'newspack-plugin' ),
+ 'add_new_item' => __( 'Add New Correction', 'newspack-plugin' ),
+ 'new_item' => __( 'New Correction', 'newspack-plugin' ),
+ 'edit_item' => __( 'Edit Correction', 'newspack-plugin' ),
+ 'view_item' => __( 'View Correction', 'newspack-plugin' ),
+ 'view_items' => __( 'View Correction', 'newspack-plugin' ),
+ 'all_items' => __( 'All Corrections', 'newspack-plugin' ),
+ 'search_items' => __( 'Search Corrections', 'newspack-plugin' ),
+ 'parent_item_colon' => __( 'Parent Correction:', 'newspack-plugin' ),
+ 'not_found' => __( 'No corrections found.', 'newspack-plugin' ),
+ 'not_found_in_trash' => __( 'No corrections found in Trash.', 'newspack-plugin' ),
+ 'archives' => __( 'Correction Archives', 'newspack-plugin' ),
+ 'attributes' => __( 'Correction Attributes', 'newspack-plugin' ),
+ 'insert_into_item' => __( 'Insert into correction', 'newspack-plugin' ),
+ 'uploaded_to_this_item' => __( 'Uploaded to this correction', 'newspack-plugin' ),
+ 'filter_items_list' => __( 'Filter corrections list', 'newspack-plugin' ),
+ 'items_list_navigation' => __( 'Corrections list navigation', 'newspack-plugin' ),
+ 'items_list' => __( 'Corrections list', 'newspack-plugin' ),
+ 'item_published' => __( 'Correction published.', 'newspack-plugin' ),
+ 'item_published_privately' => __( 'Correction published privately.', 'newspack-plugin' ),
+ 'item_reverted_to_draft' => __( 'Correction reverted to draft.', 'newspack-plugin' ),
+ 'item_scheduled' => __( 'Correction scheduled.', 'newspack-plugin' ),
+ 'item_updated' => __( 'Correction updated.', 'newspack-plugin' ),
+ 'item_link' => __( 'Correction Link', 'newspack-plugin' ),
+ 'item_link_description' => __( 'A link to a correction.', 'newspack-plugin' ),
+ ];
+
+ $args = array(
+ 'labels' => $labels,
+ 'description' => 'Post type used to store corrections and clarifications.',
+ 'has_archive' => true,
+ 'public' => true,
+ 'public_queryable' => true,
+ 'query_var' => true,
+ 'rewrite' => [ 'slug' => 'correction' ],
+ 'show_ui' => true,
+ 'show_in_rest' => true,
+ 'supports' => $supports,
+ 'taxonomies' => [],
+ 'menu_icon' => 'dashicons-edit',
+ );
+ \register_post_type( self::POST_TYPE, $args );
+ }
+
/**
* Adds the corrections shortcode.
*/
@@ -94,8 +162,8 @@ public static function handle_corrections_shortcode() {
-
-
+
+
Date: Wed, 18 Dec 2024 17:44:43 -0500
Subject: [PATCH 03/12] fix: refactor scripts and styles
---
includes/corrections/class-corrections.php | 166 +++++++++++----------
src/other-scripts/corrections/index.js | 34 +++++
src/other-scripts/corrections/style.scss | 37 +++++
3 files changed, 158 insertions(+), 79 deletions(-)
create mode 100644 src/other-scripts/corrections/index.js
create mode 100644 src/other-scripts/corrections/style.scss
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
index 651eed1ff0..9ea69b9281 100644
--- a/includes/corrections/class-corrections.php
+++ b/includes/corrections/class-corrections.php
@@ -14,17 +14,17 @@ class Corrections {
/**
* Post type for corrections.
*/
- const POST_TYPE = 'np_correction';
+ const POST_TYPE = 'newspack_correction';
/**
* Meta key for storing corrections.
*/
- const CORRECTION_META = 'article-corrections';
+ const POST_ID_META = 'newspack_correction-post-id';
/**
- * Meta key for storing whether corrections are active.
+ * Meta key for corrections active postmeta.
*/
- const CORRECTION_ACTIVE_META = 'has_corrections';
+ const CORRECTIONS_ACTIVE_META = 'newspack_corrections_active';
/**
* Initializes the class.
@@ -38,6 +38,8 @@ public static function init() {
add_action( 'add_meta_boxes', [ __CLASS__, 'add_corrections_metabox' ] );
add_action( 'save_post', [ __CLASS__, 'save_corrections_metabox' ] );
add_filter( 'the_content', [ __CLASS__, 'output_corrections_on_post' ] );
+ add_action( 'wp_enqueue_scripts', [ __CLASS__, 'wp_enqueue_scripts' ] );
+ add_action( 'admin_enqueue_scripts', [ __CLASS__, 'wp_enqueue_scripts' ] );
}
/**
@@ -52,6 +54,29 @@ public static function is_enabled() {
return defined( 'NEWSPACK_CORRECTIONS_ENABLED' ) && NEWSPACK_CORRECTIONS_ENABLED;
}
+
+ /**
+ * Enqueue scripts and styles.
+ */
+ public static function wp_enqueue_scripts() {
+ if ( ! is_admin() || ! isset( $_GET['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
+ return;
+ }
+ \wp_enqueue_script(
+ 'newspack-corrections',
+ Newspack::plugin_url() . '/dist/other-scripts/corrections.js',
+ [],
+ NEWSPACK_PLUGIN_VERSION,
+ true
+ );
+ \wp_enqueue_style(
+ 'newspack-corrections',
+ Newspack::plugin_url() . '/dist/other-scripts/corrections.css',
+ [],
+ NEWSPACK_PLUGIN_VERSION
+ );
+ }
+
/**
* Registers the corrections post type.
*
@@ -63,6 +88,7 @@ public static function register_post_type() {
'editor',
'title',
'revisions',
+ 'custom-fields',
];
$labels = [
@@ -114,6 +140,48 @@ public static function register_post_type() {
\register_post_type( self::POST_TYPE, $args );
}
+ /**
+ * Get corrections for post.
+ *
+ * @param int $post_id The post ID.
+ *
+ * @return array The corrections.
+ */
+ public static function get_corrections( $post_id ) {
+ return get_posts(
+ [
+ 'posts_per_page' => -1,
+ 'post_type' => self::POST_TYPE,
+ 'meta_key' => self::POST_ID_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ 'meta_value' => $post_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ ]
+ );
+ }
+
+ /**
+ * Save corrections for post.
+ *
+ * @param int $post_id The post ID.
+ * @param array $corrections The corrections.
+ */
+ public static function save_corrections( $post_id, $corrections ) {
+ foreach ( $corrections as $correction ) {
+ $post_id = wp_insert_post(
+ [
+ 'post_title' => 'Correction for ' . get_the_title( $post_id ),
+ 'post_content' => $correction,
+ 'post_type' => self::POST_TYPE,
+ 'post_status' => 'publish',
+ 'meta_input' => [
+ self::POST_ID_META => $post_id,
+ ],
+ ]
+ );
+ }
+ }
+
/**
* Adds the corrections shortcode.
*/
@@ -132,7 +200,7 @@ public static function handle_corrections_shortcode() {
$post_ids = get_posts(
[
'posts_per_page' => -1,
- 'meta_key' => self::CORRECTION_ACTIVE_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ 'meta_key' => self::CORRECTIONS_ACTIVE_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
'meta_value' => 1, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
'fields' => 'ids',
'orderby' => 'date',
@@ -142,7 +210,7 @@ public static function handle_corrections_shortcode() {
ob_start();
foreach ( $post_ids as $post_id ) :
- $corrections = get_post_meta( $post_id, self::CORRECTION_META, true );
+ $corrections = self::get_corrections( $post_id );
if ( empty( $corrections ) ) {
continue;
}
@@ -195,53 +263,13 @@ public static function add_corrections_metabox( $post_type ) {
* @param \WP_Post $post The post object.
*/
public static function render_corrections_metabox( $post ) {
- $is_active = (bool) get_post_meta( $post->ID, self::CORRECTION_ACTIVE_META, true );
- $existing_corrections = get_post_meta( $post->ID, self::CORRECTION_META, true );
- if ( ! is_array( $existing_corrections ) ) {
- $existing_corrections = [];
- }
+ $is_active = (bool) get_post_meta( $post->ID, self::CORRECTIONS_ACTIVE_META, true );
+ $existing_corrections = self::get_corrections( $post->ID );
?>
-
-
-
+
-
-
-
[
+ 'correction' => [
'flags' => FILTER_REQUIRE_ARRAY,
'filter' => FILTER_SANITIZE_STRING,
],
- 'reveal_correction_date' => [
+ 'correction_date' => [
'flags' => FILTER_REQUIRE_ARRAY,
'filter' => FILTER_SANITIZE_STRING,
],
@@ -316,8 +324,8 @@ public static function save_corrections_metabox( $post_id ) {
];
}
- update_post_meta( $post_id, self::CORRECTION_ACTIVE_META, $is_active );
- update_post_meta( $post_id, self::CORRECTION_META, $corrections );
+ self::save_corrections( $post_id, $corrections );
+ update_post_meta( $post_id, self::CORRECTIONS_ACTIVE_META, true );
}
/**
@@ -332,12 +340,12 @@ public static function output_corrections_on_post( $content ) {
return $content;
}
- $corrections_active = get_post_meta( get_the_ID(), self::CORRECTION_ACTIVE_META, true );
+ $corrections_active = get_post_meta( get_the_ID(), self::CORRECTIONS_ACTIVE_META, true );
if ( ! $corrections_active ) {
return $content;
}
- $corrections = get_post_meta( get_the_ID(), self::CORRECTION_META ) ?? [];
+ $corrections = self::get_corrections( get_the_ID() );
$has_valid_correction = false;
foreach ( $corrections as $correction ) {
if ( ! empty( trim( $correction['correction'] ) ) ) {
diff --git a/src/other-scripts/corrections/index.js b/src/other-scripts/corrections/index.js
new file mode 100644
index 0000000000..b101ee27dd
--- /dev/null
+++ b/src/other-scripts/corrections/index.js
@@ -0,0 +1,34 @@
+/**
+ * External dependencies
+ */
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import { domReady } from '../../utils';
+import './style.scss';
+
+domReady( () => {
+ // Handle admin metabox for article corrections.
+ const metaboxContainer = document.querySelector( '.corrections-metabox-container' );
+ if ( metaboxContainer ) {
+ metaboxContainer.querySelector( 'button.add-correction' ).addEventListener( 'click', () => {
+ const existingCorrections = metaboxContainer.querySelector( '.existing-corrections' );
+ const newCorrection = document.createElement( 'div' );
+ newCorrection.classList.add( 'reveal-correction' );
+ newCorrection.innerHTML = `
+ ${ __( 'Article Correction', 'newspack-plugin' ) }
+
+
+ ${ __( 'Date:', 'newspack-plugin' ) }
+ X
+ `;
+ existingCorrections.appendChild( newCorrection );
+ newCorrection.querySelector( 'span.delete-correction' ).addEventListener( 'click', () => {
+ newCorrection.remove();
+ } );
+ } );
+ }
+} );
+
diff --git a/src/other-scripts/corrections/style.scss b/src/other-scripts/corrections/style.scss
new file mode 100644
index 0000000000..0e02b6602e
--- /dev/null
+++ b/src/other-scripts/corrections/style.scss
@@ -0,0 +1,37 @@
+// Admin metabox styles
+.corrections-metabox-container {
+ .activate-corrections {
+ padding-top: 1em;
+ padding-bottom: 1em;
+ border-bottom: 2px solid silver;
+ margin-bottom: 1em;
+ }
+
+ .reveal-correction {
+ position: relative;
+ border-bottom: 1px solid silver;
+ padding-top: 1em;
+ padding-bottom: 1em;
+ }
+
+ .add-correction {
+ margin-top: 2em;
+ cursor: pointer;
+ }
+
+ .delete-correction {
+ position: absolute;
+ top: 2em;
+ right: 2em;
+ font-weight: bold;
+ color: silver;
+ border: 1px solid silver;
+ padding-left: 0.25em;
+ padding-right: 0.25em;
+ cursor: pointer;
+ }
+
+ .delete-correction:hover {
+ color: red;
+ }
+}
From efdc46c2af3e4c402be429cbc876638a20db26d2 Mon Sep 17 00:00:00 2001
From: Rasmy Nguyen
Date: Tue, 7 Jan 2025 17:36:39 -0500
Subject: [PATCH 04/12] feat(corrections): render on frontend
---
includes/corrections/class-corrections.php | 146 +++++++++++++--------
src/other-scripts/corrections/index.js | 39 +++++-
src/other-scripts/corrections/style.scss | 6 +-
3 files changed, 128 insertions(+), 63 deletions(-)
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
index 9ea69b9281..a5f6ea5fab 100644
--- a/includes/corrections/class-corrections.php
+++ b/includes/corrections/class-corrections.php
@@ -17,12 +17,17 @@ class Corrections {
const POST_TYPE = 'newspack_correction';
/**
- * Meta key for storing corrections.
+ * Meta key for correction date meta.
*/
- const POST_ID_META = 'newspack_correction-post-id';
+ const CORRECTION_DATE_META = 'newspack_correction_date';
/**
- * Meta key for corrections active postmeta.
+ * Meta key for correction post ID meta.
+ */
+ const CORRECTION_POST_ID_META = 'newspack_correction-post-id';
+
+ /**
+ * Meta key for post corrections active meta.
*/
const CORRECTIONS_ACTIVE_META = 'newspack_corrections_active';
@@ -152,7 +157,7 @@ public static function get_corrections( $post_id ) {
[
'posts_per_page' => -1,
'post_type' => self::POST_TYPE,
- 'meta_key' => self::POST_ID_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ 'meta_key' => self::CORRECTION_POST_ID_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
'meta_value' => $post_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
'orderby' => 'date',
'order' => 'DESC',
@@ -171,17 +176,29 @@ public static function save_corrections( $post_id, $corrections ) {
$post_id = wp_insert_post(
[
'post_title' => 'Correction for ' . get_the_title( $post_id ),
- 'post_content' => $correction,
+ 'post_content' => $correction['content'],
'post_type' => self::POST_TYPE,
'post_status' => 'publish',
'meta_input' => [
- self::POST_ID_META => $post_id,
+ self::CORRECTION_POST_ID_META => $post_id,
+ self::CORRECTION_DATE_META => $correction['date'],
],
]
);
}
}
+ /**
+ * Delete corrections for post.
+ *
+ * @param array $correction_ids Correction IDs.
+ */
+ public static function delete_corrections( $correction_ids ) {
+ foreach ( $correction_ids as $id ) {
+ wp_delete_post( $id, true );
+ }
+ }
+
/**
* Adds the corrections shortcode.
*/
@@ -247,7 +264,7 @@ public static function add_corrections_metabox( $post_type ) {
$valid_post_types = [ 'article_legacy', 'content_type_blog', 'post', 'press_release' ];
if ( in_array( $post_type, $valid_post_types, true ) ) {
add_meta_box(
- 'reveal_corrections',
+ 'corrections',
'Corrections',
[ __CLASS__, 'render_corrections_metabox' ],
$post_type,
@@ -263,29 +280,37 @@ public static function add_corrections_metabox( $post_type ) {
* @param \WP_Post $post The post object.
*/
public static function render_corrections_metabox( $post ) {
- $is_active = (bool) get_post_meta( $post->ID, self::CORRECTIONS_ACTIVE_META, true );
- $existing_corrections = self::get_corrections( $post->ID );
+ $is_active = (bool) get_post_meta( $post->ID, self::CORRECTIONS_ACTIVE_META, true );
+ $corrections = self::get_corrections( $post->ID );
?>
[
+ 'new-corrections' => [
'flags' => FILTER_REQUIRE_ARRAY,
'filter' => FILTER_SANITIZE_STRING,
],
- 'correction_date' => [
+ 'deleted-corrections' => [
'flags' => FILTER_REQUIRE_ARRAY,
- 'filter' => FILTER_SANITIZE_STRING,
+ 'filter' => FILTER_SANITIZE_NUMBER_INT,
],
+ self::CORRECTIONS_ACTIVE_META => FILTER_SANITIZE_NUMBER_INT,
]
);
-
- $corrections = [];
- foreach ( $corrections_data['reveal_correction'] as $index => $correction_text ) {
- $corrections[] = [
- 'correction' => sanitize_textarea_field( $correction_text ),
- 'date' => ! empty( $corrections_data['reveal_correction_date'][ $index ] ) ? sanitize_text_field( $corrections_data['reveal_correction_date'][ $index ] ) : gmdate( 'Y-m-d' ),
- ];
+ // Return early if there is no corrections data.
+ if ( ! $corrections_data ) {
+ return;
+ }
+ // Save new corrections if present.
+ if ( ! empty( $corrections_data['new-corrections'] ) ) {
+ $corrections = [];
+ foreach ( $corrections_data['new-corrections'] as $correction ) {
+ // Don't save empty corrections.
+ if ( empty( trim( $correction['content'] ) ) ) {
+ continue;
+ }
+ $corrections[] = [
+ 'content' => sanitize_textarea_field( $correction['content'] ),
+ 'date' => ! empty( $correction['date'] ) ? sanitize_text_field( $correction['date'] ) : gmdate( 'Y-m-d' ),
+ ];
+ }
+ self::save_corrections( $post_id, $corrections );
+ }
+ // Delete corrections if present.
+ if ( ! empty( $corrections_data['deleted-corrections'] ) ) {
+ $correction_ids = array_map( 'intval', $corrections_data['deleted-corrections'] );
+ self::delete_corrections( $correction_ids );
+ }
+ // Update active flag if present.
+ if ( isset( $corrections_data[ self::CORRECTIONS_ACTIVE_META ] ) ) {
+ update_post_meta( $post_id, self::CORRECTIONS_ACTIVE_META, (bool) $corrections_data[ self::CORRECTIONS_ACTIVE_META ] );
}
-
- self::save_corrections( $post_id, $corrections );
- update_post_meta( $post_id, self::CORRECTIONS_ACTIVE_META, true );
}
/**
@@ -340,21 +383,12 @@ public static function output_corrections_on_post( $content ) {
return $content;
}
- $corrections_active = get_post_meta( get_the_ID(), self::CORRECTIONS_ACTIVE_META, true );
- if ( ! $corrections_active ) {
+ if ( ! (bool) get_post_meta( get_the_ID(), self::CORRECTIONS_ACTIVE_META, true ) ) {
return $content;
}
- $corrections = self::get_corrections( get_the_ID() );
- $has_valid_correction = false;
- foreach ( $corrections as $correction ) {
- if ( ! empty( trim( $correction['correction'] ) ) ) {
- $has_valid_correction = true;
- break;
- }
- }
-
- if ( ! $has_valid_correction ) {
+ $corrections = self::get_corrections( get_the_ID() );
+ if ( empty( $corrections ) ) {
return $content;
}
@@ -365,18 +399,20 @@ public static function output_corrections_on_post( $content ) {
post_content;
+ $correction_date = get_post_meta( $correction->ID, self::CORRECTION_DATE_META, true );
+ $correction_heading = sprintf(
+ // translators: %s: correction date.
+ __( 'Correction on %s', 'newspack-plugin' ),
+ gmdate( 'M j, Y', strtotime( $correction_date ) )
+ );
?>
-
+
diff --git a/src/other-scripts/corrections/index.js b/src/other-scripts/corrections/index.js
index b101ee27dd..adb1688919 100644
--- a/src/other-scripts/corrections/index.js
+++ b/src/other-scripts/corrections/index.js
@@ -13,21 +13,46 @@ domReady( () => {
// Handle admin metabox for article corrections.
const metaboxContainer = document.querySelector( '.corrections-metabox-container' );
if ( metaboxContainer ) {
+ // Handle deletion of existing corrections.
+ metaboxContainer.querySelectorAll( '.existing-corrections button.delete-correction' )
+ .forEach( button => {
+ button.addEventListener( 'click', e => {
+ // Get the partent .correction element.
+ const correction = e.target.closest( '.correction' );
+ if ( correction ) {
+ correction.remove();
+ const correctionId = correction.getAttribute( 'name' ).replace( 'existing-corrections[', '' ).replace( ']', '' );
+ if ( correctionId ) {
+ const deletedCorrections = metaboxContainer.querySelector( '.deleted-corrections' );
+ const deletedCorrection = document.createElement( 'input' );
+ deletedCorrection.type = 'hidden';
+ deletedCorrection.name = 'deleted-corrections[]';
+ deletedCorrection.value = correctionId;
+ deletedCorrections.appendChild( deletedCorrection );
+ }
+ }
+ } );
+ } );
+ // Handle addition of new corrections.
+ let newCorrectionsCount = 0;
metaboxContainer.querySelector( 'button.add-correction' ).addEventListener( 'click', () => {
- const existingCorrections = metaboxContainer.querySelector( '.existing-corrections' );
+ const newCorrections = metaboxContainer.querySelector( '.new-corrections' );
const newCorrection = document.createElement( 'div' );
- newCorrection.classList.add( 'reveal-correction' );
+ newCorrection.classList.add( 'correction' );
newCorrection.innerHTML = `
+
`;
- existingCorrections.appendChild( newCorrection );
- newCorrection.querySelector( 'span.delete-correction' ).addEventListener( 'click', () => {
+ newCorrections.appendChild( newCorrection );
+ newCorrection.querySelector( 'button.delete-correction' ).addEventListener( 'click', () => {
newCorrection.remove();
} );
+ newCorrectionsCount++;
} );
}
} );
diff --git a/src/other-scripts/corrections/style.scss b/src/other-scripts/corrections/style.scss
index 0e02b6602e..f47740bbf4 100644
--- a/src/other-scripts/corrections/style.scss
+++ b/src/other-scripts/corrections/style.scss
@@ -7,7 +7,11 @@
margin-bottom: 1em;
}
- .reveal-correction {
+ .deleted-corrections {
+ visibility: hidden;
+ }
+
+ .correction {
position: relative;
border-bottom: 1px solid silver;
padding-top: 1em;
From af063302b840cdfc0451890d8338df1dae4eb611 Mon Sep 17 00:00:00 2001
From: Rasmy Nguyen
Date: Tue, 7 Jan 2025 17:45:08 -0500
Subject: [PATCH 05/12] fix(corrections): handle shortcode
---
includes/corrections/class-corrections.php | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
index a5f6ea5fab..63aaaa8f12 100644
--- a/includes/corrections/class-corrections.php
+++ b/includes/corrections/class-corrections.php
@@ -239,11 +239,19 @@ public static function handle_corrections_shortcode() {
-
-
+ post_content;
+ $correction_date = get_post_meta( $correction->ID, self::CORRECTION_DATE_META, true );
+ $correction_heading = sprintf(
+ // translators: %s: correction date.
+ __( 'Correction on %s', 'newspack-plugin' ),
+ gmdate( 'M j, Y', strtotime( $correction_date ) )
+ );
+ ?>
:
-
+
From 0208f5de8acc8a01fb929c55b466e4f397397145 Mon Sep 17 00:00:00 2001
From: Rasmy Nguyen
Date: Tue, 7 Jan 2025 17:53:48 -0500
Subject: [PATCH 06/12] fix: filter get input
---
includes/corrections/class-corrections.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
index 63aaaa8f12..90994e7e4e 100644
--- a/includes/corrections/class-corrections.php
+++ b/includes/corrections/class-corrections.php
@@ -64,9 +64,10 @@ public static function is_enabled() {
* Enqueue scripts and styles.
*/
public static function wp_enqueue_scripts() {
- if ( ! is_admin() || ! isset( $_GET['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
+ if ( ! is_admin() || ! filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT ) ) {
return;
}
+
\wp_enqueue_script(
'newspack-corrections',
Newspack::plugin_url() . '/dist/other-scripts/corrections.js',
From 4bae5aa6457a2f3b4b23a5bfa8c9bce5fa8231ed Mon Sep 17 00:00:00 2001
From: Rasmy Nguyen
Date: Wed, 8 Jan 2025 14:43:21 -0500
Subject: [PATCH 07/12] feat: update corrections
---
includes/corrections/class-corrections.php | 80 ++++++++++++++++++----
1 file changed, 66 insertions(+), 14 deletions(-)
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
index 90994e7e4e..8c4c242489 100644
--- a/includes/corrections/class-corrections.php
+++ b/includes/corrections/class-corrections.php
@@ -31,6 +31,11 @@ class Corrections {
*/
const CORRECTIONS_ACTIVE_META = 'newspack_corrections_active';
+ /**
+ * Meta key for post corrections ids meta.
+ */
+ const CORRECTIONS_IDS_META = 'newspack_corrections_ids';
+
/**
* Initializes the class.
*/
@@ -154,14 +159,15 @@ public static function register_post_type() {
* @return array The corrections.
*/
public static function get_corrections( $post_id ) {
+ $correction_ids = get_post_meta( $post_id, self::CORRECTIONS_IDS_META, true );
+ if ( ! is_array( $correction_ids ) ) {
+ return [];
+ }
return get_posts(
[
'posts_per_page' => -1,
'post_type' => self::POST_TYPE,
- 'meta_key' => self::CORRECTION_POST_ID_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
- 'meta_value' => $post_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
- 'orderby' => 'date',
- 'order' => 'DESC',
+ 'include' => $correction_ids,
]
);
}
@@ -173,8 +179,12 @@ public static function get_corrections( $post_id ) {
* @param array $corrections The corrections.
*/
public static function save_corrections( $post_id, $corrections ) {
+ $correction_ids = get_post_meta( $post_id, self::CORRECTIONS_IDS_META, true );
+ if ( ! is_array( $correction_ids ) ) {
+ $correction_ids = [];
+ }
foreach ( $corrections as $correction ) {
- $post_id = wp_insert_post(
+ $id = wp_insert_post(
[
'post_title' => 'Correction for ' . get_the_title( $post_id ),
'post_content' => $correction['content'],
@@ -186,7 +196,27 @@ public static function save_corrections( $post_id, $corrections ) {
],
]
);
+ if ( ! \is_wp_error( $id ) ) {
+ $correction_ids[] = $id;
+ }
}
+ update_post_meta( $post_id, self::CORRECTIONS_IDS_META, $correction_ids );
+ }
+
+ /**
+ * Update correction.
+ *
+ * @param int $correction_id The post ID.
+ * @param array $correction The correction.
+ */
+ public static function update_correction( $correction_id, $correction ) {
+ wp_update_post(
+ [
+ 'ID' => $correction_id,
+ 'post_content' => sanitize_textarea_field( $correction['content'] ),
+ ]
+ );
+ update_post_meta( $correction_id, self::CORRECTION_DATE_META, sanitize_text_field( $correction['date'] ) );
}
/**
@@ -195,9 +225,17 @@ public static function save_corrections( $post_id, $corrections ) {
* @param array $correction_ids Correction IDs.
*/
public static function delete_corrections( $correction_ids ) {
+ $stored_correction_ids = get_post_meta( $post_id, self::CORRECTIONS_IDS_META, true );
+ if ( ! is_array( $stored_correction_ids ) ) {
+ $stored_correction_ids = [];
+ }
foreach ( $correction_ids as $id ) {
wp_delete_post( $id, true );
+ if ( isset( $stored_correction_ids[ $id ] ) ) {
+ unset( $stored_correction_ids[ $id ] );
+ }
}
+ update_post_meta( $post_id, self::CORRECTIONS_IDS_META, $stored_correction_ids );
}
/**
@@ -336,24 +374,42 @@ public static function save_corrections_metabox( $post_id ) {
return;
}
- $corrections_data = filter_input_array(
+ $corrections_active = filter_input( INPUT_POST, self::CORRECTIONS_ACTIVE_META, FILTER_VALIDATE_BOOLEAN );
+ $corrections_data = filter_input_array(
INPUT_POST,
[
- 'new-corrections' => [
+ 'existing-corrections' => [
+ 'flags' => FILTER_REQUIRE_ARRAY,
+ 'filter' => FILTER_SANITIZE_STRING,
+ ],
+ 'new-corrections' => [
'flags' => FILTER_REQUIRE_ARRAY,
'filter' => FILTER_SANITIZE_STRING,
],
- 'deleted-corrections' => [
+ 'deleted-corrections' => [
'flags' => FILTER_REQUIRE_ARRAY,
'filter' => FILTER_SANITIZE_NUMBER_INT,
],
- self::CORRECTIONS_ACTIVE_META => FILTER_SANITIZE_NUMBER_INT,
]
);
// Return early if there is no corrections data.
- if ( ! $corrections_data ) {
+ if ( false === $corrections_active && empty( $corrections_data ) ) {
return;
}
+ // Update active flag if present.
+ if ( (bool) $corrections_active !== (bool) get_post_meta( $post_id, self::CORRECTIONS_ACTIVE_META, true ) ) {
+ update_post_meta( $post_id, self::CORRECTIONS_ACTIVE_META, (bool) $corrections_active );
+ }
+ // Update existing corrections if present.
+ if ( ! empty( $corrections_data['existing-corrections'] ) ) {
+ foreach ( $corrections_data['existing-corrections'] as $correction_id => $correction ) {
+ // Don't save empty corrections.
+ if ( empty( trim( $correction['content'] ) ) ) {
+ continue;
+ }
+ self::update_correction( $correction_id, $correction );
+ }
+ }
// Save new corrections if present.
if ( ! empty( $corrections_data['new-corrections'] ) ) {
$corrections = [];
@@ -374,10 +430,6 @@ public static function save_corrections_metabox( $post_id ) {
$correction_ids = array_map( 'intval', $corrections_data['deleted-corrections'] );
self::delete_corrections( $correction_ids );
}
- // Update active flag if present.
- if ( isset( $corrections_data[ self::CORRECTIONS_ACTIVE_META ] ) ) {
- update_post_meta( $post_id, self::CORRECTIONS_ACTIVE_META, (bool) $corrections_data[ self::CORRECTIONS_ACTIVE_META ] );
- }
}
/**
From 94659b0f97fb9954cd38934c9529ed4f2ea571c8 Mon Sep 17 00:00:00 2001
From: Rasmy Nguyen
Date: Wed, 8 Jan 2025 16:00:50 -0500
Subject: [PATCH 08/12] feat: add location
---
includes/corrections/class-corrections.php | 72 +++++++++++++---------
src/other-scripts/corrections/index.js | 12 ++++
2 files changed, 56 insertions(+), 28 deletions(-)
diff --git a/includes/corrections/class-corrections.php b/includes/corrections/class-corrections.php
index 8c4c242489..4b00262f14 100644
--- a/includes/corrections/class-corrections.php
+++ b/includes/corrections/class-corrections.php
@@ -31,6 +31,11 @@ class Corrections {
*/
const CORRECTIONS_ACTIVE_META = 'newspack_corrections_active';
+ /**
+ * Meta key for post corrections location meta.
+ */
+ const CORRECTIONS_LOCATION_META = 'newspack_corrections_location';
+
/**
* Meta key for post corrections ids meta.
*/
@@ -101,7 +106,6 @@ public static function register_post_type() {
'revisions',
'custom-fields',
];
-
$labels = [
'name' => _x( 'Corrections', 'post type general name', 'newspack-plugin' ),
'singular_name' => _x( 'Correction', 'post type singular name', 'newspack-plugin' ),
@@ -133,7 +137,6 @@ public static function register_post_type() {
'item_link' => __( 'Correction Link', 'newspack-plugin' ),
'item_link_description' => __( 'A link to a correction.', 'newspack-plugin' ),
];
-
$args = array(
'labels' => $labels,
'description' => 'Post type used to store corrections and clarifications.',
@@ -206,8 +209,8 @@ public static function save_corrections( $post_id, $corrections ) {
/**
* Update correction.
*
- * @param int $correction_id The post ID.
- * @param array $correction The correction.
+ * @param int $correction_id the post id.
+ * @param array $correction the correction.
*/
public static function update_correction( $correction_id, $correction ) {
wp_update_post(
@@ -222,7 +225,7 @@ public static function update_correction( $correction_id, $correction ) {
/**
* Delete corrections for post.
*
- * @param array $correction_ids Correction IDs.
+ * @param array $correction_ids correction ids.
*/
public static function delete_corrections( $correction_ids ) {
$stored_correction_ids = get_post_meta( $post_id, self::CORRECTIONS_IDS_META, true );
@@ -248,7 +251,7 @@ public static function add_corrections_shortcode() {
/**
* Handles the corrections shortcode.
*
- * @return string The shortcode output.
+ * @return string the shortcode output.
*/
public static function handle_corrections_shortcode() {
global $wpdb;
@@ -256,7 +259,7 @@ public static function handle_corrections_shortcode() {
$post_ids = get_posts(
[
'posts_per_page' => -1,
- 'meta_key' => self::CORRECTIONS_ACTIVE_META, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ 'meta_key' => self::CORRECTIONS_ACTIVE_META,
'meta_value' => 1, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
'fields' => 'ids',
'orderby' => 'date',
@@ -305,7 +308,7 @@ public static function handle_corrections_shortcode() {
/**
* Adds the corrections metabox.
*
- * @param string $post_type The post type.
+ * @param string $post_type the post type.
*/
public static function add_corrections_metabox( $post_type ) {
$valid_post_types = [ 'article_legacy', 'content_type_blog', 'post', 'press_release' ];
@@ -324,17 +327,25 @@ public static function add_corrections_metabox( $post_type ) {
/**
* Renders the corrections metabox.
*
- * @param \WP_Post $post The post object.
+ * @param \WP_Post $post the post object.
*/
public static function render_corrections_metabox( $post ) {
$is_active = (bool) get_post_meta( $post->ID, self::CORRECTIONS_ACTIVE_META, true );
+ $location = get_post_meta( $post->ID, self::CORRECTIONS_LOCATION_META, true );
$corrections = self::get_corrections( $post->ID );
?>