Skip to content

Commit 9aac8dd

Browse files
Refactors for layout selector and WP 6.8 compatibility (#2639)
* refactors for layout selector and wp 6.8 compat * ensure the layout selector auto-opens * try test fix * try pipeline fixes
1 parent 8347bf2 commit 9aac8dd

File tree

7 files changed

+187
-139
lines changed

7 files changed

+187
-139
lines changed

.github/workflows/test-e2e-cypress.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
- name: Setup Spec Matrix
4242
id: setup-spec-matrix
4343
run: |
44-
changed_files=$(git diff --name-only --diff-filter=ADMR ${{ github.event.before }} origin/master)
44+
changed_files=$(git diff --name-only --diff-filter=ADMR origin/master...HEAD)
4545
spec_list=()
4646
declare -A spec_seen
4747

.github/workflows/test-e2e.yml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,3 @@ jobs:
3535
wpVersion: "WordPress/WordPress#${{matrix.wp}}"
3636
theme: ${{matrix.theme}}
3737
phpVersion: ${{matrix.php}}
38-
concurrency:
39-
group: >
40-
${{
41-
format(
42-
'chrome-e2e-WP{0}-PHP{1}-{2}',
43-
matrix.wp,
44-
matrix.php,
45-
matrix.theme == '' && 'twentytwentythree' || 'go'
46-
)
47-
}}
48-
cancel-in-progress: true

.github/workflows/test-wp-next.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ jobs:
3737
wpVersion: ${{ needs.set_constant.outputs.wp_next }}
3838
installPath: "tests-wordpress-6.8-RC2"
3939
theme: "https://downloads.wordpress.org/theme/go.zip"
40-
concurrency:
41-
group: chrome-wp-next
42-
cancel-in-progress: true
4340

4441
# PHP Unit testing
4542
php_unit_wp_next:

src/extensions/layout-selector/index.js

Lines changed: 83 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ import { useEntityProp } from '@wordpress/core-data';
1313
import { __, sprintf } from '@wordpress/i18n';
1414
import { Button, DropdownMenu, Icon, MenuGroup, MenuItem, Modal, Path, SVG } from '@wordpress/components';
1515
import { Component, isValidElement } from '@wordpress/element';
16-
import { compose, ifCondition } from '@wordpress/compose';
17-
import { register, useSelect, withDispatch, withSelect } from '@wordpress/data';
16+
import { register, useSelect, useDispatch } from '@wordpress/data';
1817

1918
/**
2019
* Internal dependencies
@@ -176,78 +175,89 @@ class LayoutSelector extends Component {
176175
}
177176
}
178177

178+
const LayoutSelectorApp = () => {
179+
// Hooks must be called unconditionally and in the same order every render.
180+
const [ layoutSelectorEnabled ] = useEntityProp( 'root', 'site', LAYOUT_SELECTOR_FEATURE_ENABLED_KEY );
181+
182+
const layouts = useComputedLayouts();
183+
const categories = useCategories( layouts );
184+
185+
const {
186+
hasLayouts,
187+
hasCategories,
188+
selectedCategory,
189+
templateSelectorActive,
190+
isMobile,
191+
hasComputedLayouts,
192+
} = useSelect( ( select ) => {
193+
const ts = select( 'coblocks/template-selector' ) || {};
194+
const vp = select( 'core/viewport' ) || {};
195+
return {
196+
hasLayouts: typeof ts.hasLayouts === 'function' ? ts.hasLayouts() : false,
197+
hasCategories: typeof ts.hasCategories === 'function' ? ts.hasCategories() : false,
198+
selectedCategory: typeof ts.getSelectedCategory === 'function' ? ts.getSelectedCategory() : 'most-used',
199+
templateSelectorActive: typeof ts.isTemplateSelectorActive === 'function' ? ts.isTemplateSelectorActive() : false,
200+
isMobile: typeof vp.isViewportMatch === 'function' ? vp.isViewportMatch( '< medium' ) : false,
201+
hasComputedLayouts: typeof ts.getComputedLayouts === 'function' ? ( ( ts.getComputedLayouts() || [] ).length > 0 ) : false,
202+
};
203+
}, [] );
204+
205+
const tsDispatch = useDispatch( 'coblocks/template-selector' ) || {};
206+
const editorDispatch = useDispatch( 'core/editor' ) || {};
207+
const noticesDispatch = useDispatch( 'core/notices' ) || {};
208+
209+
// Non-hook logic can be conditional.
210+
const labsIsPresent = !! document.getElementsByClassName( 'coblocks-labs-modal' )?.[ 0 ];
211+
const shouldRender = layoutSelectorEnabled && ! labsIsPresent && hasLayouts && hasCategories && hasComputedLayouts;
212+
213+
if ( ! shouldRender ) {
214+
return null;
215+
}
216+
217+
const closeTemplateSelector = typeof tsDispatch.closeTemplateSelector === 'function' ? tsDispatch.closeTemplateSelector : () => {};
218+
const incrementLayoutUsage = typeof tsDispatch.incrementLayoutUsage === 'function' ? tsDispatch.incrementLayoutUsage : () => {};
219+
const updateSelectedCategory = typeof tsDispatch.updateSelectedCategory === 'function' ? tsDispatch.updateSelectedCategory : () => {};
220+
const editPost = typeof editorDispatch.editPost === 'function' ? editorDispatch.editPost : () => {};
221+
const createSuccessNotice = typeof noticesDispatch.createSuccessNotice === 'function' ? noticesDispatch.createSuccessNotice : () => {};
222+
223+
const useEmptyTemplateLayout = () => {
224+
editPost( { blocks: [], title: '' } );
225+
closeTemplateSelector();
226+
};
227+
228+
const useTemplateLayout = ( layout ) => {
229+
editPost( {
230+
blocks: layout.blocks,
231+
title: layout.label,
232+
} );
233+
closeTemplateSelector();
234+
incrementLayoutUsage( layout );
235+
createSuccessNotice(
236+
sprintf(
237+
/* translators: %s: layout name */
238+
__( '"%s" layout has been added to the page.', 'coblocks' ),
239+
layout.label
240+
),
241+
{ type: 'snackbar' }
242+
);
243+
};
244+
245+
return (
246+
<LayoutSelector
247+
categories={ categories }
248+
selectedCategory={ selectedCategory }
249+
updateSelectedCategory={ updateSelectedCategory }
250+
isActive={ templateSelectorActive }
251+
isMobile={ isMobile }
252+
useEmptyTemplateLayout={ useEmptyTemplateLayout }
253+
useTemplateLayout={ useTemplateLayout }
254+
layouts={ layouts }
255+
/>
256+
);
257+
};
258+
179259
if ( typeof coblocksLayoutSelector !== 'undefined' && coblocksLayoutSelector.postTypeEnabled ) {
180260
registerPlugin( 'coblocks-layout-selector', {
181-
render: compose( [
182-
ifCondition( () => {
183-
const [ layoutSelectorEnabled ] = useEntityProp( 'root', 'site', LAYOUT_SELECTOR_FEATURE_ENABLED_KEY );
184-
// Prevent render if labs modal is open.
185-
const labsIsPresent = !! document.getElementsByClassName( 'coblocks-labs-modal' )?.[ 0 ];
186-
const {
187-
hasLayouts,
188-
hasCategories,
189-
} = useSelect( ( select ) => select( 'coblocks/template-selector' ) );
190-
191-
return layoutSelectorEnabled && ! labsIsPresent && hasLayouts() && hasCategories();
192-
} ),
193-
withSelect( ( select ) => {
194-
const {
195-
getSelectedCategory,
196-
isTemplateSelectorActive,
197-
} = select( 'coblocks/template-selector' );
198-
199-
const { isViewportMatch } = select( 'core/viewport' );
200-
201-
const layouts = useComputedLayouts();
202-
203-
return {
204-
categories: useCategories( layouts ),
205-
isActive: isTemplateSelectorActive(),
206-
isMobile: isViewportMatch( '< medium' ),
207-
layouts,
208-
selectedCategory: getSelectedCategory(),
209-
};
210-
} ),
211-
withDispatch( ( dispatch ) => {
212-
const {
213-
closeTemplateSelector,
214-
incrementLayoutUsage,
215-
updateSelectedCategory,
216-
} = dispatch( 'coblocks/template-selector' );
217-
const { editPost } = dispatch( 'core/editor' );
218-
const { createWarningNotice, createSuccessNotice } = dispatch( 'core/notices' );
219-
220-
return {
221-
closeTemplateSelector,
222-
createSuccessNotice,
223-
createWarningNotice,
224-
editPost,
225-
updateSelectedCategory,
226-
227-
useEmptyTemplateLayout: () => {
228-
editPost( { blocks: [], title: '' } );
229-
closeTemplateSelector();
230-
},
231-
232-
// Replace any blocks with the selected layout.
233-
useTemplateLayout: ( layout ) => {
234-
editPost( {
235-
blocks: layout.blocks,
236-
title: layout.label,
237-
} );
238-
closeTemplateSelector();
239-
incrementLayoutUsage( layout );
240-
createSuccessNotice(
241-
sprintf(
242-
// translators: %s is the post title.
243-
__( '"%s" layout has been added to the page.', 'coblocks' ),
244-
layout.label
245-
),
246-
{ type: 'snackbar' }
247-
);
248-
},
249-
};
250-
} ),
251-
] )( LayoutSelector ),
261+
render: LayoutSelectorApp,
252262
} );
253263
}

src/extensions/layout-selector/index.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ function coblocks_layout_selector_layouts() {
6262
* Localize layout and category definitions for the Layout Selector component.
6363
*/
6464
function coblocks_localize_layout_selector() {
65-
$current_screen = get_current_screen();
66-
$screen_post_type = $current_screen->post_type;
65+
$current_screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
66+
$screen_post_type = ( $current_screen && isset( $current_screen->post_type ) ) ? $current_screen->post_type : null;
6767

6868
$allowed_post_types = array(
6969
'page',
@@ -73,7 +73,7 @@ function coblocks_localize_layout_selector() {
7373
'coblocks-editor',
7474
'coblocksLayoutSelector',
7575
array(
76-
'postTypeEnabled' => in_array( $screen_post_type, $allowed_post_types, true ),
76+
'postTypeEnabled' => $screen_post_type ? in_array( $screen_post_type, $allowed_post_types, true ) : false,
7777
'layouts' => coblocks_layout_selector_layouts(),
7878
'categories' => coblocks_layout_selector_categories(),
7979
)

src/extensions/layout-selector/store.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { kebabCase } from 'lodash';
99
*/
1010
import { controls } from '@wordpress/data-controls';
1111
import memoize from 'memize';
12-
import { createReduxStore, select } from '@wordpress/data';
12+
import { createReduxStore, select as dataSelect } from '@wordpress/data';
1313

1414
const DEFAULT_STATE = {
1515
categories: coblocksLayoutSelector.categories || [],
@@ -110,11 +110,19 @@ const store = createReduxStore( 'coblocks/template-selector', {
110110

111111
resolvers: {
112112
* isTemplateSelectorActive() {
113-
const isCleanNewPost = select( 'core/editor' ).isCleanNewPost();
114-
const isEditedPostEmpty = select( 'core/editor' ).isEditedPostEmpty();
113+
// Ensure the editor store is available in environments where it isn't auto-enqueued.
114+
const editorSelect = dataSelect( 'core/editor' );
115+
const isCleanNewPost = editorSelect && typeof editorSelect.isCleanNewPost === 'function'
116+
? editorSelect.isCleanNewPost()
117+
: false;
118+
const isEditedPostEmpty = editorSelect && typeof editorSelect.isEditedPostEmpty === 'function'
119+
? editorSelect.isEditedPostEmpty()
120+
: false;
115121
const shouldShowTemplateSelector = isCleanNewPost || isEditedPostEmpty;
116122

117-
return shouldShowTemplateSelector && actions.openTemplateSelector();
123+
if ( shouldShowTemplateSelector ) {
124+
yield actions.openTemplateSelector();
125+
}
118126
},
119127
},
120128
selectors: {

0 commit comments

Comments
 (0)