-
Notifications
You must be signed in to change notification settings - Fork 58
feat: add featured image caption block #4519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| { | ||
| "$schema": "https://schemas.wp.org/trunk/block.json", | ||
| "apiVersion": 3, | ||
| "name": "newspack/featured-image-caption", | ||
| "title": "Featured Image Caption", | ||
| "category": "newspack", | ||
| "textdomain": "newspack-plugin", | ||
| "attributes": { | ||
| "customCaption": { | ||
| "type": "string", | ||
| "default": "" | ||
| } | ||
| }, | ||
| "usesContext": [ "postId", "postType" ], | ||
| "supports": { | ||
| "html": false, | ||
| "color": { | ||
| "gradients": true, | ||
| "__experimentalDefaultControls": { | ||
| "background": true, | ||
| "text": true, | ||
| "link": true | ||
| } | ||
| }, | ||
| "spacing": { | ||
| "margin": true, | ||
| "padding": true | ||
| }, | ||
| "typography": { | ||
| "fontSize": true, | ||
| "lineHeight": true, | ||
| "textAlign": true, | ||
| "__experimentalFontFamily": true, | ||
| "__experimentalFontWeight": true, | ||
| "__experimentalFontStyle": true, | ||
| "__experimentalTextTransform": true, | ||
| "__experimentalTextDecoration": true, | ||
| "__experimentalLetterSpacing": true, | ||
| "__experimentalDefaultControls": { | ||
| "fontSize": true, | ||
| "fontAppearance": true | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| <?php | ||
| /** | ||
| * Featured Image Caption Block. | ||
| * | ||
| * @package Newspack | ||
| */ | ||
|
|
||
| namespace Newspack\Blocks\FeaturedImageCaption; | ||
|
|
||
| defined( 'ABSPATH' ) || exit; | ||
|
|
||
| /** | ||
| * Featured Image Caption Block class. | ||
| */ | ||
| final class Featured_Image_Caption_Block { | ||
|
|
||
| /** | ||
| * Initializer. | ||
| */ | ||
| public static function init() { | ||
| \add_action( 'init', [ __CLASS__, 'register_block' ] ); | ||
| } | ||
|
|
||
| /** | ||
| * Register the block. | ||
| */ | ||
| public static function register_block() { | ||
| register_block_type_from_metadata( | ||
| __DIR__ . '/block.json', | ||
| [ | ||
| 'render_callback' => [ __CLASS__, 'render_block' ], | ||
| ] | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Block render callback. | ||
| * | ||
| * @param array $attributes Block attributes. | ||
| * @param string $content Block content. | ||
| * @param \WP_Block $block Block instance. | ||
| * @return string Rendered block. | ||
| */ | ||
| public static function render_block( $attributes, $content, $block ) { | ||
| $post_id = ! empty( $block->context['postId'] ) ? $block->context['postId'] : get_the_ID(); | ||
| if ( ! $post_id ) { | ||
| return ''; | ||
| } | ||
|
|
||
| $featured_image_id = get_post_thumbnail_id( $post_id ); | ||
| if ( ! $featured_image_id ) { | ||
| return ''; | ||
| } | ||
|
|
||
| $custom_caption = $attributes['customCaption'] ?? ''; | ||
|
|
||
| if ( $custom_caption ) { | ||
| $output = wp_kses_post( $custom_caption ); | ||
| } else { | ||
| $caption = wp_kses_post( wp_get_attachment_caption( $featured_image_id ) ); | ||
| $credit = ''; | ||
|
|
||
| if ( class_exists( '\Newspack\Newspack_Image_Credits' ) ) { | ||
| $credit = \Newspack\Newspack_Image_Credits::get_media_credit_string( $featured_image_id ); | ||
| } | ||
|
|
||
| $output = trim( $caption ); | ||
| if ( $output && $credit ) { | ||
| $output .= ' ' . $credit; | ||
| } elseif ( $credit ) { | ||
| $output = $credit; | ||
| } | ||
| } | ||
|
|
||
| if ( ! $output ) { | ||
| return ''; | ||
| } | ||
|
|
||
| $wrapper_attributes = get_block_wrapper_attributes(); | ||
| return sprintf( '<figcaption %1$s>%2$s</figcaption>', $wrapper_attributes, $output ); | ||
| } | ||
| } | ||
| Featured_Image_Caption_Block::init(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import { useBlockProps, RichText } from '@wordpress/block-editor'; | ||
| import { useEntityProp } from '@wordpress/core-data'; | ||
| import { useSelect } from '@wordpress/data'; | ||
| import { __, sprintf } from '@wordpress/i18n'; | ||
|
|
||
| /** | ||
| * Generates the credit text for the media credit and organization. | ||
| * | ||
| * @param {string} mediaCredit The media credit. | ||
| * @param {string} organization The organization associated with the media credit. Optional. | ||
| * | ||
| * @return {string} The formatted credit text. | ||
| */ | ||
| const generateCreditText = ( mediaCredit, organization ) => { | ||
| if ( mediaCredit && organization ) { | ||
| return sprintf( | ||
| /* translators: 1: media credit, 2: organization */ | ||
| __( 'Credit: %1$s / %2$s', 'newspack-plugin' ), | ||
| mediaCredit, | ||
| organization | ||
| ); | ||
| } | ||
|
|
||
| return sprintf( | ||
| /* translators: %s: media credit */ | ||
| __( 'Credit: %s', 'newspack-plugin' ), | ||
| mediaCredit | ||
| ); | ||
| }; | ||
|
|
||
| export const Edit = ( { attributes, setAttributes, context: { postType, postId } } ) => { | ||
| const blockProps = useBlockProps(); | ||
|
|
||
| const [ featuredImage ] = useEntityProp( 'postType', postType, 'featured_media', postId ); | ||
|
|
||
| const { caption, credit } = useSelect( | ||
| select => { | ||
| if ( ! featuredImage ) { | ||
| return {}; | ||
| } | ||
| const media = select( 'core' ).getMedia( featuredImage ); | ||
| if ( ! media ) { | ||
| return {}; | ||
| } | ||
| return { | ||
| caption: media.caption?.raw || '', | ||
| credit: media.meta?._media_credit ? generateCreditText( media.meta._media_credit, media.meta?._navis_media_credit_org ) : '', | ||
| }; | ||
| }, | ||
| [ featuredImage ] | ||
| ); | ||
|
|
||
| const defaultText = [ caption, credit ].filter( Boolean ).join( ' ' ); | ||
|
|
||
| if ( ! featuredImage ) { | ||
| return ( | ||
| <figcaption { ...blockProps }> | ||
| <span className="featured-image-caption-placeholder">{ __( 'Featured image caption.', 'newspack-plugin' ) }</span> | ||
| </figcaption> | ||
|
Comment on lines
+57
to
+59
|
||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <RichText | ||
| { ...blockProps } | ||
| tagName="figcaption" | ||
| value={ attributes.customCaption } | ||
| onChange={ val => setAttributes( { customCaption: val } ) } | ||
| placeholder={ defaultText || __( 'Write caption…', 'newspack-plugin' ) } | ||
| allowedFormats={ [ 'core/bold', 'core/italic', 'core/link' ] } | ||
| /> | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /** | ||
| * WordPress dependencies | ||
| */ | ||
| import { __ } from '@wordpress/i18n'; | ||
| import { caption as icon } from '@wordpress/icons'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import metadata from './block.json'; | ||
| import { Edit } from './edit'; | ||
| import colors from '../../../packages/colors/colors.module.scss'; | ||
| import './style.scss'; | ||
|
|
||
| export const title = __( 'Featured Image Caption', 'newspack-plugin' ); | ||
|
|
||
| const { name } = metadata; | ||
|
|
||
| export { metadata, name }; | ||
|
|
||
| export const settings = { | ||
| title, | ||
| icon: { | ||
| src: icon, | ||
| foreground: colors[ 'primary-400' ], | ||
| }, | ||
| keywords: [ | ||
| __( 'caption', 'newspack-plugin' ), | ||
| __( 'featured image', 'newspack-plugin' ), | ||
| __( 'credit', 'newspack-plugin' ), | ||
| __( 'newspack', 'newspack-plugin' ), | ||
| ], | ||
| description: __( 'Display the featured image caption and credit.', 'newspack-plugin' ), | ||
| edit: Edit, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| .wp-block-newspack-featured-image-caption { | ||
| .featured-image-caption-placeholder { | ||
| opacity: 0.6; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new block adds logic to derive caption/credit from the featured image entity (and format credits) but there are no accompanying unit tests. Similar blocks in this repo have Jest/Testing Library coverage; consider adding tests for “no featured image”, “caption only”, “credit only”, and “caption + org credit” to prevent regressions.