\n";
+ }
+ $body_with_layout .= "\n";
+ }
+ break;
+ case 'image':
+ if (!empty($storyimages[$reference])) {
+ $figclass="npr-featured-image";
+ $thisimg = $storyimages[$reference];
+ $fightml = !empty( (string)$thisimg['image_url']) ? '' : '';
+ $figcaption = (!empty($fightml) && !empty( $thiscaption)) ? '' . $thiscaption : '';
+ if (!empty($figcaption)) {
+ $cites = '';
+ foreach (array('producer', 'provider', 'copyright') as $item) {
+ $thisitem = (string)$thisimg[$item];
+ if (!empty($thisitem)) {
+ $cites .= !empty($cites) ? ' | ' . $thisitem : $thisitem;
+ }
+ }
+ $figcaption .= !empty($cites) ? "$cites" : '';
+ }
+ $figcapton .= !empty($figcaption) ? '' : '';
+ $fightml .= (!empty($fightml) && !empty($figcaption)) ? $figcaption : '';
+ $body_with_layout .= (!empty($fightml)) ? "$fightml\n\n" : '';
+ }
+ break;
+ }
+ }
+
+ }
+ return $body_with_layout;
+ }
+
+
+
+
+
+
+
+
+
}
From 68d08d19a4ea742f0ad3faaa89f5d3f6d1b0b248 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Mon, 27 Jul 2020 21:49:07 +0000
Subject: [PATCH 08/23] disable WPs kses filters when pulling a post from the
NPR Story API so javascript etc can be saved
---
classes/NPRAPIWordpress.php | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index 41e0aa5..2041b34 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -275,10 +275,21 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
* @param NPRMLEntity $story Story object created during import
* @param bool $created true if not pre-existing, false otherwise
*/
+
+ if ($use_npr_layout) {
+ // keep WP from stripping content from NPR posts
+ kses_remove_filters();
+ }
+
$args = apply_filters( 'npr_pre_insert_post', $args, $post_id, $story, $created );
$post_id = wp_insert_post( $args );
+ if ($use_npr_layout) {
+ // re-enable the built-in content stripping
+ kses_init_filters();
+ }
+
//now that we have an id, we can add images
//this is the way WP seems to do it, but we couldn't call media_sideload_image or media_ because that returned only the URL
//for the attachment, and we want to be able to set the primary image, so we had to use this method to get the attachment ID.
@@ -452,9 +463,20 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
* @param int $post_id Post ID or NULL if no post ID.
* @param NPRMLEntity $story Story object created during import
*/
+
+ if ($use_npr_layout) {
+ // keep WP from stripping content from NPR posts
+ kses_remove_filters();
+ }
+
$args = apply_filters( 'npr_pre_update_post', $args, $post_id, $story );
$post_id = wp_insert_post( $args );
+
+ if ($use_npr_layout) {
+ // re-enable content stripping
+ kses_init_filters();
+ }
}
//set categories for story
From 511f6f25172c0c2f979c406de900ca8003153c51 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Tue, 28 Jul 2020 16:47:19 +0000
Subject: [PATCH 09/23] redoing get_body_with_layout to return an array and
call for it to expect array
---
classes/NPRAPIWordpress.php | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index 2041b34..f4eaaca 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -140,13 +140,15 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
$existing = $existing_status = null;
}
- $has_npr_layout = FALSE;
+ $npr_has_layout = FALSE;
+ $npr_has_video = FALSE;
if ($use_npr_layout) {
// get the "NPR layout" version if available and the "use rich layout" option checked in settings
- $body_with_layout = $this->get_body_with_layout($story);
- if (!empty($body_with_layout)) {
- $story->body = $body_with_layout;
- $has_npr_layout = TRUE;
+ $npr_layout = $this->get_body_with_layout($story);
+ if (!empty($npr_layout['body'])) {
+ $story->body = $npr_layout['body'];
+ $npr_has_layout = TRUE;
+ $npr_has_video = $npr_layout['has_video'];
}
}
//add the transcript
@@ -703,12 +705,14 @@ function get_transcript_body( $story ) {
/**
*
* This function will check a story to see if it has a layout object, if there is
- * we'll return the body with any externalAssets or htmlAssets inserted in the order they are in the layout
+ * we'll format the body with any images, externalAssets, or htmlAssets inserted in the order they are in the layout
+ * and return an array of the transformed body and flags for what sort of elements are returned
*
- * @param string $story
- * @return string
+ * @param NPRMLEntity $story Story object created during import
+ * @return array with reconstructed body and flags describing returned elements
*/
function get_body_with_layout( $story ) {
+ $returnary = array('body' => FALSE, 'has_layout' => FALSE, 'has_image' => FALSE, 'has_video' => FALSE, 'has_external' => FALSE);
$body_with_layout = "";
if ( ! empty( $story->layout ) ) {
// simplify the arrangement of the storytext object
@@ -720,14 +724,16 @@ function get_body_with_layout( $story ) {
foreach ($elements as $element) {
$num = $element->num;
$reference = $element->refId;
- if ($type == 'text') {
+ if ($type == 'text') {
+ // only paragraphs don't have a refId, they use num instead
$reference = $element->paragraphNum;
}
$layoutarry[(int)$num] = array('type'=>$type, 'reference' => $reference);
}
}
ksort($layoutarry);
-
+ $returnary['has_layout'] = TRUE;
+
$paragraphs = array();
$num = 1;
foreach ($story->textWithHtml->paragraphs as $paragraph) {
@@ -876,7 +882,9 @@ function get_body_with_layout( $story ) {
}
}
- return $body_with_layout;
+ $returnary['body']= $body_with_layout;
+
+ return $returnary;
}
From bc82c6f8d3666dbc9030d7bfd2c2303bb6f9a294 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Tue, 28 Jul 2020 16:48:32 +0000
Subject: [PATCH 10/23] fixing layout html to be more semantically correct and
better fit WP standards
---
classes/NPRAPIWordpress.php | 52 +++++++++++++++++++++++--------------
1 file changed, 33 insertions(+), 19 deletions(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index f4eaaca..90ebaf2 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -840,40 +840,54 @@ function get_body_with_layout( $story ) {
case 'staticHtml':
if (!empty($htmlAssets[$reference])) {
$body_with_layout .= $htmlAssets[$reference] . "\n\n";
+ $returnary['has_external'] = TRUE;
+ if (strpos($htmlAssets[$reference], 'jwplayer.com')) {
+ $returnary['has_video'] = TRUE;
+ }
}
break;
case 'externalAsset':
if (!empty($externalAssets[$reference])) {
- $body_with_layout .= $externalAssets[$reference]['url'] . "\n";
- if (!empty( (string)$externalAssets[$reference]['credit'])) {
- $body_with_layout .= "" . (string) $externalAssets[$reference]['credit'] . "\n";
+ $figclass = "wp-block-embed";
+ if (!empty( (string)$externalAssets[$reference]['type']) && strtolower((string)$externalAssets[$reference]['type']) == 'youtube') {
+ $returnary['has_video'] = TRUE;
+ $figclass .= " is-type-video";
}
- if (!empty( (string)$externalAssets[$reference]['caption'])) {
- $body_with_layout .= "
If layout is available will render any YouTube, Tweets, images, or JavaScript-based widgets within the post in the order they appear. CAUTION: This will allow the 'admin' user to post unfiltered content such as JavaScript.
";
+ echo $check_box_string . "
If layout is available will render any YouTube, Tweets, images, or JavaScript-based widgets within the post in the order they appear. CAUTION: This disables the normal 'wp_kses' filtering for imported posts that prevents any JavaScript from being included in the post. We assume that NPR Story API posts will not have malicious scripts.
";
wp_nonce_field( 'nprstory_nonce_ds_npr_query_use_layout', 'nprstory_nonce_ds_npr_query_use_layout_name', true, true );
}
From 5a7ab6a19b0bcc0b9857077cce05a4beb29c2e81 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Tue, 28 Jul 2020 19:23:10 +0000
Subject: [PATCH 14/23] strip tags from image caption before using as an alt
tag
---
classes/NPRAPIWordpress.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index 598beae..7cb5fbd 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -877,7 +877,7 @@ function get_body_with_layout( $story ) {
$thisimg = $storyimages[$reference];
$fightml = !empty( (string)$thisimg['image_url']) ? '' : '';
$figcaption = (!empty($fightml) && !empty( $thiscaption)) ? $thiscaption : '';
$cites = '';
From 0f2b19c494419bd421dd9374292eb66d844e017a Mon Sep 17 00:00:00 2001
From: William Tam
Date: Tue, 28 Jul 2020 19:24:11 +0000
Subject: [PATCH 15/23] set portrait/custom size images to alignright
---
classes/NPRAPIWordpress.php | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index 7cb5fbd..b73903d 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -758,28 +758,21 @@ function get_body_with_layout( $story ) {
}
}
foreach ($storyimages_array as $image) {
+ $image_url = FALSE;
+ $is_portrait = FALSE;
if ( ! empty( $image->enlargement ) ) {
$image_url = $image->enlargement->src;
- } else {
- if ( ! empty( $image->crop ) && is_array( $image->crop ) ) {
- foreach ( $image->crop as $crop ) {
- if ( empty( $crop->type ) ) {
- continue;
- }
- if ( 'enlargement' === $crop->type ) {
- $image_url = $crop->src;
- }
+ }
+ if ( ! empty( $image->crop ) && is_array( $image->crop ) ) {
+ foreach ( $image->crop as $crop ) {
+ if (empty($crop->primary)) {
+ continue;
}
- if ( empty( $image_url ) ) {
- foreach ( $image->crop as $crop ) {
- if ( empty( $crop->type ) ) {
- continue;
- }
- if ( 'standard' === $crop->type ) {
- $image_url = $crop->src;
- }
- }
+ $image_url = $crop->src;
+ if ($crop->type == 'custom' || ((int)$crop->height > (int)$crop->width)) {
+ $is_portrait = TRUE;
}
+ break;
}
}
if ( empty( $image_url ) && ! empty( $image->src ) ) {
@@ -791,10 +784,11 @@ function get_body_with_layout( $story ) {
if (strpos($image_url)) {
$image_url = substr($image_url, strpos($image_url, 0, '?'));
}
- $image_url .= '?s=6';
+ $image_url .= !$is_portrait ? '?s=6' : '?s=12';
}
$storyimages[$image->id] = (array) $image;
$storyimages[$image->id]['image_url'] = $image_url;
+ $storyimages[$image->id]['is_portrait'] = $is_portrait;
}
}
@@ -876,6 +870,10 @@ function get_body_with_layout( $story ) {
$figclass = "wp-block-image size-large";
$thisimg = $storyimages[$reference];
$fightml = !empty( (string)$thisimg['image_url']) ? '' : '';
From f26f0633f2dafff4641e5994dbd49444088a266f Mon Sep 17 00:00:00 2001
From: William Tam
Date: Tue, 28 Jul 2020 21:15:29 +0000
Subject: [PATCH 16/23] silly error on substr
---
classes/NPRAPIWordpress.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index b73903d..cefcf4f 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -781,8 +781,8 @@ function get_body_with_layout( $story ) {
// add resizing to any npr-hosted image
if (strpos($image_url, 'media.npr.org')) {
// remove any existing querystring
- if (strpos($image_url)) {
- $image_url = substr($image_url, strpos($image_url, 0, '?'));
+ if (strpos($image_url, '?')) {
+ $image_url = substr($image_url, 0, strpos($image_url, '?'));
}
$image_url .= !$is_portrait ? '?s=6' : '?s=12';
}
From 0de0d97009451e0f5ab4fc8caf86dffe5aadaa91 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Tue, 28 Jul 2020 21:16:32 +0000
Subject: [PATCH 17/23] add the primary image to a page in place of a gallery
---
classes/NPRAPIWordpress.php | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index cefcf4f..9e54f49 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -865,7 +865,21 @@ function get_body_with_layout( $story ) {
$body_with_layout .= $fightml;
}
break;
- case 'image':
+ default:
+ // handles both 'list' and 'image' since it will reset the type and then assign the reference
+ if ($element['type'] == 'list') {
+ foreach ($storyimages as $image) {
+ if ($image['type'] != 'primary') {
+ continue;
+ }
+ $reference = $image['id'];
+ $element['type'] = 'image';
+ break;
+ }
+ }
+ if ($element['type'] != 'image') {
+ break;
+ }
if (!empty($storyimages[$reference])) {
$figclass = "wp-block-image size-large";
$thisimg = $storyimages[$reference];
@@ -889,7 +903,9 @@ function get_body_with_layout( $story ) {
$thiscaption .= $cites;
$figcaption = (!empty($fightml) && !empty( $thiscaption)) ? "$thiscaption" : '';
$fightml .= (!empty($fightml) && !empty($figcaption)) ? $figcaption : '';
- $body_with_layout .= (!empty($fightml)) ? "$fightml\n\n" : '';
+ $body_with_layout .= (!empty($fightml)) ? "$fightml\n\n" : '';
+ // make sure it doesn't get reused;
+ unset($storyimages[$reference]);
}
break;
}
From e1fb87da5db6162682cc5f3ea24a33508ed3d75d Mon Sep 17 00:00:00 2001
From: William Tam
Date: Wed, 29 Jul 2020 16:59:43 +0000
Subject: [PATCH 18/23] only make custom crops with height > width portrait
---
classes/NPRAPIWordpress.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index 9e54f49..073d5ab 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -769,7 +769,7 @@ function get_body_with_layout( $story ) {
continue;
}
$image_url = $crop->src;
- if ($crop->type == 'custom' || ((int)$crop->height > (int)$crop->width)) {
+ if ($crop->type == 'custom' && ((int)$crop->height > (int)$crop->width)) {
$is_portrait = TRUE;
}
break;
From ac3672f207d73402c129f522b9070a8325599cce Mon Sep 17 00:00:00 2001
From: William Tam
Date: Wed, 29 Jul 2020 17:03:47 +0000
Subject: [PATCH 19/23] skip the sideloading of non-primary images if using the
npr layout to SERIOUSLY improve import performance on multi-image posts
---
classes/NPRAPIWordpress.php | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index 073d5ab..1b2f73a 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -312,6 +312,12 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
$attached_images = get_children( $image_args );
}
foreach ( (array) $story->image as $image ) {
+
+ // only sideload the primary image if using the npr layout
+ if ( ($image->type != 'primary') && $use_npr_layout ) {
+ continue;
+ }
+
$image_url = '';
//check the and then the crops, in this order "enlargement", "standard" if they don't exist, just get the image->src
if ( ! empty( $image->enlargement ) ) {
From 7846a629f869aa2dd3940c5dd7ae5562ac92bde3 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Wed, 29 Jul 2020 20:34:29 +0000
Subject: [PATCH 20/23] properly process crops when theres only one of them
---
classes/NPRAPIWordpress.php | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index 1b2f73a..a4e09f8 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -769,7 +769,12 @@ function get_body_with_layout( $story ) {
if ( ! empty( $image->enlargement ) ) {
$image_url = $image->enlargement->src;
}
- if ( ! empty( $image->crop ) && is_array( $image->crop ) ) {
+ if ( ! empty( $image->crop )) {
+ if (!is_array( $image->crop ) ) {
+ $cropobj = $image->crop;
+ unset($image->crop);
+ $image->crop = array($cropobj);
+ }
foreach ( $image->crop as $crop ) {
if (empty($crop->primary)) {
continue;
From 90de775dd82c437b3da506ea07895663b0a98ba2 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Thu, 30 Jul 2020 15:03:30 +0000
Subject: [PATCH 21/23] base layout conditionals on whether a layout was
retrieved, not just on whether the admin selected to use the layout feature
---
classes/NPRAPIWordpress.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/classes/NPRAPIWordpress.php b/classes/NPRAPIWordpress.php
index a4e09f8..d391e76 100644
--- a/classes/NPRAPIWordpress.php
+++ b/classes/NPRAPIWordpress.php
@@ -280,7 +280,7 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
* @param bool $created true if not pre-existing, false otherwise
*/
- if ($use_npr_layout) {
+ if ($npr_has_layout) {
// keep WP from stripping content from NPR posts
kses_remove_filters();
}
@@ -289,7 +289,7 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
$post_id = wp_insert_post( $args );
- if ($use_npr_layout) {
+ if ($npr_has_layout) {
// re-enable the built-in content stripping
kses_init_filters();
}
@@ -314,7 +314,7 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
foreach ( (array) $story->image as $image ) {
// only sideload the primary image if using the npr layout
- if ( ($image->type != 'primary') && $use_npr_layout ) {
+ if ( ($image->type != 'primary') && $npr_has_layout ) {
continue;
}
@@ -474,7 +474,7 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
* @param NPRMLEntity $story Story object created during import
*/
- if ($use_npr_layout) {
+ if ($npr_has_layout) {
// keep WP from stripping content from NPR posts
kses_remove_filters();
}
@@ -483,7 +483,7 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
$post_id = wp_insert_post( $args );
- if ($use_npr_layout) {
+ if ($npr_has_layout) {
// re-enable content stripping
kses_init_filters();
}
From 0159a6eb8d6fcd2aafe311db1429257c4f71793a Mon Sep 17 00:00:00 2001
From: William Tam
Date: Thu, 30 Jul 2020 15:40:23 +0000
Subject: [PATCH 22/23] further doc tweak for settings page
---
settings.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings.php b/settings.php
index 5663233..753ed7c 100644
--- a/settings.php
+++ b/settings.php
@@ -166,7 +166,7 @@ function nprstory_query_use_layout_callback() {
}
$check_box_string .= "/>";
- echo $check_box_string . "
If layout is available will render any YouTube, Tweets, images, or JavaScript-based widgets within the post in the order they appear. CAUTION: This disables the normal 'wp_kses' filtering for imported posts that prevents any JavaScript from being included in the post. We assume that NPR Story API posts will not have malicious scripts.
";
+ echo $check_box_string . "
If 'layout' is available in the NPR Story API output for your key, checking this box will import posts with more complex HTML to render any images, YouTube videos, Tweets, iframes, or JavaScript-based widgets within the post in the order they appeared on the NPR website. Only the 'primary' image for the story will be sideloaded into the Media Library, all other images will be linked from NPR. CAUTION: This disables the normal 'wp_kses' filtering for imported posts that prevents any JavaScript from being included in the post. We assume that NPR Story API posts will not have malicious scripts.
";
wp_nonce_field( 'nprstory_nonce_ds_npr_query_use_layout', 'nprstory_nonce_ds_npr_query_use_layout_name', true, true );
}
From 5bc21977a8e49d8658bee933ef46b776da0fcec9 Mon Sep 17 00:00:00 2001
From: William Tam
Date: Thu, 30 Jul 2020 16:01:40 +0000
Subject: [PATCH 23/23] only check delete NPR API permissions on posts that
will be pushed to NPR API
---
push_story.php | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/push_story.php b/push_story.php
index a964698..6ecb6de 100644
--- a/push_story.php
+++ b/push_story.php
@@ -82,13 +82,6 @@ function nprstory_api_push ( $post_ID, $post ) {
* @param unknown_type $post_ID
*/
function nprstory_api_delete ( $post_ID ) {
- if ( ! current_user_can( 'delete_others_posts' ) ) {
- wp_die(
- __('You do not have permission to delete posts in the NPR API. Users that can delete other users\' posts have that ability: administrators and editors.'),
- __('NPR Story API Error'),
- 403
- );
- }
$push_post_type = get_option( 'ds_npr_push_post_type' );
if ( empty( $push_post_type ) ) {
@@ -106,6 +99,15 @@ function nprstory_api_delete ( $post_ID ) {
//if the push url isn't set, don't even try to delete.
$push_url = get_option( 'ds_npr_api_push_url' );
if ( $post->post_type == $push_post_type && ! empty( $push_url ) && ! empty( $api_id ) ) {
+ // don't let a non-admin/editor push a delete to the API
+ if ( ! current_user_can( 'delete_others_posts' ) ) {
+ wp_die(
+ __('You do not have permission to delete posts in the NPR API. Users that can delete other users\' posts have that ability: administrators and editors.'),
+ __('NPR Story API Error'),
+ 403
+ );
+ }
+
// For now, only submit regular posts, and only on publish.
if ( $post->post_type != 'post' || $post->post_status != 'publish' ) {
return;