diff --git a/.github/workflows/test-php.yml b/.github/workflows/test-php.yml index 7c0ea6282f..c6913e8349 100644 --- a/.github/workflows/test-php.yml +++ b/.github/workflows/test-php.yml @@ -111,4 +111,5 @@ jobs: - name: PHPStan Static Analysis uses: php-actions/phpstan@v2 with: + version: 0.12.99 memory_limit: 512M diff --git a/CHANGELOG.md b/CHANGELOG.md index 68a614d2f3..432248cd75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +##### [Version 3.0.11](https://github.com/Codeinwp/neve/compare/v3.0.10...v3.0.11) (2021-11-10) + +- [Feat] Add the possibility to replace WooCommerce Breadcrumbs with the ones from Yoast, SeoPress Pro, or RankMath - [Learn more](https://docs.themeisle.com/article/1123-breadcrumbs-in-neve#woo) +- [Fix] Infinite scroll not working in some specific context +- [Fix] Compatibility of palette switcher with Elementor global colors +- [Fix] Archive featured image as background works only with all taxonomies enabled +- [Fix] Post title alignment +- [Fix] Repeater control adding unused values to the database & causing customizer to load in publishing state +- [Fix] Edge case of footer columns not having a proper corresponding layout +- [Fix] Bug affecting the container size and elements style +- [Fix] Compatibility with Cartflows plugin +- [Fix] HTML Component's TinyMCE new lines for existing content and Safari support +- [Fix] Bring back custom font size field inside the WordPress editor +- [Fix] Removed previously added values for font-size presets inside the editor +- [Fix] Removed redundant border controls for mobile header sidebar +- [Fix] Ordering control with blank elements +- [Fix] Double scrollbar appearing in some customizer sections +- [Fix] Inconsistent console error inside the customizer preview +- Update Google Fonts + ##### [Version 3.0.10](https://github.com/Codeinwp/neve/compare/v3.0.9...v3.0.10) (2021-10-27) - [Fix] header rows background images not applying on legacy skin diff --git a/assets/apps/customizer-controls/src/ordering/Ordering.js b/assets/apps/customizer-controls/src/ordering/Ordering.js index ffc0b146a7..9f0b2fcf37 100644 --- a/assets/apps/customizer-controls/src/ordering/Ordering.js +++ b/assets/apps/customizer-controls/src/ordering/Ordering.js @@ -88,6 +88,10 @@ const Ordering = ({ onUpdate(updatedValue); }; + value = value.filter((element) => { + return components.hasOwnProperty(element.id); + }); + return ( <> {label /* TODO: Add proper label id for this */ && ( @@ -101,15 +105,19 @@ const Ordering = ({ animation={300} handle=".handle" > - {value.map((item, index) => ( - - ))} + {value + .filter((element) => { + return components.hasOwnProperty(element.id); + }) + .map((item, index) => ( + + ))} ); diff --git a/assets/apps/customizer-controls/src/ordering/OrderingComponent.js b/assets/apps/customizer-controls/src/ordering/OrderingComponent.js index 9f010d97f7..f5a4dc47e6 100644 --- a/assets/apps/customizer-controls/src/ordering/OrderingComponent.js +++ b/assets/apps/customizer-controls/src/ordering/OrderingComponent.js @@ -4,7 +4,9 @@ import { Spinner } from '@wordpress/components'; import { maybeParseJson } from '../common/common'; import PropTypes from 'prop-types'; -const Ordering = lazy(() => import('./Ordering')); +const Ordering = lazy(() => + import(/* webpackChunkName: "order" */ './Ordering') +); import { __ } from '@wordpress/i18n'; const OrderingComponent = ({ control }) => { diff --git a/assets/apps/customizer-controls/src/repeater/Repeater.js b/assets/apps/customizer-controls/src/repeater/Repeater.js index e9de325ecf..29970b0fa1 100644 --- a/assets/apps/customizer-controls/src/repeater/Repeater.js +++ b/assets/apps/customizer-controls/src/repeater/Repeater.js @@ -54,12 +54,26 @@ const Repeater = ({ fields, value, onUpdate }) => { onUpdate(newValue); }; + const setList = (l) => { + const final = l.map((i) => { + Object.keys(i).forEach((k) => { + if (![...Object.keys(fields), 'visibility'].includes(k)) { + delete i[k]; + } + }); + return i; + }); + + onUpdate(final); + return final; + }; + return (
{ + const textArea = useRef(null); + const useDynamicFields = Boolean( + Array.isArray(allowedDynamicFields) && allowedDynamicFields.length + ); + const toolbarOneDefaults = + 'formatselect,bold,italic,bullist,numlist,link,wp_adv'; + const toolbarTwoDefaults = + 'strikethrough,hr,forecolor,pastetext,removeformat'; + const { + toolbar1 = toolbarOneDefaults, + toolbar2 = toolbarTwoDefaults, + } = toolbars; + const editorId = `${id}-editor`; + NeveReactCustomize.fieldSelection = {}; + + /** + * Get the editor to be used based on the available version that WP loads. + */ + const correctEditor = wp.oldEditor || wp.editor; + + /** + * A listener to trigger the update state on change. + */ + const listener = useCallback( + () => onChange(correctEditor.getContent(editorId)), + [editorId] + ); + + /** + * Method to add a change listener for the current editor. + */ + const addEditorChangeListener = () => { + if (window.tinymce.editors[editorId]) { + window.tinymce.editors[editorId].on('change', listener); + } + }; + + /** + * Method to remove a change listener for the current editor. + */ + const removeEditorChangeListener = () => { + if (window.tinymce.editors[editorId]) { + window.tinymce.editors[editorId].off('change', listener); + } + }; + + /** + * Initialise the editor. + */ + const initEditor = () => { + correctEditor.initialize(editorId, { + quicktags: true, + mediaButtons: true, + + tinymce: { + toolbar1, + toolbar2, + style_formats_merge: true, + style_formats: [], + }, + }); + + setTimeout(addEditorChangeListener, 0); + + if (wp.oldEditor) { + setTimeout(() => { + removeEditorChangeListener(); + + correctEditor.remove(editorId); + + correctEditor.initialize(editorId, { + quicktags: true, + mediaButtons: true, + + tinymce: { + toolbar1, + toolbar2, + style_formats_merge: true, + style_formats: [], + }, + }); + + setTimeout(addEditorChangeListener, 0); + }, 300); + } + }; + + /** + * Method to update the editor content and state. + * + * @param {string} content The new content. + */ + const setEditorContent = (content) => { + onChange(content); + window.tinymce.editors[editorId].setContent(content); + }; + + /** + * Add dynamic tag to input field. + * + * @param {string} magicTag + * @param {string} optionType + */ + const addToField = function (magicTag, optionType) { + let tag; + const codeEditor = textArea.current; + const isVisualEditor = !window.tinymce.editors[editorId].hidden; + + if (optionType === 'url') { + tag = `Link`; + } else { + tag = `{${magicTag}}`; + } + + if (isVisualEditor) { + window.tinymce.editors[editorId].editorCommands.execCommand( + 'mceInsertContent', + false, + tag + ); + window.tinymce.editors[editorId].focus(); + } else { + if (NeveReactCustomize.fieldSelection[id]) { + const { start, end } = NeveReactCustomize.fieldSelection[id]; + const length = codeEditor.value.length; + codeEditor.value = + codeEditor.value.substring(0, start) + + tag + + codeEditor.value.substring(end, length); + } else { + codeEditor.value += tag; + } + codeEditor.focus(); + } + codeEditor.dispatchEvent(new Event('change')); + }; + + const controlWrapperStyle = { + position: 'relative', + }; + const dynamicFieldStyle = { + position: 'absolute', + top: 0, + right: '8px', + }; + + const textAreaStyle = { + width: '100%', + }; + + useEffect(() => { + // We also hook here to listen for changes of the dynamic settings change to also trigger the editor content update. + if (textArea && textArea.current) { + textArea.current.addEventListener('change', () => { + setEditorContent(textArea.current.value); + }); + + textArea.current.addEventListener('focusout', function (e) { + NeveReactCustomize.fieldSelection[id] = { + start: e.target.selectionStart, + end: e.target.selectionEnd, + }; + }); + } + initEditor(); + }, []); + + // Re-init text editor content on conditional changes. + useEffect(() => { + document.addEventListener('neve-changed-customizer-value', (e) => { + if (!e.detail) return false; + if (e.detail.id !== id) return false; + setEditorContent(e.detail.value); + }); + }, []); -const RichText = ({ onChange, currentValue, label, id, editorId }) => { return ( -
+
{label} + {useDynamicFields && ( + + + addToField(magicTag, group) + } + /> + + )}