diff --git a/.eslintrc.json b/.eslintrc.json index 4ca16399d..aaaa70f3b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -23,7 +23,8 @@ "React": "readonly", "Block": "readonly", "classifai_term_cleanup_params": "readonly", - "classifAISettings": "readonly" + "classifAISettings": "readonly", + "classifaiRecommendedContentSettings": "readonly" }, "rules": { "react/jsx-no-undef": "off" diff --git a/includes/Classifai/Features/RecommendedContent.php b/includes/Classifai/Features/RecommendedContent.php index 0e0f4cf1d..1b662f2e6 100644 --- a/includes/Classifai/Features/RecommendedContent.php +++ b/includes/Classifai/Features/RecommendedContent.php @@ -42,6 +42,8 @@ public function __construct() { public function feature_setup() { $settings = $this->get_settings(); + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_feature_setting_assets' ] ); + if ( isset( $settings['provider'] ) && OpenAIEmbeddings::ID === $settings['provider'] ) { add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] ); add_filter( 'pre_render_block', [ $this, 'pre_render_block' ], 10, 2 ); @@ -65,10 +67,24 @@ public function get_enable_description(): string { */ public function get_feature_default_settings(): array { return [ - 'provider' => OpenAIEmbeddings::ID, + 'provider' => OpenAIEmbeddings::ID, + 'default_template' => 'title-date', ]; } + /** + * Enqueues feature-level assets. + */ + public function enqueue_feature_setting_assets() { + wp_enqueue_script( + 'classifai-plugin-recommended-content-feature-fields', + CLASSIFAI_PLUGIN_URL . 'dist/classifai-plugin-recommended-content-feature-fields.js', + get_asset_info( 'classifai-plugin-recommended-content-feature-fields', 'dependencies' ), + get_asset_info( 'classifai-plugin-recommended-content-feature-fields', 'version' ), + true + ); + } + /** * Enqueue editor assets. */ @@ -80,6 +96,19 @@ public function enqueue_editor_assets() { get_asset_info( 'recommended-content-block-variation', 'version' ), true ); + + $settings = $this->get_settings(); + $data = [ + 'default_template' => $settings['default_template'], + ]; + + wp_add_inline_script( + 'classifai-recommended-content-block-variation', + sprintf( + 'const classifaiRecommendedContentSettings = %s', + wp_json_encode( $data ) + ) + ); } /** diff --git a/src/js/features/recommended-content/feature-fields-plugin.js b/src/js/features/recommended-content/feature-fields-plugin.js new file mode 100644 index 000000000..9f86d410a --- /dev/null +++ b/src/js/features/recommended-content/feature-fields-plugin.js @@ -0,0 +1,123 @@ +import { registerPlugin } from '@wordpress/plugins'; +import { __ } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; +import { registerCoreBlocks } from '@wordpress/block-library'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/blocks'; + +import { + Fill, + Flex, + FlexItem, + Icon, +} from '@wordpress/components'; + +import { SettingsRow } from '../../settings/components/settings-row'; + +// To access core/query details. +registerCoreBlocks(); + +registerPlugin( 'classifai-plugin-recommended-content-feature-fields', { + render: AdditionalFeatureFields, + scope: 'feature-recommended-content' +} ); + +function AdditionalFeatureFields() { + const featureSettings = useSelect( ( select ) => + select( 'classifai-settings' ).getFeatureSettings() + ); + + const { setFeatureSettings } = useDispatch( 'classifai-settings' ); + + const defaultTemplate = featureSettings.default_template; + const blockVariations = useSelect( ( select ) => + select( coreStore ).getBlockVariations( 'core/query' ) + ); + const [ focusedTemplate, setFocusedTemplate ] = useState( featureSettings.defaultTemplate ); + const [ isTemplateInFocus, setIsTemplateInFocus ] = useState( false ); + + const iconWrapperStyle = { + border: '1px solid #e0e0e0', + width: '120px', + borderRadius: '6px', + cursor: 'pointer', + }; + + return ( + + + + { blockVariations.map( ( variation, index ) => ( + { + setFocusedTemplate( variation.name ); + setIsTemplateInFocus( true ); + } } + onBlur={ () => + setIsTemplateInFocus( false ) + } + onKeyDown={ ( e ) => { + if ( + 'Space' === e.code || + 'Enter' === e.code + ) { + e.preventDefault(); + setFeatureSettings( { + default_template: + variation.name, + } ); + } + } } + style={ { + ...iconWrapperStyle, + borderColor: + defaultTemplate === variation.name + ? 'var(--wp-admin-theme-color)' + : '#e0e0e0', + borderWidth: + defaultTemplate === + variation.name && '1px', + backgroundColor: + defaultTemplate === + variation.name && + 'color-mix(in srgb, var(--wp-admin-theme-color) 10%, transparent)', + outline: + isTemplateInFocus && + focusedTemplate === + variation.name && + '2px solid var(--wp-admin-theme-color)', + } } + onClick={ () => + setFeatureSettings( { + default_template: variation.name, + } ) + } + > + + + { variation.title } + + + ) ) } + + + + ); +} diff --git a/src/js/features/recommended-content/variation.js b/src/js/features/recommended-content/variation.js index ce4fc39c8..53e074cf6 100644 --- a/src/js/features/recommended-content/variation.js +++ b/src/js/features/recommended-content/variation.js @@ -3,45 +3,66 @@ */ import { registerBlockVariation } from '@wordpress/blocks'; import { __ } from '@wordpress/i18n'; +import domReady from '@wordpress/dom-ready'; /** * Internal Dependencies. */ import { ReactComponent as icon } from '../../../../assets/img/block-icon.svg'; -registerBlockVariation( 'core/query', { - name: 'classifai/recommended-content', - title: __( 'Recommended Content', 'classifai' ), - description: __( - 'Render recommended content based on embeddings.', - 'classifai' - ), - icon, - attributes: { - namespace: 'classifai/recommended-content', - align: 'wide', - className: 'classifai-recommended-content', - query: { - postType: 'post', - perPage: 3, - useAI: true, - }, - }, - allowedControls: [ 'order', 'postCount' ], - innerBlocks: [ - [ - 'core/post-template', - { - layout: { type: 'grid', columnCount: 3 }, +domReady( () => { + const { default_template: defaultTemplate = 'title-date' } = + classifaiRecommendedContentSettings; + const registeredVariations = wp.blocks.getBlockVariations( 'core/query' ); + const variation = registeredVariations.find( + ( __variation ) => __variation.name === defaultTemplate + ); + + variation.innerBlocks = variation.innerBlocks.filter( ( innerBlock ) => 'core/post-template' === innerBlock[0] ); + variation.innerBlocks.forEach( ( innerBlock, index ) => { + if ( 'core/post-template' === innerBlock[0] ) { + variation.innerBlocks[ index ][1] = Object.assign( variation.innerBlocks[ index ][1], { + layout: { + type: 'grid', + columnCount: 3, + } + } ); + + if ( Array.isArray( innerBlock[2] ) ) { + innerBlock[2].forEach( ( __innerBlock, __index ) => { + if ( 'core/post-title' === __innerBlock[0] ) { + variation.innerBlocks[ index ][2][ __index ][1] = variation.innerBlocks[ index ][2][ __index ][1] || {}; + variation.innerBlocks[ index ][2][ __index ][1] = Object.assign( variation.innerBlocks[ index ][2][ __index ][1], { + level: 3, + isLink: true, + } ); + } + } ); + } + } + } ); + + registerBlockVariation( 'core/query', { + name: 'classifai/recommended-content', + title: __( 'Recommended Content', 'classifai' ), + description: __( + 'Render recommended content based on embeddings.', + 'classifai' + ), + icon, + attributes: { + namespace: 'classifai/recommended-content', + align: 'wide', + className: 'classifai-recommended-content', + query: { + postType: 'post', + perPage: 3, + useAI: true, }, - [ - [ 'core/post-featured-image' ], - [ 'core/post-title', { level: 3, isLink: true } ], - [ 'core/post-date' ], - [ 'core/post-excerpt' ], - ], - ], - ], - isActive: [ 'namespace' ], - scope: [ 'inserter' ], + }, + allowedControls: [ 'order', 'postCount' ], + innerBlocks: variation.innerBlocks, + isActive: [ 'namespace' ], + scope: [ 'inserter' ], + } ); } ); diff --git a/webpack.config.js b/webpack.config.js index 7b3072ab6..726452e4d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -43,6 +43,7 @@ module.exports = { './src/js/features/image-generation/extend-image-block-generate-image.js' ], 'classifai-plugin-image-generation-generate-image-media-upload': './src/js/features/image-generation/media-modal/views/generate-image-media-upload.js', + 'classifai-plugin-recommended-content-feature-fields': './src/js/features/recommended-content/feature-fields-plugin.js', settings: './src/js/settings/index.js', }, module: {