Skip to content
This repository has been archived by the owner on Mar 26, 2021. It is now read-only.

Use NPR layout to format the post body in WordPress #74

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dd64aa5
import externalAssets from a story into postmeta
tamw-wnet May 20, 2020
94df141
comment typo fix
tamw-wnet May 20, 2020
7df7e0b
append htmlAssets to end of post body
tamw-wnet May 20, 2020
98cfbea
put htmlAssets into a postmeta npr_html_assets INSTEAD of appending t…
tamw-wnet Jun 2, 2020
6b37c5b
create a use npr layout setting and make it available to update stori…
tamw-wnet Jul 27, 2020
c263454
remove unused code for importing externalAssets and htmlAssets as met…
tamw-wnet Jul 27, 2020
d0317c0
process the textWithHtml, images, externalAssets, and htmlAssets and …
tamw-wnet Jul 27, 2020
68d08d1
disable WPs kses filters when pulling a post from the NPR Story API s…
tamw-wnet Jul 27, 2020
511f6f2
redoing get_body_with_layout to return an array and call for it to ex…
tamw-wnet Jul 28, 2020
bc82c6f
fixing layout html to be more semantically correct and better fit WP …
tamw-wnet Jul 28, 2020
c741856
removing unused meta key assignment
tamw-wnet Jul 28, 2020
524b73f
assign npr_has_layout and npr_has_video postmeta if rich layout used …
tamw-wnet Jul 28, 2020
e6802fe
better caution language on settings screen about wp_kses disabling
tamw-wnet Jul 28, 2020
5a7ab6a
strip tags from image caption before using as an alt tag
tamw-wnet Jul 28, 2020
0f2b19c
set portrait/custom size images to alignright
tamw-wnet Jul 28, 2020
f26f063
silly error on substr
tamw-wnet Jul 28, 2020
0de0d97
add the primary image to a page in place of a gallery
tamw-wnet Jul 28, 2020
e1fb87d
only make custom crops with height > width portrait
tamw-wnet Jul 29, 2020
ac3672f
skip the sideloading of non-primary images if using the npr layout to…
tamw-wnet Jul 29, 2020
7846a62
properly process crops when theres only one of them
tamw-wnet Jul 29, 2020
90de775
base layout conditionals on whether a layout was retrieved, not just …
tamw-wnet Jul 30, 2020
0159a6e
further doc tweak for settings page
tamw-wnet Jul 30, 2020
5bc2197
only check delete NPR API permissions on posts that will be pushed to…
tamw-wnet Jul 30, 2020
c68d6ef
Merge branch 'fix_trash'
tamw-wnet Jul 30, 2020
e8e15a7
Merge branch 'master' into assets_in_body
tamw-wnet Jul 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 273 additions & 1 deletion classes/NPRAPIWordpress.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
if ( empty( $pull_post_type ) ) {
$pull_post_type = 'post';
}
$use_npr_layout = !empty(get_option( 'dp_npr_query_use_layout' )) ? TRUE : FALSE;

$post_id = null;

Expand Down Expand Up @@ -138,7 +139,18 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
} else {
$existing = $existing_status = null;
}


$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
$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
$story->body .= $this->get_transcript_body($story);

Expand Down Expand Up @@ -226,6 +238,8 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
NPR_PUB_DATE_META_KEY => $story->pubDate->value,
NPR_STORY_DATE_MEATA_KEY => $story->storyDate->value,
NPR_LAST_MODIFIED_DATE_KEY => $story->lastModifiedDate->value,
NPR_STORY_HAS_LAYOUT_META_KEY => $npr_has_layout,
NPR_STORY_HAS_VIDEO_META_KEY => $npr_has_video,
);
//get audio
if ( isset($story->audio) ) {
Expand All @@ -244,6 +258,8 @@ function update_posts_from_stories( $publish = TRUE, $qnum = false ) {
$metas[NPR_AUDIO_META_KEY] = implode( ',', $mp3_array );
$metas[NPR_AUDIO_M3U_META_KEY] = implode( ',', $m3u_array );
}


if ( $existing ) {
$created = false;
$args[ 'ID' ] = $existing->ID;
Expand All @@ -263,10 +279,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 ($npr_has_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 ($npr_has_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.
Expand All @@ -285,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') && $npr_has_layout ) {
continue;
}

$image_url = '';
//check the <enlargement> and then the crops, in this order "enlargement", "standard" if they don't exist, just get the image->src
if ( ! empty( $image->enlargement ) ) {
Expand Down Expand Up @@ -440,9 +473,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 ($npr_has_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 ($npr_has_layout) {
// re-enable content stripping
kses_init_filters();
}
}

//set categories for story
Expand Down Expand Up @@ -664,4 +708,232 @@ function get_transcript_body( $story ) {

return $transcript_body;
}


/**
*
* This function will check a story to see if it has a layout object, if there is
* 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 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
$layoutarry = array();
foreach($story->layout->storytext as $type => $elements) {
if (!is_array($elements)) {
$elements = array($elements);
}
foreach ($elements as $element) {
$num = $element->num;
$reference = $element->refId;
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) {
$partext = (string) $paragraph->value;
$paragraphs[$num] = $partext;
$num++;
}

$storyimages = array();
if (isset($story->image) ) {
$storyimages_array = array();
if (isset($story->image->id)) {
$storyimages_array[] = $story->image;
} else {
// sometimes there are multiple objects
foreach ( (array) $story->image as $stryimage ) {
if (isset($stryimage->id)) {
$storyimages_array[] = $stryimage;
}
}
}
foreach ($storyimages_array as $image) {
$image_url = FALSE;
$is_portrait = FALSE;
if ( ! empty( $image->enlargement ) ) {
$image_url = $image->enlargement->src;
}
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;
}
$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 ) ) {
$image_url = $image->src;
}
// 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, 0, strpos($image_url, '?'));
}
$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;
}
}



$externalAssets = array();
if (isset($story->externalAsset) ) {
$externals_array = array();
if (isset($story->externalAsset->type)) {
$externals_array[] = $story->externalAsset;
} else {
// sometimes there are multiple objects
foreach ( (array) $story->externalAsset as $extasset ) {
if (isset($extasset->type)) {
$externals_array[] = $extasset;
}
}
}
foreach ($externals_array as $embed) {
$externalAssets[$embed->id] = (array) $embed;
}
}
$htmlAssets = array();
if (isset($story->htmlAsset) ) {
if (isset($story->htmlAsset->id)) {
$htmlAssets[$story->htmlAsset->id] = $story->htmlAsset->value;
} else {
// sometimes there are multiple objects
foreach ( (array) $story->htmlAsset as $hasset ) {
if (isset($hasset->id)) {
$htmlAssets[$hasset->id] = $hasset->value;
}
}
}
}

foreach ($layoutarry as $ordernum => $element) {
$reference = $element['reference'];
switch ($element['type']) {
case 'text':
if (!empty($paragraphs[$reference])) {
$body_with_layout .= "<p>" . $paragraphs[$reference] . "</p>\n";
}
break;
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])) {
$figclass = "wp-block-embed";
if (!empty( (string)$externalAssets[$reference]['type']) && strtolower((string)$externalAssets[$reference]['type']) == 'youtube') {
$returnary['has_video'] = TRUE;
$figclass .= " is-type-video";
}
$fightml = "<figure class=\"$figclass\"><div class=\"wp-block-embed__wrapper\">";
$fightml .= "\n" . $externalAssets[$reference]['url'] . "\n";
$figcaption = '';
if (!empty( (string)$externalAssets[$reference]['credit']) || !empty( (string)$externalAssets[$reference]['caption'] ) ) {
if (!empty( trim((string)$externalAssets[$reference]['credit']))) {
$figcaption .= "<cite>" . trim((string) $externalAssets[$reference]['credit']) . "</cite>";
}
if (!empty( (string)$externalAssets[$reference]['caption'])) {
$figcaption .= trim((string) $externalAssets[$reference]['caption']);
}
$figcaption = !empty($figcaption) ? "<figcaption>$figcaption</figcaption>" : "";
}
$fightml .= "</div>$figcaption</figure>\n";
$body_with_layout .= $fightml;
}
break;
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];
$fightml = !empty( (string)$thisimg['image_url']) ? '<img src="' . (string)$thisimg['image_url'] . '"' : '';
if (!empty($thisimg['is_portrait'])) {
$figclass .= ' alignright';
$fightml .= " width=200";
}
$thiscaption = !empty(trim( (string)$thisimg['caption'] )) ? trim( (string)$thisimg['caption'] ) : '';
$fightml .= (!empty($fightml) && !empty( $thiscaption)) ? ' alt="' . strip_tags($thiscaption) . '"' : '';
$fightml .= !empty($fightml) ? '>' : '';
$figcaption = (!empty($fightml) && !empty( $thiscaption)) ? $thiscaption : '';
$cites = '';
foreach (array('producer', 'provider', 'copyright') as $item) {
$thisitem = trim( (string)$thisimg[$item] );
if (!empty($thisitem)) {
$cites .= !empty($cites) ? ' | ' . $thisitem : $thisitem;
}
}
$cites = !empty($cites) ? "<cite>$cites</cite>" : '';
$thiscaption .= $cites;
$figcaption = (!empty($fightml) && !empty( $thiscaption)) ? "<figcaption>$thiscaption</figcaption>" : '';
$fightml .= (!empty($fightml) && !empty($figcaption)) ? $figcaption : '';
$body_with_layout .= (!empty($fightml)) ? "<figure class=\"$figclass\">$fightml</figure>\n\n" : '';
// make sure it doesn't get reused;
unset($storyimages[$reference]);
}
break;
}
}

}
$returnary['body']= $body_with_layout;

return $returnary;
}









}
4 changes: 4 additions & 0 deletions ds-npr-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
define( 'NPR_BYLINE_LINK_META_KEY', 'npr_byline_link' );
define( 'NPR_MULTI_BYLINE_META_KEY', 'npr_multi_byline' );
define( 'NPR_IMAGE_GALLERY_META_KEY', 'npr_image_gallery');
define( 'NPR_HTML_ASSETS_META_KEY', 'npr_html_assets');
define( 'NPR_AUDIO_META_KEY', 'npr_audio');
define( 'NPR_AUDIO_M3U_META_KEY', 'npr_audio_m3u');
define( 'NPR_PUB_DATE_META_KEY', 'npr_pub_date');
Expand All @@ -43,6 +44,9 @@
define( 'NPR_IMAGE_AGENCY_META_KEY', 'npr_image_agency');
define( 'NPR_IMAGE_CAPTION_META_KEY', 'npr_image_caption');

define( 'NPR_STORY_HAS_LAYOUT_META_KEY', 'npr_has_layout');
define( 'NPR_STORY_HAS_VIDEO_META_KEY', 'npr_has_video');

define( 'NPR_PUSH_STORY_ERROR', 'npr_push_story_error');

define( 'NPR_MAX_QUERIES', 10 );
Expand Down
16 changes: 9 additions & 7 deletions push_story.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) ) {
Expand All @@ -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;
Expand Down
Loading