with optional attributes depending on the BeyondWords
* data of the post.
*
* @param int|\WP_Post $post The WordPress post ID, or post object.
*
* @since 4.6.0
*
* @return string The summary wrapper
.
*/
public static function getPostSummaryWrapperFormat(int|\WP_Post $post): string
{
$post = get_post($post);
if (!($post instanceof \WP_Post)) {
throw new \Exception(esc_html__('Post Not Found', 'speechkit'));
}
$summaryVoiceId = intval(get_post_meta($post->ID, 'beyondwords_summary_voice_id', true));
if ($summaryVoiceId > 0) {
return '
%s
';
}
return '
%s
';
}
/**
* Get the post summary for the audio content.
*
* @param int|\WP_Post $post The WordPress post ID, or post object.
*
* @since 4.0.0
* @since 4.6.0 Renamed from PostContentUtils::getSummary() to PostContentUtils::getPostSummary()
*
* @return string The summary.
*/
public static function getPostSummary(int|\WP_Post $post): string|null
{
$post = get_post($post);
if (!($post instanceof \WP_Post)) {
throw new \Exception(esc_html__('Post Not Found', 'speechkit'));
}
$summary = null;
// Optionally send the excerpt to the REST API, if the plugin setting has been checked
$prependExcerpt = get_option('beyondwords_prepend_excerpt');
if ($prependExcerpt && has_excerpt($post)) {
// Escape characters
$summary = htmlentities($post->post_excerpt, ENT_QUOTES | ENT_XHTML);
// Apply WordPress filters
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Applying core WordPress filter
$summary = apply_filters('get_the_excerpt', $summary);
// Convert line breaks into paragraphs
$summary = trim(wpautop($summary));
}
return $summary;
}
/**
* Get the post content without blocks which have been filtered.
*
* We have added buttons into the Gutenberg editor to optionally exclude selected
* blocks from the source text for audio.
*
* This method filters all blocks, removing any which have been excluded.
*
* @param int|\WP_Post $post The WordPress post ID, or post object.
*
* @since 3.8.0
* @since 4.0.0 Replace for loop with array_reduce
* @since 6.0.0 Remove beyondwordsMarker attribute from rendered blocks.
*
* @return string The post body without excluded blocks.
*/
public static function getContentWithoutExcludedBlocks(int|\WP_Post $post): string
{
if (! has_blocks($post)) {
return trim($post->post_content);
}
$blocks = parse_blocks($post->post_content);
$output = '';
$blocks = PostContentUtils::getAudioEnabledBlocks($post);
foreach ($blocks as $block) {
$output .= render_block($block);
}
return $output;
}
/**
* Get audio-enabled blocks.
*
* @param int|\WP_Post $post The WordPress post ID, or post object.
*
* @since 4.0.0
* @since 5.0.0 Remove beyondwords_post_audio_enabled_blocks filter.
*
* @return array The blocks.
*/
public static function getAudioEnabledBlocks(int|\WP_Post $post): array
{
$post = get_post($post);
if (! ($post instanceof \WP_Post)) {
return [];
}
if (! has_blocks($post)) {
return [];
}
$allBlocks = parse_blocks($post->post_content);
return array_filter($allBlocks, function ($block) {
$enabled = true;
if (is_array($block['attrs']) && isset($block['attrs']['beyondwordsAudio'])) {
$enabled = (bool) $block['attrs']['beyondwordsAudio'];
}
return $enabled;
});
}
/**
* Get the body param we pass to the API.
*
* @since 3.0.0 Introduced as getBodyJson.
* @since 3.3.0 Added metadata to aid custom playlist generation.
* @since 3.5.0 Moved from Core\Utils to Component\Post\PostUtils.
* @since 3.10.4 Rename `published_at` API param to `publish_date`.
* @since 4.0.0 Use new API params.
* @since 4.0.3 Ensure `image_url` is always a string.
* @since 4.3.0 Rename from getBodyJson to getContentParams.
* @since 4.6.0 Remove summary param & prepend body with summary.
* @since 5.0.0 Remove beyondwords_body_params filter.
* @since 6.0.0 Cast return value to string.
*
* @static
* @param int $postId WordPress Post ID.
*
* @return string JSON endoded params.
**/
public static function getContentParams(int $postId): array|string
{
$body = [
'type' => 'auto_segment',
'title' => get_the_title($postId),
'body' => PostContentUtils::getContentBody($postId),
'source_url' => get_the_permalink($postId),
'source_id' => strval($postId),
'author' => PostContentUtils::getAuthorName($postId),
'image_url' => strval(wp_get_original_image_url(get_post_thumbnail_id($postId))),
'metadata' => PostContentUtils::getMetadata($postId),
'publish_date' => get_post_time(PostContentUtils::DATE_FORMAT, true, $postId),
];
$status = get_post_status($postId);
/*
* If the post status is draft/pending then we explicity send
* { published: false } to the BeyondWords API, to prevent the
* generated audio from being published in playlists.
*
* We also omit { publish_date } because get_post_time() returns `false`
* for posts which are "Pending Review".
*/
if (in_array($status, ['draft', 'pending'])) {
$body['published'] = false;
unset($body['publish_date']);
} elseif (get_option('beyondwords_project_auto_publish_enabled')) {
$body['published'] = true;
}
$languageCode = get_post_meta($postId, 'beyondwords_language_code', true);
if ($languageCode) {
$body['language'] = $languageCode;
}
$bodyVoiceId = intval(get_post_meta($postId, 'beyondwords_body_voice_id', true));
if ($bodyVoiceId > 0) {
$body['body_voice_id'] = $bodyVoiceId;
}
$titleVoiceId = intval(get_post_meta($postId, 'beyondwords_title_voice_id', true));
if ($titleVoiceId > 0) {
$body['title_voice_id'] = $titleVoiceId;
}
$summaryVoiceId = intval(get_post_meta($postId, 'beyondwords_summary_voice_id', true));
if ($summaryVoiceId > 0) {
$body['summary_voice_id'] = $summaryVoiceId;
}
/**
* Filters the params we send to the BeyondWords API 'content' endpoint.
*
* @since 4.0.0 Introduced as beyondwords_body_params
* @since 4.3.0 Renamed from beyondwords_body_params to beyondwords_content_params
*
* @param array $body The params we send to the BeyondWords API.
* @param array $postId WordPress post ID.
*/
$body = apply_filters('beyondwords_content_params', $body, $postId);
return (string) wp_json_encode($body);
}
/**
* Get the post metadata to send with BeyondWords API requests.
*
* The metadata key is defined by the BeyondWords API as "A custom object
* for storing meta information".
*
* The metadata values are used to create filters for playlists in the
* BeyondWords dashboard.
*
* We currently only include taxonomies by default, and the output of this
* method can be filtered using the `beyondwords_post_metadata` filter.
*
* @since 3.3.0
* @since 3.5.0 Moved from Core\Utils to Component\Post\PostUtils.
* @since 5.0.0 Remove beyondwords_post_metadata filter.
*
* @param int $postId Post ID.
*
* @return object The metadata object (empty if no metadata).
*/
public static function getMetadata(int $postId): array|object
{
$metadata = new \stdClass();
$taxonomy = PostContentUtils::getAllTaxonomiesAndTerms($postId);
if (count((array)$taxonomy)) {
$metadata->taxonomy = $taxonomy;
}
return $metadata;
}
/**
* Get all taxonomies, and their selected terms, for a post.
*
* Returns an associative array of taxonomy names and terms.
*
* For example:
*
* array(
* "categories" => array("Category 1"),
* "post_tag" => array("Tag 1", "Tag 2", "Tag 3"),
* )
*
* @since 3.3.0
* @since 3.5.0 Moved from Core\Utils to Component\Post\PostUtils
*
* @param int $postId Post ID.
*
* @return object The taxonomies object (empty if no taxonomies).
*/
public static function getAllTaxonomiesAndTerms(int $postId): array|object
{
$postType = get_post_type($postId);
$postTypeTaxonomies = get_object_taxonomies($postType);
$taxonomies = new \stdClass();
foreach ($postTypeTaxonomies as $postTypeTaxonomy) {
$terms = get_the_terms($postId, $postTypeTaxonomy);
if (! empty($terms) && ! is_wp_error($terms)) {
$taxonomies->{(string)$postTypeTaxonomy} = wp_list_pluck($terms, 'name');
}
}
return $taxonomies;
}
/**
* Get author name for a post.
*
* @since 3.10.4
*
* @param int $postId Post ID.
*/
public static function getAuthorName(int $postId): string
{
$authorId = get_post_field('post_author', $postId);
return get_the_author_meta('display_name', $authorId);
}
}