diff --git a/.wp-env.json b/.wp-env.json index 3abbf56333..8f3fa899c1 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -21,6 +21,7 @@ ".htaccess": "./tests/cypress/wordpress-files/.htaccess", "wp-content/mu-plugins/skip-wp-lookup.php": "./tests/cypress/wordpress-files/test-mu-plugins/skip-wp-lookup.php", "wp-content/mu-plugins/unique-index-name.php": "./tests/cypress/wordpress-files/test-mu-plugins/unique-index-name.php", + "wp-content/plugins/auto-meta-mode.php": "./tests/cypress/wordpress-files/test-plugins/auto-meta-mode.php", "wp-content/mu-plugins/disable-welcome-guide.php": "./tests/cypress/wordpress-files/test-mu-plugins/disable-welcome-guide.php", "wp-content/plugins/cpt-and-custom-tax.php": "./tests/cypress/wordpress-files/test-plugins/cpt-and-custom-tax.php", "wp-content/plugins/custom-instant-results-template.php": "./tests/cypress/wordpress-files/test-plugins/custom-instant-results-template.php", diff --git a/assets/css/dashboard.css b/assets/css/dashboard.css index 1264207443..329f3a7c75 100644 --- a/assets/css/dashboard.css +++ b/assets/css/dashboard.css @@ -665,180 +665,6 @@ h2.ep-list-features { color: #d84440; } -/** - * Weighting - */ - -.weighting-settings .postbox { - box-sizing: border-box; - max-width: 650px; - - & * { - box-sizing: border-box; - } -} - -.weighting-settings .postbox h2.hndle { - color: #444; - cursor: inherit; -} - -.weighting-settings fieldset { - padding: 10px; -} - -.weighting-settings fieldset legend { - float: left; /* legend cannot use display */ - position: relative; - top: 5px; - width: 100px; -} - -.weighting-settings fieldset p { - display: inline-block; - float: left; - margin: 0; -} - -.weighting-settings .field-group { - margin: 10px 0 0; -} - -.weighting-settings .field-group h3 { - font-size: 1em; - margin: 10px; -} - -.weighting-settings .fields > fieldset:nth-of-type(odd) { - background: #f9f9f9; -} - -.weighting-settings .searchable { - display: inline-block; - width: 120px; -} - -.weighting-settings .weighting { - align-items: center; - display: flex; -} - -.weighting-settings .weighting label { - margin-right: 10px; - min-width: 80px; -} - -.weighting-settings input[type="range"] { - -webkit-appearance: none; - background: transparent; - display: inline-block; - height: 1em; - margin: 0; - vertical-align: middle; - width: 200px; -} - -.weighting-settings input[type="range"]:focus { - outline: none; -} - -.weighting-settings input[type="range"]:disabled { - opacity: 0.5; - pointer-events: none; -} - -.weighting-settings input[type="range"]::-webkit-slider-runnable-track { - background: #ddd; - border: 0 solid #000; - border-radius: 1px; - box-shadow: 0 0 0 #000; - cursor: pointer; - height: 3px; - width: 100%; -} - -.weighting-settings input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - background: #1e8cbe; - border: 1px solid #1e8cbe; - border-radius: 25px; - box-shadow: 0 0 0 #000; - cursor: pointer; - height: 14px; - margin-top: -6px; - width: 14px; -} - -.weighting-settings input[type="range"]:focus::-webkit-slider-runnable-track { - background: #ddd; -} - -.weighting-settings input[type="range"]:focus::-webkit-slider-thumb { - background: #fff !important; -} - -.weighting-settings input[type="range"]::-moz-range-track { - background: #1e8cbe; - border: 0 solid #000; - border-radius: 1px; - box-shadow: 0 0 0 #000; - cursor: pointer; - height: 3px; - width: 100%; -} - -.weighting-settings input[type="range"]::-moz-range-thumb { - background: #1e8cbe; - border: 1px solid #1e8cbe; - border-radius: 25px; - box-shadow: 0 0 0 #000; - cursor: pointer; - height: 14px; - width: 14px; -} - -.weighting-settings input[type="range"]::-ms-track { - background: transparent; - border-color: transparent; - color: transparent; - cursor: pointer; - height: 3px; - width: 100%; -} - -.weighting-settings input[type="range"]::-ms-fill-lower { - background: #1e8cbe; - border: 0 solid #000; - border-radius: 2px; - box-shadow: 0 0 0 #000; -} - -.weighting-settings input[type="range"]::-ms-fill-upper { - background: #1e8cbe; - border: 0 solid #000; - border-radius: 2px; - box-shadow: 0 0 0 #000; -} - -.weighting-settings input[type="range"]::-ms-thumb { - background: #a1d0ff; - border: 1px solid #1e8cbe; - border-radius: 25px; - box-shadow: 0 0 0 #000; - cursor: pointer; - height: 14px; - margin-top: 1px; - width: 14px; -} - -.weighting-settings input[type="range"]:focus::-ms-fill-lower { - background: #1e8cbe; -} - -.weighting-settings input[type="range"]:focus::-ms-fill-upper { - background: #1e8cbe; -} - .ep-feature-search .wp-color-result.button { margin-bottom: 10px; } diff --git a/assets/js/weighting/apps/weighting.js b/assets/js/weighting/apps/weighting.js new file mode 100644 index 0000000000..000e55d372 --- /dev/null +++ b/assets/js/weighting/apps/weighting.js @@ -0,0 +1,64 @@ +/** + * WordPress dependencies. + */ +import { Button } from '@wordpress/components'; +import { WPElement } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal Dependencies. + */ +import { useSettingsScreen } from '../../settings-screen'; +import PostType from '../components/post-type'; +import { useWeightingSettings } from '../provider'; + +/** + * Weighting settings app. + * + * @returns {WPElement} Element. + */ +export default () => { + const { createNotice } = useSettingsScreen(); + const { isBusy, save, weightableFields } = useWeightingSettings(); + + /** + * Submit event. + * + * @param {Event} event Submit event. + */ + const onSubmit = async (event) => { + event.preventDefault(); + + try { + await save(); + createNotice('success', __('Settings saved.', 'elasticpress')); + } catch (e) { + createNotice('error', __('Something went wrong. Please try again.', 'elasticpress')); + } + }; + + return ( + <> +

+ {__( + 'This dashboard enables you to select which fields ElasticPress should sync, whether to use those fields in searches, and how heavily to weight fields in the search algorithm. In general, increasing the Weight of a field will increase the relevancy score of a post that has matching text in that field.', + 'elasticpress', + )} +

+

+ {__( + 'For example, adding more weight to the title attribute will cause search matches on the post title to appear more prominently.', + 'elasticpress', + )} +

+
+ {weightableFields.map(({ key }) => { + return ; + })} + + + + ); +}; diff --git a/assets/js/weighting/components/field.js b/assets/js/weighting/components/field.js new file mode 100644 index 0000000000..8477456aa9 --- /dev/null +++ b/assets/js/weighting/components/field.js @@ -0,0 +1,78 @@ +/** + * WordPress Dependencies. + */ +import { Button, CheckboxControl, RangeControl } from '@wordpress/components'; +import { WPElement } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { trash } from '@wordpress/icons'; + +/** + * Field settings component. + * + * @param {object} props Component props. + * @param {string} props.label Property label. + * @param {Function} props.onChange Change handler. + * @param {Function} props.onDelete Delete handler. + * @param {object} props.value Values. + * @returns {WPElement} Component element. + */ +export default ({ label, onChange, onDelete, value }) => { + const { enabled = false, weight = 0 } = value; + + /** + * Handle change of searchable. + * + * @param {boolean} enabled New searchable value. + * @returns {void} + */ + const onChangeSearchable = (enabled) => { + onChange({ weight, enabled }); + }; + + /** + * Handle change of weighting. + * + * @param {number} weight New weight value. + * @returns {void} + */ + const onChangeWeight = (weight) => { + onChange({ enabled: true, weight }); + }; + + /** + * Render. + */ + return ( +
+
+ {label} +
+ +
+
+ +
+
+
+
+
+ ); +}; diff --git a/assets/js/weighting/components/group.js b/assets/js/weighting/components/group.js new file mode 100644 index 0000000000..8334a7681a --- /dev/null +++ b/assets/js/weighting/components/group.js @@ -0,0 +1,193 @@ +/** + * WordPress dependencies. + */ +import { Button, PanelRow, TextControl } from '@wordpress/components'; +import { useMemo, useState, WPElement } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Internal dependencies. + */ +import { useSettingsScreen } from '../../settings-screen'; +import { useWeightingSettings } from '../provider'; +import Field from './field'; + +/** + * Post type propertes component. + * + * @param {object} props Component props. + * @param {string} props.group Group. + * @param {string} props.postType Post type. + * @returns {WPElement} Component element. + */ +export default ({ group, postType }) => { + const { createNotice } = useSettingsScreen(); + const { currentWeightingConfiguration, setWeightingForPostType, weightableFields } = + useWeightingSettings(); + + /** + * State. + */ + const [toAdd, setToAdd] = useState(''); + + /** + * Saved weighting values for this group's post type. + */ + const values = currentWeightingConfiguration[postType]; + const { fields } = weightableFields.find((w) => w.key === postType); + + /** + * Whether this is the Metadata group. + */ + const isMetadata = group === 'ep_metadata'; + + /** + * Fields that belond to this group. + */ + const defaultFields = useMemo(() => fields.filter((f) => f.group === group), [fields, group]); + + /** + * Custom fields. + * + * These are meta fields that have a saved weighting value but are not + * included in the list of weightable fields. This will be fields that + * were added manually using the UI. + */ + const customFields = useMemo(() => { + if (!isMetadata) { + return []; + } + + const fieldKeys = fields.map(({ key }) => key); + + const customFields = Object.keys(values).reduce((customFields, key) => { + if (fieldKeys.includes(key)) { + return customFields; + } + + const matches = key.match(/meta\.(?