Skip to content

Commit

Permalink
Merge pull request #2986 from 10up/feature/2972
Browse files Browse the repository at this point in the history
Add Comments block.
  • Loading branch information
felipeelia authored Nov 9, 2022
2 parents d3d1c1c + de7ca49 commit c06cc5c
Show file tree
Hide file tree
Showing 10 changed files with 587 additions and 66 deletions.
106 changes: 106 additions & 0 deletions assets/js/blocks/comments/Edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* WordPress dependencies.
*/
import { InspectorControls, RichText, useBlockProps } from '@wordpress/block-editor';
import { CheckboxControl, PanelBody } from '@wordpress/components';
import { useMemo } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';

/**
* Window dependencies.
*/
const { searchablePostTypes } = window.epComments;

/**
* Edit component.
*
* @param {object} props Component props.
* @param {object} props.attributes Block attributes.
* @param {Function} props.setAttributes Block attribute setter.
* @returns {Function} Component.
*/
export default ({ attributes, setAttributes }) => {
const { label, postTypes } = attributes;

const blockProps = useBlockProps({
className: 'ep-widget-search-comments',
});

const allSelected = useMemo(() => {
return postTypes.length === 0;
}, [postTypes]);

/**
* Handle checking a post type option.
*
* @param {string} postType Post type slug.
* @param {boolean} checked Whether post type is selected.
* @returns {void}
*/
const onChange = (postType, checked) => {
const newPostTypes = checked
? [...postTypes, postType]
: postTypes.filter((v) => v !== postType);

setAttributes({ postTypes: newPostTypes });
};

/**
* Handle selecting all post types.
*
* @param {boolean} checked Whether all has been selected.
* @returns {void}
*/
const onSelectAll = (checked) => {
if (checked) {
setAttributes({ postTypes: [] });
} else {
setAttributes({ postTypes: Object.keys(searchablePostTypes) });
}
};

return (
<>
<div {...blockProps}>
<RichText
aria-label={__('Label text')}
placeholder={__('Add label…')}
withoutInteractiveFormatting
value={label}
onChange={(html) => setAttributes({ label: html })}
/>
<input
autoComplete="off"
className="ep-widget-search-comments-input"
disabled
type="search"
/>
</div>
<InspectorControls>
<PanelBody title={__('Search settings', 'elasticpress')}>
<CheckboxControl
checked={allSelected}
label={__('Search all comments', 'elasticpress')}
onChange={onSelectAll}
/>
{Object.entries(searchablePostTypes).map(([postType, postTypeLabel]) => {
const label = sprintf(
/* translators: %s: Post type label, plural. */
__('Search comments on %s', 'elasticpress'),
postTypeLabel,
);

return (
<CheckboxControl
checked={postTypes.includes(postType)}
indeterminate={allSelected}
label={label}
onChange={(checked) => onChange(postType, checked)}
/>
);
})}
</PanelBody>
</InspectorControls>
</>
);
};
22 changes: 22 additions & 0 deletions assets/js/blocks/comments/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"title": "Search Comments (ElasticPress)",
"icon": "search",
"textdomain": "elasticpress",
"name": "elasticpress/comments",
"category": "widgets",
"attributes": {
"label": {
"default": "Search comments",
"type": "string"
},
"postTypes": {
"default": [],
"type": "array"
}
},
"editorScript": "elasticpress-comments-editor-script",
"script": "elasticpress-comments",
"style": "elasticpress-comments"
}
17 changes: 17 additions & 0 deletions assets/js/blocks/comments/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* WordPress dependencies.
*/
import { registerBlockType } from '@wordpress/blocks';

/**
* Internal dependencies.
*/
import Edit from './Edit';
import block from './block.json';
import transforms from './transforms';

registerBlockType(block, {
edit: (props) => <Edit {...props} />,
save: () => {},
transforms,
});
29 changes: 29 additions & 0 deletions assets/js/blocks/comments/transforms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* WordPress dependencies.
*/
import { createBlock } from '@wordpress/blocks';

/**
* Facet widget block transforms.
*/
export default {
from: [
{
type: 'block',
blocks: ['core/legacy-widget'],
isMatch: ({ idBase }) => idBase === 'ep-comments',
transform: ({ instance }) => {
const { title = null, post_type: postTypes } = instance.raw;

if (!title) {
return createBlock('elasticpress/comments', { postTypes });
}

return [
createBlock('core/heading', { content: title }),
createBlock('elasticpress/comments', { postTypes }),
];
},
},
],
};
4 changes: 3 additions & 1 deletion assets/js/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ const widgetSearchComments = document.querySelectorAll('.ep-widget-search-commen
let selectedResultIndex;

widgetSearchComments.forEach((element) => {
const { id } = element;
const input = document.createElement('input');
input.setAttribute('autocomplete', 'off');
input.setAttribute('type', 'search');
input.setAttribute('class', 'ep-widget-search-comments-input');
input.setAttribute('id', `${id}-s`);

const resultList = document.createElement('ul');
resultList.setAttribute('class', 'ep-widget-search-comments-results');
Expand Down Expand Up @@ -136,7 +138,7 @@ function setIsLoading(isLoading, inputElement) {
function fetchResults(inputElement) {
if (hasMinimumLength(inputElement)) {
const widget = findAncestorByClass(inputElement, 'ep-widget-search-comments');
const postTypeElement = widget.querySelector('#ep-widget-search-comments-post-type');
const postTypeElement = widget.querySelector('.ep-widget-search-comments-post-type');
const postTypeQueryParameter = postTypeElement?.value
? `&post_type=${postTypeElement.value.trim()}`
: '';
Expand Down
172 changes: 172 additions & 0 deletions includes/classes/Feature/Comments/Comments.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use ElasticPress\Indexable as Indexable;
use ElasticPress\Features as Features;
use ElasticPress\FeatureRequirementsStatus as FeatureRequirementsStatus;
use ElasticPress\Utils;

/**
* Comments feature class
Expand Down Expand Up @@ -46,9 +47,12 @@ public function __construct() {
public function setup() {
Indexables::factory()->register( new Indexable\Comment\Comment() );

add_action( 'init', [ $this, 'register_block' ] );
add_action( 'init', [ $this, 'search_setup' ] );
add_action( 'widgets_init', [ $this, 'register_widget' ] );
add_action( 'rest_api_init', [ $this, 'rest_api_init' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'frontend_scripts' ] );
add_filter( 'widget_types_to_hide_from_legacy_widget_block', [ $this, 'hide_legacy_widget' ] );
}

/**
Expand Down Expand Up @@ -251,4 +255,172 @@ function ( $post_type ) {
*/
return apply_filters( 'ep_comment_search_widget_response', $return );
}

/**
* Get a list of searchable post types that support comments.
*
* @return array Array of post type labels keyed by post type.
* @since 4.4.0
*/
public static function get_searchable_post_types() {
$searchable_post_types = array();

$post_types = Features::factory()->get_registered_feature( 'search' )->get_searchable_post_types();
$post_types = array_filter(
$post_types,
function( $post_type ) {
return post_type_supports( $post_type, 'comments' );
}
);

foreach ( $post_types as $post_type ) {
$post_type_object = get_post_type_object( $post_type );
$post_type_labels = get_post_type_labels( $post_type_object );

$searchable_post_types[ $post_type ] = $post_type_labels->name;
}

return $searchable_post_types;
}

/**
* Enqueue frontend scripts.
*
* @since 4.4.0
*/
public function frontend_scripts() {
wp_register_script(
'elasticpress-comments',
EP_URL . 'dist/js/comments-script.js',
Utils\get_asset_info( 'comments-script', 'dependencies' ),
Utils\get_asset_info( 'comments-script', 'version' ),
true
);

wp_set_script_translations( 'elasticpress-comments', 'elasticpress' );

wp_register_style(
'elasticpress-comments',
EP_URL . 'dist/css/comments-styles.css',
Utils\get_asset_info( 'comments-styles', 'dependencies' ),
Utils\get_asset_info( 'comments-styles', 'version' )
);

$default_script_data = [
'noResultsFoundText' => esc_html__( 'We could not find any results', 'elasticpress' ),
'minimumLengthToSearch' => 2,
'restApiEndpoint' => get_rest_url( null, 'elasticpress/v1/comments' ),
];

/**
* Filter the l10n data attached to the Widget Search Comments script
*
* @since 3.6.0
* @hook ep_comment_search_widget_l10n_data_script
* @param {array} $default_script_data Default data attached to the script
* @return {array} New l10n data to be attached
*/
$script_data = apply_filters( 'ep_comment_search_widget_l10n_data_script', $default_script_data );

wp_localize_script(
'elasticpress-comments',
'epc',
$script_data
);
}

/**
* Register block.
*
* @since 4.4.0
*/
public function register_block() {
/**
* Registering it here so translation works
*
* @see https://core.trac.wordpress.org/ticket/54797#comment:20
*/
wp_register_script(
'elasticpress-comments-editor-script',
EP_URL . 'dist/js/comments-block-script.js',
Utils\get_asset_info( 'comments-block-script', 'dependencies' ),
Utils\get_asset_info( 'comments-block-script', 'version' ),
true
);

wp_set_script_translations( 'elasticpress-comments-editor-script', 'elasticpress' );

wp_localize_script(
'elasticpress-comments-editor-script',
'epComments',
[
'searchablePostTypes' => self::get_searchable_post_types(),
]
);

register_block_type_from_metadata(
EP_PATH . 'assets/js/blocks/comments',
[
'render_callback' => [ $this, 'render_block' ],
]
);
}

/**
* Render block.
*
* @param array $attributes Block attributes
* @since 4.4.0
* @return string
*/
public function render_block( $attributes ) {
$wrapper_id = 'ep-search-comments-' . uniqid();
$wrapper_attributes = get_block_wrapper_attributes(
array(
'id' => $wrapper_id,
'class' => 'ep-widget-search-comments',
)
);

$label = ! empty( $attributes['label'] )
? sprintf(
'<label for="%1$s-s">%2$s</label>',
esc_attr( $wrapper_id ),
wp_kses_post( $attributes['label'] )
)
: '';

$post_types_input = ! empty( $attributes['postTypes'] )
? sprintf(
'<input class="ep-widget-search-comments-post-type" type="hidden" id="%1$s-post-type" value="%2$s">',
esc_attr( $wrapper_id ),
esc_attr( implode( ',', $attributes['postTypes'] ) )
)
: '';

$block_html = sprintf(
'<div %1$s>%2$s%3$s</div>',
$wrapper_attributes, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$label,
$post_types_input
);

return $block_html;
}

/**
* Hide the legacy widget.
*
* Hides the legacy widget in favor of the Block when the block editor
* is in use and the legacy widget has not been used.
*
* @since 4.4.0
* @param array $widgets An array of excluded widget-type IDs.
* @return array array of excluded widget-type IDs to hide.
*/
public function hide_legacy_widget( $widgets ) {
$widgets[] = 'ep-comments';

return $widgets;
}
}
Loading

0 comments on commit c06cc5c

Please sign in to comment.