@wordpress/block-library
Version:
Block library for the WordPress editor.
621 lines (615 loc) • 24.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = LatestPostsEdit;
var _clsx = _interopRequireDefault(require("clsx"));
var _components = require("@wordpress/components");
var _i18n = require("@wordpress/i18n");
var _date = require("@wordpress/date");
var _blockEditor = require("@wordpress/block-editor");
var _data = require("@wordpress/data");
var _icons = require("@wordpress/icons");
var _coreData = require("@wordpress/core-data");
var _notices = require("@wordpress/notices");
var _compose = require("@wordpress/compose");
var _element = require("@wordpress/element");
var _constants = require("./constants");
var _hooks = require("../utils/hooks");
var _jsxRuntime = require("react/jsx-runtime");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
/**
* Module Constants
*/const CATEGORIES_LIST_QUERY = {
per_page: -1,
_fields: 'id,name',
context: 'view'
};
const USERS_LIST_QUERY = {
per_page: -1,
has_published_posts: ['post'],
context: 'view'
};
const imageAlignmentOptions = [{
value: 'none',
icon: _icons.alignNone,
label: (0, _i18n.__)('None')
}, {
value: 'left',
icon: _icons.positionLeft,
label: (0, _i18n.__)('Left')
}, {
value: 'center',
icon: _icons.positionCenter,
label: (0, _i18n.__)('Center')
}, {
value: 'right',
icon: _icons.positionRight,
label: (0, _i18n.__)('Right')
}];
function getFeaturedImageDetails(post, size) {
var _image$media_details$;
const image = post._embedded?.['wp:featuredmedia']?.['0'];
return {
url: (_image$media_details$ = image?.media_details?.sizes?.[size]?.source_url) !== null && _image$media_details$ !== void 0 ? _image$media_details$ : image?.source_url,
alt: image?.alt_text
};
}
function getCurrentAuthor(post) {
return post._embedded?.author?.[0];
}
function Controls({
attributes,
setAttributes,
postCount
}) {
var _categoriesList$reduc;
const {
postsToShow,
order,
orderBy,
categories,
selectedAuthor,
displayFeaturedImage,
displayPostContentRadio,
displayPostContent,
displayPostDate,
displayAuthor,
postLayout,
columns,
excerptLength,
featuredImageAlign,
featuredImageSizeSlug,
featuredImageSizeWidth,
featuredImageSizeHeight,
addLinkToFeaturedImage
} = attributes;
const {
imageSizes,
defaultImageWidth,
defaultImageHeight,
categoriesList,
authorList
} = (0, _data.useSelect)(select => {
var _settings$imageDimens, _settings$imageDimens2;
const {
getEntityRecords,
getUsers
} = select(_coreData.store);
const settings = select(_blockEditor.store).getSettings();
return {
defaultImageWidth: (_settings$imageDimens = settings.imageDimensions?.[featuredImageSizeSlug]?.width) !== null && _settings$imageDimens !== void 0 ? _settings$imageDimens : 0,
defaultImageHeight: (_settings$imageDimens2 = settings.imageDimensions?.[featuredImageSizeSlug]?.height) !== null && _settings$imageDimens2 !== void 0 ? _settings$imageDimens2 : 0,
imageSizes: settings.imageSizes,
categoriesList: getEntityRecords('taxonomy', 'category', CATEGORIES_LIST_QUERY),
authorList: getUsers(USERS_LIST_QUERY)
};
}, [featuredImageSizeSlug]);
const dropdownMenuProps = (0, _hooks.useToolsPanelDropdownMenuProps)();
const imageSizeOptions = imageSizes.filter(({
slug
}) => slug !== 'full').map(({
name,
slug
}) => ({
value: slug,
label: name
}));
const categorySuggestions = (_categoriesList$reduc = categoriesList?.reduce((accumulator, category) => ({
...accumulator,
[category.name]: category
}), {})) !== null && _categoriesList$reduc !== void 0 ? _categoriesList$reduc : {};
const selectCategories = tokens => {
const hasNoSuggestion = tokens.some(token => typeof token === 'string' && !categorySuggestions[token]);
if (hasNoSuggestion) {
return;
}
// Categories that are already will be objects, while new additions will be strings (the name).
// allCategories nomalizes the array so that they are all objects.
const allCategories = tokens.map(token => {
return typeof token === 'string' ? categorySuggestions[token] : token;
});
// We do nothing if the category is not selected
// from suggestions.
if (allCategories.includes(null)) {
return false;
}
setAttributes({
categories: allCategories
});
};
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, {
label: (0, _i18n.__)('Post content'),
resetAll: () => setAttributes({
displayPostContent: false,
displayPostContentRadio: 'excerpt',
excerptLength: _constants.DEFAULT_EXCERPT_LENGTH
}),
dropdownMenuProps: dropdownMenuProps,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => !!displayPostContent,
label: (0, _i18n.__)('Display post content'),
onDeselect: () => setAttributes({
displayPostContent: false
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Display post content'),
checked: displayPostContent,
onChange: value => setAttributes({
displayPostContent: value
})
})
}), displayPostContent && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => displayPostContentRadio !== 'excerpt',
label: (0, _i18n.__)('Content length'),
onDeselect: () => setAttributes({
displayPostContentRadio: 'excerpt'
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RadioControl, {
label: (0, _i18n.__)('Content length'),
selected: displayPostContentRadio,
options: [{
label: (0, _i18n.__)('Excerpt'),
value: 'excerpt'
}, {
label: (0, _i18n.__)('Full post'),
value: 'full_post'
}],
onChange: value => setAttributes({
displayPostContentRadio: value
})
})
}), displayPostContent && displayPostContentRadio === 'excerpt' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => excerptLength !== _constants.DEFAULT_EXCERPT_LENGTH,
label: (0, _i18n.__)('Max number of words'),
onDeselect: () => setAttributes({
excerptLength: _constants.DEFAULT_EXCERPT_LENGTH
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RangeControl, {
__nextHasNoMarginBottom: true,
__next40pxDefaultSize: true,
label: (0, _i18n.__)('Max number of words'),
value: excerptLength,
onChange: value => setAttributes({
excerptLength: value
}),
min: _constants.MIN_EXCERPT_LENGTH,
max: _constants.MAX_EXCERPT_LENGTH
})
})]
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, {
label: (0, _i18n.__)('Post meta'),
resetAll: () => setAttributes({
displayAuthor: false,
displayPostDate: false
}),
dropdownMenuProps: dropdownMenuProps,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => !!displayAuthor,
label: (0, _i18n.__)('Display author name'),
onDeselect: () => setAttributes({
displayAuthor: false
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Display author name'),
checked: displayAuthor,
onChange: value => setAttributes({
displayAuthor: value
})
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => !!displayPostDate,
label: (0, _i18n.__)('Display post date'),
onDeselect: () => setAttributes({
displayPostDate: false
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Display post date'),
checked: displayPostDate,
onChange: value => setAttributes({
displayPostDate: value
})
})
})]
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, {
label: (0, _i18n.__)('Featured image'),
resetAll: () => setAttributes({
displayFeaturedImage: false,
featuredImageAlign: undefined,
featuredImageSizeSlug: 'thumbnail',
featuredImageSizeWidth: null,
featuredImageSizeHeight: null,
addLinkToFeaturedImage: false
}),
dropdownMenuProps: dropdownMenuProps,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => !!displayFeaturedImage,
label: (0, _i18n.__)('Display featured image'),
onDeselect: () => setAttributes({
displayFeaturedImage: false
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Display featured image'),
checked: displayFeaturedImage,
onChange: value => setAttributes({
displayFeaturedImage: value
})
})
}), displayFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => featuredImageSizeSlug !== 'thumbnail' || featuredImageSizeWidth !== null || featuredImageSizeHeight !== null,
label: (0, _i18n.__)('Image size'),
onDeselect: () => setAttributes({
featuredImageSizeSlug: 'thumbnail',
featuredImageSizeWidth: null,
featuredImageSizeHeight: null
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.__experimentalImageSizeControl, {
onChange: value => {
const newAttrs = {};
if (value.hasOwnProperty('width')) {
newAttrs.featuredImageSizeWidth = value.width;
}
if (value.hasOwnProperty('height')) {
newAttrs.featuredImageSizeHeight = value.height;
}
setAttributes(newAttrs);
},
slug: featuredImageSizeSlug,
width: featuredImageSizeWidth,
height: featuredImageSizeHeight,
imageWidth: defaultImageWidth,
imageHeight: defaultImageHeight,
imageSizeOptions: imageSizeOptions,
imageSizeHelp: (0, _i18n.__)('Select the size of the source image.'),
onChangeImage: value => setAttributes({
featuredImageSizeSlug: value,
featuredImageSizeWidth: undefined,
featuredImageSizeHeight: undefined
})
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => !!featuredImageAlign,
label: (0, _i18n.__)('Image alignment'),
onDeselect: () => setAttributes({
featuredImageAlign: undefined
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToggleGroupControl, {
className: "editor-latest-posts-image-alignment-control",
__nextHasNoMarginBottom: true,
__next40pxDefaultSize: true,
label: (0, _i18n.__)('Image alignment'),
value: featuredImageAlign || 'none',
onChange: value => setAttributes({
featuredImageAlign: value !== 'none' ? value : undefined
}),
children: imageAlignmentOptions.map(({
value,
icon,
label
}) => {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToggleGroupControlOptionIcon, {
value: value,
icon: icon,
label: label
}, value);
})
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => !!addLinkToFeaturedImage,
label: (0, _i18n.__)('Add link to featured image'),
onDeselect: () => setAttributes({
addLinkToFeaturedImage: false
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Add link to featured image'),
checked: addLinkToFeaturedImage,
onChange: value => setAttributes({
addLinkToFeaturedImage: value
})
})
})]
})]
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, {
label: (0, _i18n.__)('Sorting and filtering'),
resetAll: () => setAttributes({
order: 'desc',
orderBy: 'date',
postsToShow: 5,
categories: undefined,
selectedAuthor: undefined,
columns: 3
}),
dropdownMenuProps: dropdownMenuProps,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => order !== 'desc' || orderBy !== 'date' || postsToShow !== 5 || categories?.length > 0 || !!selectedAuthor,
label: (0, _i18n.__)('Sort and filter'),
onDeselect: () => setAttributes({
order: 'desc',
orderBy: 'date',
postsToShow: 5,
categories: undefined,
selectedAuthor: undefined
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.QueryControls, {
order,
orderBy,
numberOfItems: postsToShow,
onOrderChange: value => setAttributes({
order: value
}),
onOrderByChange: value => setAttributes({
orderBy: value
}),
onNumberOfItemsChange: value => setAttributes({
postsToShow: value
}),
categorySuggestions: categorySuggestions,
onCategoryChange: selectCategories,
selectedCategories: categories,
onAuthorChange: value => setAttributes({
selectedAuthor: '' !== value ? Number(value) : undefined
}),
authorList: authorList !== null && authorList !== void 0 ? authorList : [],
selectedAuthorId: selectedAuthor
})
}), postLayout === 'grid' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
hasValue: () => columns !== 3,
label: (0, _i18n.__)('Columns'),
onDeselect: () => setAttributes({
columns: 3
}),
isShownByDefault: true,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RangeControl, {
__nextHasNoMarginBottom: true,
__next40pxDefaultSize: true,
label: (0, _i18n.__)('Columns'),
value: columns,
onChange: value => setAttributes({
columns: value
}),
min: 2,
max: !postCount ? _constants.MAX_POSTS_COLUMNS : Math.min(_constants.MAX_POSTS_COLUMNS, postCount),
required: true
})
})]
})]
});
}
function LatestPostsEdit({
attributes,
setAttributes
}) {
var _latestPosts$length;
const instanceId = (0, _compose.useInstanceId)(LatestPostsEdit);
const {
postsToShow,
order,
orderBy,
categories,
selectedAuthor,
displayFeaturedImage,
displayPostContentRadio,
displayPostContent,
displayPostDate,
displayAuthor,
postLayout,
columns,
excerptLength,
featuredImageAlign,
featuredImageSizeSlug,
featuredImageSizeWidth,
featuredImageSizeHeight,
addLinkToFeaturedImage
} = attributes;
const {
latestPosts
} = (0, _data.useSelect)(select => {
const {
getEntityRecords
} = select(_coreData.store);
const catIds = categories && categories.length > 0 ? categories.map(cat => cat.id) : [];
const latestPostsQuery = Object.fromEntries(Object.entries({
categories: catIds,
author: selectedAuthor,
order,
orderby: orderBy,
per_page: postsToShow,
_embed: 'author,wp:featuredmedia',
ignore_sticky: true
}).filter(([, value]) => typeof value !== 'undefined'));
return {
latestPosts: getEntityRecords('postType', 'post', latestPostsQuery)
};
}, [postsToShow, order, orderBy, categories, selectedAuthor]);
// If a user clicks to a link prevent redirection and show a warning.
const {
createWarningNotice
} = (0, _data.useDispatch)(_notices.store);
const showRedirectionPreventedNotice = event => {
event.preventDefault();
createWarningNotice((0, _i18n.__)('Links are disabled in the editor.'), {
id: `block-library/core/latest-posts/redirection-prevented/${instanceId}`,
type: 'snackbar'
});
};
const hasPosts = !!latestPosts?.length;
const inspectorControls = /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Controls, {
attributes: attributes,
setAttributes: setAttributes,
postCount: (_latestPosts$length = latestPosts?.length) !== null && _latestPosts$length !== void 0 ? _latestPosts$length : 0
})
});
const blockProps = (0, _blockEditor.useBlockProps)({
className: (0, _clsx.default)({
'wp-block-latest-posts__list': true,
'is-grid': postLayout === 'grid',
'has-dates': displayPostDate,
'has-author': displayAuthor,
[`columns-${columns}`]: postLayout === 'grid'
})
});
if (!hasPosts) {
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
...blockProps,
children: [inspectorControls, /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Placeholder, {
icon: _icons.pin,
label: (0, _i18n.__)('Latest Posts'),
children: !Array.isArray(latestPosts) ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {}) : (0, _i18n.__)('No posts found.')
})]
});
}
// Removing posts from display should be instant.
const displayPosts = latestPosts.length > postsToShow ? latestPosts.slice(0, postsToShow) : latestPosts;
const layoutControls = [{
icon: _icons.list,
title: (0, _i18n._x)('List view', 'Latest posts block display setting'),
onClick: () => setAttributes({
postLayout: 'list'
}),
isActive: postLayout === 'list'
}, {
icon: _icons.grid,
title: (0, _i18n._x)('Grid view', 'Latest posts block display setting'),
onClick: () => setAttributes({
postLayout: 'grid'
}),
isActive: postLayout === 'grid'
}];
const dateFormat = (0, _date.getSettings)().formats.date;
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [inspectorControls, /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, {
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarGroup, {
controls: layoutControls
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("ul", {
...blockProps,
children: displayPosts.map(post => {
const titleTrimmed = post.title.rendered.trim();
let excerpt = post.excerpt.rendered;
const currentAuthor = getCurrentAuthor(post);
const excerptElement = document.createElement('div');
excerptElement.innerHTML = excerpt;
excerpt = excerptElement.textContent || excerptElement.innerText || '';
const {
url: imageSourceUrl,
alt: featuredImageAlt
} = getFeaturedImageDetails(post, featuredImageSizeSlug);
const imageClasses = (0, _clsx.default)({
'wp-block-latest-posts__featured-image': true,
[`align${featuredImageAlign}`]: !!featuredImageAlign
});
const renderFeaturedImage = displayFeaturedImage && imageSourceUrl;
const featuredImage = renderFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
src: imageSourceUrl,
alt: featuredImageAlt,
style: {
maxWidth: featuredImageSizeWidth,
maxHeight: featuredImageSizeHeight
}
});
const needsReadMore = excerptLength < excerpt.trim().split(' ').length && post.excerpt.raw === '';
const postExcerpt = needsReadMore ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [excerpt.trim().split(' ', excerptLength).join(' '), (0, _element.createInterpolateElement)((0, _i18n.sprintf)(/* translators: 1: Hidden accessibility text: Post title */
(0, _i18n.__)('… <a>Read more<span>: %1$s</span></a>'), titleTrimmed || (0, _i18n.__)('(no title)')), {
a:
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/anchor-has-content
(0, _jsxRuntime.jsx)("a", {
className: "wp-block-latest-posts__read-more",
href: post.link,
rel: "noopener noreferrer",
onClick: showRedirectionPreventedNotice
}),
span: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
className: "screen-reader-text"
})
})]
}) : excerpt;
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("li", {
children: [renderFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: imageClasses,
children: addLinkToFeaturedImage ? /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
href: post.link,
rel: "noreferrer noopener",
onClick: showRedirectionPreventedNotice,
children: featuredImage
}) : featuredImage
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
className: "wp-block-latest-posts__post-title",
href: post.link,
rel: "noreferrer noopener",
dangerouslySetInnerHTML: !!titleTrimmed ? {
__html: titleTrimmed
} : undefined,
onClick: showRedirectionPreventedNotice,
children: !titleTrimmed ? (0, _i18n.__)('(no title)') : null
}), displayAuthor && currentAuthor && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: "wp-block-latest-posts__post-author",
children: (0, _i18n.sprintf)(/* translators: byline. %s: author. */
(0, _i18n.__)('by %s'), currentAuthor.name)
}), displayPostDate && post.date_gmt && /*#__PURE__*/(0, _jsxRuntime.jsx)("time", {
dateTime: (0, _date.format)('c', post.date_gmt),
className: "wp-block-latest-posts__post-date",
children: (0, _date.dateI18n)(dateFormat, post.date_gmt)
}), displayPostContent && displayPostContentRadio === 'excerpt' && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: "wp-block-latest-posts__post-excerpt",
children: postExcerpt
}), displayPostContent && displayPostContentRadio === 'full_post' && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: "wp-block-latest-posts__post-full-content",
dangerouslySetInnerHTML: {
__html: post.content.raw.trim()
}
})]
}, post.id);
})
})]
});
}
//# sourceMappingURL=edit.js.map