Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion blocks/post-title/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"render": "file:render.php",
"supports": {
"inserter": false,
"inserter": true,
"typography": {
"textAlign": true
}
Expand Down
12 changes: 8 additions & 4 deletions blocks/post-title/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface PostTitleEditProps {
include?: string;
orderby?: string;
};
pinnedPosts?: Array<number>;
pinnedPosts?: Array<number | null>;
customPostTitles?: {
postId: number;
title: string;
Expand All @@ -46,13 +46,13 @@ export default function Edit({
const queryParentId = queryParentIds.length ? queryParentIds[queryParentIds.length - 1] : null;

const {
postId,
postId = null,
pinnedPosts = [],
query: { postType = 'post' },
query: { postType = 'post' } = {},
customPostTitles = [],
} = context;
const { level = 3, supportsLevel } = attributes;
const [rawTitle = '', , fullTitle] = useEntityProp('postType', postType, 'title', postId.toString());
const [rawTitle = '', , fullTitle] = useEntityProp('postType', postType, 'title', postId?.toString());
const isPinned = pinnedPosts.includes(postId);
const currentCustomPostTitle = customPostTitles.find((item) => item?.postId === postId);
const TagName = !supportsLevel || level === 0 ? 'p' : `h${level}`;
Expand All @@ -74,6 +74,10 @@ export default function Edit({
}, [isPinned, postId, customPostTitles, currentCustomPostTitle, setAttributes, queryParentId]);

const handleOnChange = (title: string) => {
if (!postId) {
return;
}

/**
* Handle case for removing custom title from the collection if a
* custom title no longer exists.
Expand Down
8 changes: 7 additions & 1 deletion blocks/post/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@
"style": [
"file:style-index.css"
],
"attributes": {
"index": {
"type": "number"
}
},
"usesContext": [
"allPostIds",
"postId",
"query",
"moveData"
],
"render": "file:render.php",
"supports": {
"inserter": false
"inserter": true
}
}
92 changes: 73 additions & 19 deletions blocks/post/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { useState } from 'react';
import classnames from 'classnames';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
// @ts-expect-error BlockContextProvider not available in types yet.
import { InnerBlocks, useBlockProps, BlockContextProvider } from '@wordpress/block-editor';
import { PostPicker } from '@alleyinteractive/block-editor-tools';
import { dispatch, select, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { useCallback } from '@wordpress/element';

import type { Block } from '../../types/block';
import NoRender from './norender';
import SearchFilters from '../../components/SearchFilters';
import recursivelyFindBlocksByName from '../../services/recursivelyFindBlocksByName';

import type {
Term,
Expand All @@ -30,6 +33,9 @@ interface PostEditProps {
};
};
isSelected: boolean;
attributes: {
postId?: number;
};
}

interface PostTypeOrTerm {
Expand All @@ -52,14 +58,18 @@ interface Window {
export default function Edit({
clientId,
context: {
postId,
postId: contextPostId,
query: {
include = '',
} = {},
moveData = {},
},
isSelected,
attributes: {
postId: attributePostId,
},
}: PostEditProps) {
const postId = attributePostId || contextPostId;
const {
wpCurateQueryBlock: {
allowedPostTypes = [],
Expand All @@ -68,7 +78,10 @@ export default function Edit({

// @ts-ignore
const queryParents = select('core/block-editor').getBlockParentsByBlockName(clientId, ['wp-curate/query', 'wp-curate/subquery']);
const queryParentId = queryParents.pop();
const queryParentId = queryParents[queryParents.length - 1];

const templateBlockParents = select('core/block-editor').getBlockParentsByBlockName(clientId, 'core/post-template');
const hasPostTemplateBlock = templateBlockParents.length > 0;

// @ts-ignore
const queryParent = select('core/block-editor').getBlock(queryParentId) ?? {
Expand All @@ -87,15 +100,50 @@ export default function Edit({
postTypes = [],
terms = {} as Record<string, Term[]>,
supportsPostTypes = [],
numberOfPosts = 0,
} = {},
name: parentName,
} = queryParent;

const curateableBlocks: Block[] = [];
recursivelyFindBlocksByName(queryParent, ['wp-curate/post', 'core/post-template'], curateableBlocks);
const postBlockCount = curateableBlocks.filter((block) => block.name === 'wp-curate/post').length;
let templateBlockIndex = 0;
let templateBlockPostCount = 0;
if (hasPostTemplateBlock) {
const templateBlockId = templateBlockParents[templateBlockParents.length - 1];
templateBlockIndex = curateableBlocks.findIndex((block) => block.clientId === templateBlockId);
} else {
const thisBlockIndex = curateableBlocks.findIndex((block) => block.clientId === clientId);
templateBlockIndex = curateableBlocks.findIndex((block) => block.name === 'core/post-template');
// If there's a template block before this one, offset the index by the number of posts
// that would be rendered inside the template block.
if (templateBlockIndex !== -1 && templateBlockIndex < thisBlockIndex) {
// Number of posts, minus the total number of post blocks,
// removing the post block in the template block.
templateBlockPostCount = numberOfPosts - postBlockCount;
}
}

const [filtered, setFiltered] = useState(true);

const queryInclude = include.split(',').map((id: string) => parseInt(id, 10));
const index = queryInclude.findIndex((id: number) => id === postId);
const selected = posts[index] ?? null;
let selected = null;
let index = null;
if (hasPostTemplateBlock) {
const queryInclude = include.split(',').map((id: string) => parseInt(id, 10));
index = queryInclude.findIndex((id: number) => id === postId) + templateBlockIndex;
selected = posts[index] ?? null;
} else {
const postBlocks: Block[] = [];
recursivelyFindBlocksByName(queryParent, 'wp-curate/post', postBlocks);
// the index of the post block within the query block
index = postBlocks.findIndex((block) => block.clientId === clientId);
if (templateBlockIndex < index && templateBlockIndex !== -1) {
index -= 1; // minus 1 if for the Post block inside the template block.
}
index += templateBlockPostCount;
selected = posts[index] ?? null;
}
const postDeleted = selected !== null && selected !== postId;

const updatePost = useCallback((post: number | null) => {
Expand Down Expand Up @@ -142,27 +190,31 @@ export default function Edit({

const clickHandler = (e: MouseEvent) => {
let targetElement = e.target as HTMLElement;
// We want the wp-block-post element, not the wp-curate-post-block element.
if (targetElement.classList.contains('wp-curate-post-block')) {
targetElement = targetElement.parentElement as HTMLElement;
// If this one is hidden, select the previous one.
if (targetElement.style.display === 'none' && targetElement.previousElementSibling) {
targetElement = targetElement.previousElementSibling as HTMLElement;
}
// We want the wp-curate-post-block element not the wp-block-post element.
if (targetElement.classList.contains('wp-block-post')) {
targetElement = targetElement.querySelectorAll('.wp-curate-post-block')[0] as HTMLElement;
}
if (!targetElement.classList.contains('wp-block-post')
if (!targetElement.classList.contains('wp-curate-post-block')
&& !targetElement.classList.contains('components-button')
) {
window.removeEventListener('click', clickHandler);
cancelMove();
} else if (targetElement.classList.contains('wp-block-post')) {
} else if (targetElement.classList.contains('wp-block-wp-curate-post')) {
e.preventDefault();
const parent = targetElement.parentNode as HTMLElement;
// Get the parent wp-query block.
const parent = targetElement.closest('[data-type="wp-curate/query"]') as HTMLElement;
if (!parent) {
return;
}
let targetIndex = Array.prototype.indexOf.call(parent.children, targetElement);
if (parent.classList.contains('is-selected')) {
targetIndex -= 1;
}
const blockId = parent.dataset.block;
const parentId = select('core/block-editor').getBlockParentsByBlockName(blockId, 'wp-curate/query')[0];
const parentChildren = parent.querySelectorAll('.wp-curate-post-block');
const visibleChildren = [...parentChildren].filter((el) => el.parentElement?.style?.display !== 'none');

const targetIndex = Array.prototype.indexOf.call(visibleChildren, targetElement);
const parentId = parent.dataset.block;
if (!parentId) {
return;
}
Expand Down Expand Up @@ -244,7 +296,9 @@ export default function Edit({
},
)}
>
<InnerBlocks />
<BlockContextProvider value={{ postId }}>
<InnerBlocks />
</BlockContextProvider>
{isParentOfSelectedBlock || isSelected ? (
<div className="wp-curate-post-block__actions">
{selected && !postDeleted ? (
Expand Down
10 changes: 8 additions & 2 deletions blocks/post/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@
justify-content: flex-end;
margin-top: 0.5rem;
}

.wp-block-post-excerpt__more-text {
display: none;
}
}

.wp-curate-query-block--move .wp-block-post:hover {
.wp-curate-query-block--move .wp-block-post:hover,
.wp-curate-query-block--move .wp-curate-post-block:hover {
cursor: pointer;
}

.wp-block-post:hover .curate-droppable::after {
.wp-block-post:hover .wp-curate-post-block.curate-droppable::after,
.wp-curate-post-block.curate-droppable:hover::after {
align-items: center;
background: rgba(255,255,255,0.8);
border: 2px dashed var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
Expand Down
29 changes: 25 additions & 4 deletions blocks/query/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import type {
EditProps,
Option,
} from './types';
import type { Block } from '../../types/block';

import { mainDedupe } from '../../services/deduplicate';
import buildPostsApiPath from '../../services/buildPostsApiPath';
import buildTermQueryArgs from '../../services/buildTermQueryArgs';
import queryBlockPostFetcher from '../../services/queryBlockPostFetcher';
import recursivelyFindBlocksByName from '../../services/recursivelyFindBlocksByName';

import QueryControls from '../../components/QueryControls';
import QueryPlaceholder from '../../components/QueryPlaceholder';
Expand Down Expand Up @@ -56,7 +58,7 @@ export default function Edit({
deduplication = 'inherit',
maxNumberOfPosts = 10,
minNumberOfPosts = 1,
numberOfPosts = 5,
numberOfPosts: attributeNumberOfPosts = 5,
offset = 0,
posts: manualPosts = [],
postTypes = [],
Expand Down Expand Up @@ -87,11 +89,21 @@ export default function Edit({
setAttributes({ postTypes: allowedPostTypes.map((type) => type.slug) });
}

const hasInnerBlocks = useSelect(
const thisBlock = useSelect(
// @ts-expect-error
(select) => !!select(blockEditorStore).getBlocks(clientId).length,
(select) => select(blockEditorStore).getBlocksByClientId(clientId)[0],
[clientId],
);
const hasInnerBlocks = thisBlock ? thisBlock.innerBlocks.length > 0 : false;

const postBlocks: Block[] = [];
recursivelyFindBlocksByName(thisBlock, ['wp-curate/post', 'core/post-template'], postBlocks);
const hasTemplateBlock = postBlocks.some((block) => block.name === 'core/post-template');
const postBlockCount = postBlocks.filter((block) => block.name === 'wp-curate/post').length;

const numberOfPosts = hasTemplateBlock
? attributeNumberOfPosts
: postBlockCount;

// @ts-ignore
const [
Expand Down Expand Up @@ -197,6 +209,7 @@ export default function Edit({
data,
error,
blockIndex,
postBlockCount,
]);

// Make sure all the manual posts are still valid.
Expand Down Expand Up @@ -239,6 +252,12 @@ export default function Edit({
}
}, [numberOfPosts]); // eslint-disable-line react-hooks/exhaustive-deps

useEffect(() => {
if (attributeNumberOfPosts !== numberOfPosts && numberOfPosts !== 0) {
setAttributes({ numberOfPosts });
}
}, [numberOfPosts, attributeNumberOfPosts, setAttributes]);

const displayTypes: Option[] = allowedPostTypes
.map((type) => ({
label: type.name,
Expand Down Expand Up @@ -292,11 +311,13 @@ export default function Edit({
allowedTaxonomies={allowedTaxonomies}
deduplication={deduplication}
displayTypes={displayTypes}
hasNonTemplatePostBlocks={postBlockCount > 0}
hasTemplateBlock={hasTemplateBlock}
isPostDeduplicating={isPostDeduplicating}
manualPosts={manualPosts}
maxPosts={parseInt(maxPosts, 10)}
maxNumberOfPosts={maxNumberOfPosts}
minNumberOfPosts={minNumberOfPosts}
minNumberOfPosts={Math.max(minNumberOfPosts, postBlockCount)}
numberOfPosts={numberOfPosts}
offset={offset}
order={order}
Expand Down
15 changes: 12 additions & 3 deletions blocks/query/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,23 @@ function ( $slug ) {
function wp_curate_render_query_block( $attributes, $content ): string {
$proc = new WP_HTML_Tag_Processor( $content );

$found = false;

while ( $proc->next_tag( [ 'tag_name' => 'div' ] ) ) {
if ( $proc->get_attribute( 'class' ) && str_contains( (string) $proc->get_attribute( 'class' ), 'wp-block-wp-curate-post' ) ) {
$found = true;
break;
}
}

/*
* If a query returns no posts -- denoted by the absence of a list in the content -- don't
* show any of the inner content.
* If a query returns no posts -- denoted by the absence of an item with class `wp-block-wp-curate-post`
* in the content -- don't show any of the inner content.
*
* This approach is not great because the inner blocks will have been rendered already and their
* scripts and styles will have been enqueued, but it's not clear what other options are
* available because the post template inner block needs to render for us to know whether there
* are any posts to begin with.
*/
return $proc->next_tag( [ 'tag_name' => 'ul' ] ) === true || $proc->next_tag( [ 'tag_name' => 'ol' ] ) === true ? $content : '';
return $found ? $content : '';
}
1 change: 1 addition & 0 deletions blocks/query/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

.wp-block-wp-curate-query {
border: 1px dashed #e0e0e0;
min-height: 50px;
padding: 2px;
}
Expand Down
Loading