Version 8 to 9
This migration guide contains migration instructions for:
- eightshift/boilerplate - 8+ --> 9.0.0
- eightshift/frontend-libs - 7+ --> 8.0.0
- eightshift/libs - 6.4.0
Required changes
Migration time: ~45min to a couple of hours, depending on project size and components used.
- Update
composer
packages and check if Eightshift Libs are on version 6.4 (or higher) - Update
@eightshift/frontend-libs
in yourpackage.json
file to the latest version:"@eightshift/frontend-libs": "^8.0.0",
- Important: Delete your lockfile (
package.lock
) and yournode_modules
folder, then runnpm install
- Rename updated components, update changed properties and replace deprecated components (see chapter below)
- Do a
npm start
, check that you have no build errors visible - Smoke test your blocks - to verify everything was migrated properly, go through all the blocks and check if everything looks good visually and that everything is functional
Component updates and replacements
Below you will find some of the more common components that will need to be modified, and also some possible caveats.
Your code editor should mark the components that need replacement with a strikethrough over the component name:
Common between components
- if you have a label with an
IconLabel
inside, you can migrate it to separateicon
andlabel
props:becomeslabel={<IconLabel icon={icons.color} label={__('Background', 'domain')} />}
icon={icons.color}
label={__('Background', 'domain')} - if the component is the last in the list of options, you can add
noBottomSpacing
to make everything look a bit nicer - if you want to visually group two similar components, e.g. toggles, you can bring them vertically closer together with
reducedBottomSpacing
CollapsableComponentUseToggle
- rename the component and imports to
UseToggle
- change
showUseToggle
tonoUseToggle
and flip its logic - change
showLabel
tonoLabel
and flip its logic - change
showExpanderButton
tonoExpandButton
and flip its logic - consider adding
noExpandButton
to your attributes and add it to all your blocks, so the options render nicely
ComponentUseToggle
- replace the component with
UseToggle
- move all of the options inside the useToggle
- change
showUseToggle
tonoUseToggle
and flip its logic - change
showLabel
tonoLabel
and flip its logic
Example
Before
<ComponentUseToggle
label={label}
checked={accordionUse}
onChange={(value) => setAttributes({ [getAttrKey('accordionUse', attributes, manifest)]: value })}
showUseToggle={showAccordionUse}
showLabel={showLabel}
/>
{accordionUse &&
// Other options.
}
After:
<UseToggle
label={label}
checked={accordionUse}
onChange={(value) => setAttributes({ [getAttrKey('accordionUse', attributes, manifest)]: value })}
noUseToggle={!showAccordionUse} // Inverted logic!
noLabel={!showLabel} // Inverted logic!
noBottomSpacing // If the component is the only one in the options panel
>
// Other options.
</UseToggle>
ColorPaletteCustom
- rename the component and imports to
ColorPalette
- remove the
inline
prop if you have it added - change the
layout
prop to a string instead of aColorPaletteCustomLayout
object (hint: use autocomplete to see all the possible values) - if you have it set, change
groupShades={false}
tonoShadeGrouping
ColorPickerComponent
- rename the component and imports to
ColorPicker
- change the
type
prop to a string instead of aColorPickerType
object (hint: use autocomplete to see all the possible values) - if you have it set, change
groupShades={false}
tonoShadeGrouping
- if you have it set, replace
includeWpBottomSpacing={false}
withnoBottomSpacing
Responsive
- check and remove all breakpoint labels you had set manually, they're now automatically rendered by the component
CompactResponsive
- rename the component and imports to
Responsive
- check and remove all breakpoint labels you had set manually, they're now automatically rendered by the component
CustomSelect
- this component has been split up into 4 more specific components
- if you had a CustomSelect without
multiple
and withoptions
, replace it withSelect
- if you had a CustomSelect without
multiple
and withloadOptions
, replace it withMultiSelect
- if you had a CustomSelect with
multiple
and withoptions
, replace it withMultiSelect
- if you had a CustomSelect with
multiple
and withloadOptions
, replace it withAsyncMultiSelect
- if you had a CustomSelect without
- replace
isClearable
withclearable
if you had it set totrue
- replace
isSearchable
withnoSearch
if you had it set tofalse
, otherwise remove it - remove
reFetchOnSearch
, as it was removed - remove
multiple
(make sure you add the proper kind of Select!) - if you had an async select (with
loadOptions
), and hadsimpleValue
set, you will need to find a slightly different solution, as this is not supported anymore
LinkEditComponent
- ⚠️ props have changed here, it'll leave URL pickers broken if you forget to change them!
- replace
setAttributes
,urlAttrName
,isNewTabAttrName
(if set) with anonChange
callback (see example below) - remove
title
withlabel
if you want to keep it customized (you can also just remove it) - replace
showNewTabOption
withhideOpensInNewTab
and invert its logic - you can now hide the anchor notice with
hideAnchorNotice
Example
Before
url={buttonUrl}
<LinkEditComponent
url={buttonUrl}
opensInNewTab={buttonIsNewTab}
setAttributes={setAttributes}
title={variableLabel}
urlAttrName={getAttrKey('buttonUrl', attributes, manifest)}
isNewTabAttrName={getAttrKey('buttonIsNewTab', attributes, manifest)}
showNewTabOption={showButtonIsNewTab}
/>
After
<LinkEditComponent
url={buttonUrl}
opensInNewTab={buttonIsNewTab}
hideOpensInNewTab={!showButtonIsNewTab} // Inverted logic!
onChange={({ url, newTab, isAnchor }) => setAttributes({
[getAttrKey('buttonUrl', attributes, manifest)]: url,
[getAttrKey('buttonIsNewTab', attributes, manifest)]: newTab,
[getAttrKey('buttonIsAnchor', attributes, manifest)]: isAnchor ?? false, // Optional, can replace a manual toggle (detects setting anchor links automatically).
})}
/>
SimpleVerticalSingleSelect
- replace the component with
OptionSelector
- replace the
options
prop (one that returns an object) withvalue
,onChange
callback and availableoptions
(array)
Example
Make sure your options have at least a label
and a value
!
Before
const sizeOptions = getOption('buttonSize', attributes, manifest).map(({ label, value, icon: iconName }) => {
return {
onClick: () => setAttributes({
[getAttrKey('buttonSize', attributes, manifest)]: value,
[getAttrKey('buttonIsLink', attributes, manifest)]: false
}),
label: label,
isActive: buttonSize === value,
icon: icons[iconName],
};
});
// ...
<SimpleVerticalSingleSelect
label={<IconLabel icon={icons.size} label={__('Size', 'domain')} />}
options={sizeOptions}
/>
After
<OptionSelector
icon={icons.size}
label={__('Size', 'domain')}
options={getOption('buttonSize', attributes, manifest)}
value={buttonSize}
onChange={(value) => setAttributes({
[getAttrKey('buttonSize', attributes, manifest)]: value,
[getAttrKey('buttonIsLink', attributes, manifest)]: false
})}
/>
OptionPicker
- replace with
OptionSelector
- add
noBottomSpacing
andborder='none'
- add
additionalContainerClass='es-p-1.25'
to align it properly with other controls - remove the
label
Consider relocating your toolbar option to the options sidebar.
LinkToolbarButton
- replace with
LinkEditComponent
- follow the guide for that component for other prop replacements
- you might need to place it in a
Example
Before
<LinkToolbarButton
urlAttrName={getAttrKey('chevronUrl', attributes, manifest)}
isNewTabAttrName={getAttrKey('chevronIsNewTab', attributes, manifest)}
url={chevronUrl}
opensInNewTab={chevronIsNewTab}
setAttributes={setAttributes}
title={__(ucfirst(componentName), 'domain')}
/>
After
import { ToolbarButton, ToolbarItem, } from '@wordpress/components';
import { PopoverWithTrigger } from '@eightshift/frontend-libs/scripts';
// ...
<ToolbarItem as='div'>
<PopoverWithTrigger
position='top right'
contentClass='es-w-80 es-p-4'
trigger={
({ ref, setIsOpen, isOpen }) => (
<ToolbarButton
ref={ref}
onClick={() => setIsOpen(!isOpen)}
isPressed={chevronUrl?.length > 0}
icon={icons.link}
/>
)
}
>
<LinkEditComponent
url={chevronUrl}
opensInNewTab={chevronIsNewTab}
onChange={({ url, newTab }) => setAttributes({
[getAttrKey('chevronUrl', attributes, manifest)]: url,
[getAttrKey('chevronIsNewTab', attributes, manifest)]: newTab,
})}
hideOpensInNewTab
noBottomSpacing
/>
</PopoverWithTrigger>
</ToolbarItem>
InlineNotification
- rename the component and imports to
Notification
- change the
type
prop to a string instead of aInlineNotificationType
object (hint: use autocomplete to see all the possible values) - replace
removeBottomFieldSpacing
withnoBottomSpacing
, if set - remove
showContrastOutline
as it's not supported anymore
SpacingSlider
- replace with
ResponsiveSlider
with the config generator - remove deprecated props
- if you had
compensateForRemBase10
, addmodifyInput={(v) => v * 10}
modifyOutput={(v) => v / 10}
Example
Before
<SpacingSlider
icon={icons.order}
label={__('Order', 'domain')}
attributeName='columnOrder'
attributes={attributes}
setAttributes={setAttributes}
manifest={manifest}
markSteps={2}
hasInputField={false}
hasValueDisplay
valueDisplayFormat={(v) => !isNaN(v) && v > 0 ? v : '-'}
showDisableButton
disableWithUndefined
isNumeric
/>
After
<ResponsiveSlider
{...generateResponsiveSliderConfig({
attributeName: 'columnOrder',
attributes: attributes,
manifest: manifest,
setAttributes: setAttributes,
})}
icon={icons.order}
label={__('Order', 'domain')}
/>
WidthOffsetRangeSlider
- wrap some of the deprecated options with a config generator
Example
Before
<WidthOffsetRangeSlider
offsetAttributeName='columnOffset'
widthAttributeName='columnWidth'
manifest={manifest}
attributes={attributes}
setAttributes={setAttributes}
showFullWidthToggle={false}
includeGutters
showOffsetAutoToggle
/>
After
<WidthOffsetRangeSlider
{...generateWidthOffsetRangeSliderConfig({
offsetAttributeName: 'columnOffset',
widthAttributeName: 'columnWidth',
attributes: attributes,
manifest: manifest,
setAttributes: (attr) => {
// This is only required if you have "Auto" offset as an option, and the attributes are numeric, otherwise just pass setAttributes as-is.
const newAttr = {};
Object.entries(attr).forEach(([key, value]) => {
if (value !== 'auto' && typeof value !== 'undefined') {
newAttr[key] = parseInt(value);
return;
}
newAttr[key] = value;
});
setAttributes(newAttr);
},
numOfColumns: 14,
showOffsetAutoToggle: true,
numericValues: true,
showFullWidth: false,
})}
/>
VisibilityToggleResponsive
- replace with
ResponsiveToggleButton
and use the config generator
Example
Before
<VisibilityToggleResponsive
attributeName='columnHide'
label={__('Visibility', 'redesign')}
manifest={manifest}
attributes={attributes}
setAttributes={setAttributes}
/>
After
<ResponsiveToggleButton
{...generateResponsiveToggleButtonConfig({
attributeName: 'columnHide',
manifest: manifest,
attributes: attributes,
setAttributes: setAttributes,
})}
label={__('Hide', 'domain')}
icon={icons.hide}
/>
SimpleHorizontalSingleSelect
- rename the component and imports to
OptionSelector
- remove
border='offset'
if set, that's now the default - replace
includeWpBottomSpacing={false}
withnoBottomSpacing
AlignmentToolbar
- replace with
OptionSelector
- add
optionLabels
to transform just values into{label, value}
(or{label, value, icon}
) entries - add
noBottomSpacing
,additionalContainerClass='es-p-1.25'
, andborder='none'
so it fits the toolbar better - remove
label
andtype
Example
Before
<AlignmentToolbar
value={cardAlign}
options={getOption('cardAlign', attributes, manifest)}
label={sprintf(__('%s content align', 'domain'), manifestTitle)}
onChange={(value) => setAttributes({ [getAttrKey('cardAlign', attributes, manifest)]: value })}
type={AlignmentToolbarType.HORIZONTAL}
/>
After
<OptionSelector
value={cardAlign}
options={getOption('cardAlign', attributes, manifest)}
onChange={(value) => setAttributes({ [getAttrKey('cardAlign', attributes, manifest)]: value })}
optionLabels={getOption('cardAlign', attributes, manifest).map((v) => ({ label: ucfirst(v), icon: icons[`textAlign${ucfirst(v)}`] }))}
additionalContainerClass='es-p-1.25'
noBottomSpacing
border='none'
iconOnly
/>
HeadingLevel
- replace with
OptionSelector
- change
selectedLevel
tovalue
- add
noBottomSpacing
,additionalContainerClass='es-p-1.25'
, andborder='none'
so it fits the toolbar better - add
options
with all the available heading level options (see After in the example below) - if you want the options to look a bit better, you can add
additionalButtonClass
, just like in the After example below
Example
Before
<HeadingLevel
selectedLevel={typographyLevel}
onChange={(value) => setAttributes({ [getAttrKey('typographyLevel', attributes, manifest)]: value })}
/>
After
<OptionSelector
value={typographyLevel}
onChange={(value) => setAttributes({ [getAttrKey('typographyLevel', attributes, manifest)]: value })}
additionalContainerClass='es-p-1.25'
noBottomSpacing
border='none'
options={[
{ label: 'H1', tooltip: __('Heading 1', 'domain'), value: 1 },
{ label: 'H2', tooltip: __('Heading 2', 'domain'), value: 2 },
{ label: 'H3', tooltip: __('Heading 3', 'domain'), value: 3 },
{ label: 'H4', tooltip: __('Heading 4', 'domain'), value: 4 },
{ label: 'H5', tooltip: __('Heading 5', 'domain'), value: 5 },
{ label: 'H6', tooltip: __('Heading 6', 'domain'), value: 6 },
]}
additionalButtonClass='es-button-square-36 es-text-4 es-font-weight-300'
/>
CustomSlider
- rename the component and imports to
OptionSelector
- you might want to remove
marks
if not very specific, as an auto-generator for marks is now included
SimpleRepeater
/ SimpleRepeaterItem
- rename the component and imports to
Repeater
/RepeaterItem