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',
+ )}
+
+
+ >
+ );
+};
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\.(?.*)\.value/);
+
+ if (!matches) {
+ return customFields;
+ }
+
+ const { label } = matches.groups;
+
+ customFields.push({
+ key,
+ label,
+ });
+
+ return customFields;
+ }, []);
+
+ return customFields;
+ }, [fields, isMetadata, values]);
+
+ /**
+ * Handle changes to a property.
+ *
+ * @param {object} value New property data.
+ * @param {number} key Property key.
+ * @returns {void}
+ */
+ const onChange = (value, key) => {
+ setWeightingForPostType(postType, { ...values, [key]: value });
+ };
+
+ /**
+ * Handle clicking to add a new property.
+ *
+ * @returns {void}
+ */
+ const onClick = () => {
+ const key = `meta.${toAdd}.value`;
+
+ const isDefaultField = defaultFields.some((f) => f.key === key);
+ const isCustomField = customFields.some((f) => f.key === key);
+
+ if (isDefaultField || isCustomField) {
+ createNotice('info', sprintf(__('%s is already being synced.', 'elasticpress'), toAdd));
+ return;
+ }
+
+ const newValues = { ...values, [key]: { enabled: false, weight: 0 } };
+
+ setWeightingForPostType(postType, newValues);
+ setToAdd('');
+ };
+
+ /**
+ * Handle removing a field.
+ *
+ * @param {number} key field key.
+ * @returns {void}
+ */
+ const onDelete = (key) => {
+ const newValues = { ...values };
+
+ delete newValues[key];
+
+ setWeightingForPostType(postType, newValues);
+ };
+
+ /**
+ * Handle pressing Enter key when adding a field.
+ *
+ * @param {Event} event Keydown event.
+ */
+ const onKeyDown = (event) => {
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ onClick();
+ }
+ };
+
+ return (
+ <>
+ {defaultFields.map(({ key, label }) => (
+
+ {
+ onChange(value, key);
+ }}
+ />
+
+ ))}
+ {customFields.map(({ key, label }) => (
+
+ {
+ onChange(value, key);
+ }}
+ onDelete={() => {
+ onDelete(key);
+ }}
+ />
+
+ ))}
+ {isMetadata ? (
+
+ setToAdd(toAdd)}
+ onKeyDown={onKeyDown}
+ placeholder={__('Metadata key', 'elasticpress')}
+ value={toAdd}
+ />
+
+ {__('Add', 'elasticpress')}
+
+
+ ) : null}
+ >
+ );
+};
diff --git a/assets/js/weighting/components/post-type.js b/assets/js/weighting/components/post-type.js
new file mode 100644
index 0000000000..a5af21f6a1
--- /dev/null
+++ b/assets/js/weighting/components/post-type.js
@@ -0,0 +1,44 @@
+/**
+ * WordPress dependencies.
+ */
+import { Panel, PanelBody, PanelHeader } from '@wordpress/components';
+import { WPElement } from '@wordpress/element';
+
+/**
+ * Internal dependencies.
+ */
+import { useWeightingSettings } from '../provider';
+import Group from './group';
+
+/**
+ * Post type weighting settings component.
+ *
+ * @param {object} props Components props.
+ * @param {object[]} props.postType Post type.
+ * @returns {WPElement} Component element.
+ */
+export default ({ postType }) => {
+ const { isManual, weightableFields } = useWeightingSettings();
+
+ const { label, groups } = weightableFields.find((f) => f.key === postType);
+
+ /**
+ * Render.
+ */
+ return (
+
+
+ {label}
+
+ {groups.map(({ key, label }) => {
+ const isMetadata = key === 'ep_metadata';
+
+ return !isMetadata || isManual ? (
+
+
+
+ ) : null;
+ })}
+
+ );
+};
diff --git a/assets/js/weighting/config.js b/assets/js/weighting/config.js
new file mode 100644
index 0000000000..5ee2464a03
--- /dev/null
+++ b/assets/js/weighting/config.js
@@ -0,0 +1,3 @@
+const { apiUrl, metaMode, syncUrl, weightableFields, weightingConfiguration } = window.epWeighting;
+
+export { apiUrl, metaMode, syncUrl, weightableFields, weightingConfiguration };
diff --git a/assets/js/weighting/css/action.css b/assets/js/weighting/css/action.css
new file mode 100644
index 0000000000..ba2084222e
--- /dev/null
+++ b/assets/js/weighting/css/action.css
@@ -0,0 +1,6 @@
+.ep-weighting-action {
+
+ &[disabled] {
+ visibility: hidden;
+ }
+}
diff --git a/assets/js/weighting/css/add-new.css b/assets/js/weighting/css/add-new.css
new file mode 100644
index 0000000000..68d468c376
--- /dev/null
+++ b/assets/js/weighting/css/add-new.css
@@ -0,0 +1,16 @@
+.ep-weighting-add-new {
+ align-items: start;
+ gap: 4px;
+ justify-content: start;
+ margin-top: 16px;
+ max-width: 100%;
+ width: 50ch;
+
+ & .components-base-control .components-text-control__input {
+ min-height: 36px;
+ }
+
+ & .components-button {
+ margin-top: calc(1.4 * 11px + 8px);
+ }
+}
diff --git a/assets/js/weighting/css/field.css b/assets/js/weighting/css/field.css
new file mode 100644
index 0000000000..3d6d208436
--- /dev/null
+++ b/assets/js/weighting/css/field.css
@@ -0,0 +1,66 @@
+.ep-weighting-field {
+ align-items: center;
+ display: grid;
+ grid-gap: 1em;
+ grid-template-columns: min(20%, 30ch) max-content auto max-content;
+ width: 100%;
+
+ & .components-base-control__field {
+ margin-bottom: 0;
+ }
+
+ & .components-checkbox-control {
+
+ & .components-base-control__field {
+ align-items: center;
+ display: flex;
+ }
+ }
+
+ & .components-range-control {
+
+ & .components-base-control__field {
+ align-items: center;
+ display: flex;
+ }
+
+ & .components-base-control__label {
+ font-size: inherit;
+ font-weight: inherit;
+ margin-bottom: 0;
+ text-transform: inherit;
+ }
+ }
+
+ @media ( max-width: 600px ) {
+ grid-template-columns: 1fr 1fr 1fr max-content;
+
+ & .ep-weighting-field__weighting {
+ display: flex;
+ justify-content: end;
+
+ & .components-range-control__wrapper {
+ display: none;
+ }
+ }
+ }
+}
+
+.ep-weighting-field fieldset {
+ display: contents;
+}
+
+.ep-weighting-field__name {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ & h2 {
+ font-size: 1rem;
+ }
+}
+
+.ep-weighting-field__undo {
+ grid-column-start: 4;
+ justify-self: end;
+}
diff --git a/assets/js/weighting/css/post-type.css b/assets/js/weighting/css/post-type.css
new file mode 100644
index 0000000000..0b765587aa
--- /dev/null
+++ b/assets/js/weighting/css/post-type.css
@@ -0,0 +1,28 @@
+.ep-weighting-post-type {
+ margin-bottom: 16px;
+
+ & .components-panel__header h2 {
+ font-size: 14px;
+ }
+
+ & .components-toggle-control__label {
+ max-width: none;
+ }
+
+ & .components-base-control__help {
+ margin-bottom: 0;
+ }
+
+ & .components-notice {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ & .components-notice__dismiss {
+ align-self: center;
+ }
+
+ & .components-button {
+ vertical-align: top;
+ }
+}
diff --git a/assets/js/weighting/index.js b/assets/js/weighting/index.js
new file mode 100644
index 0000000000..869332d50d
--- /dev/null
+++ b/assets/js/weighting/index.js
@@ -0,0 +1,45 @@
+/**
+ * WordPress dependencies.
+ */
+import { createRoot, render, WPElement } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal Dependencies.
+ */
+import { SettingsScreenProvider } from '../settings-screen';
+import { apiUrl, metaMode, syncUrl, weightableFields, weightingConfiguration } from './config';
+import { WeightingSettingsProvider } from './provider';
+import Weighting from './apps/weighting';
+
+/**
+ * Styles.
+ */
+import './style.css';
+
+/**
+ * App component.
+ *
+ * @returns {WPElement} App component.
+ */
+const App = () => (
+
+
+
+
+
+);
+
+if (typeof createRoot === 'function') {
+ const root = createRoot(document.getElementById('ep-weighting-screen'));
+
+ root.render( );
+} else {
+ render( , document.getElementById('ep-weighting-screen'));
+}
diff --git a/assets/js/weighting/provider.js b/assets/js/weighting/provider.js
new file mode 100644
index 0000000000..8fb37f2473
--- /dev/null
+++ b/assets/js/weighting/provider.js
@@ -0,0 +1,103 @@
+/**
+ * WordPress dependencies.
+ */
+import apiFetch from '@wordpress/api-fetch';
+import { createContext, WPElement, useContext, useMemo, useState } from '@wordpress/element';
+
+/**
+ * Instant Results context.
+ */
+const Context = createContext();
+
+/**
+ * Weighting settings app.
+ *
+ * @param {object} props Component props.
+ * @param {string} props.apiUrl API URL.
+ * @param {Function} props.children Component children.
+ * @param {'auto'|'manual'} props.metaMode Metadata management mode.
+ * @param {object} props.weightableFields Weightable fields, indexed by post type.
+ * @param {object} props.weightingConfiguration Weighting configuration, indexed by post type.
+ * @returns {WPElement} Element.
+ */
+export const WeightingSettingsProvider = ({
+ apiUrl,
+ children,
+ metaMode,
+ weightableFields,
+ weightingConfiguration,
+}) => {
+ const [currentWeightingConfiguration, setCurrentWeightingConfiguration] = useState({
+ ...weightingConfiguration,
+ });
+
+ const [isBusy, setIsBusy] = useState(false);
+
+ /**
+ * Whether to show weighting for metadata.
+ */
+ const isManual = useMemo(() => metaMode === 'manual', [metaMode]);
+
+ /**
+ * Handle data change.
+ *
+ * @param {string} postType Post type to update.
+ * @param {Array} values New valus.
+ * @returns {void}
+ */
+ const setWeightingForPostType = (postType, values) => {
+ setCurrentWeightingConfiguration({
+ ...currentWeightingConfiguration,
+ [postType]: values,
+ });
+ };
+
+ /**
+ * Save settings.
+ *
+ * @returns {void}
+ */
+ const save = async () => {
+ setIsBusy(true);
+
+ try {
+ await apiFetch({
+ body: JSON.stringify(currentWeightingConfiguration),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ method: 'POST',
+ url: apiUrl,
+ });
+ } catch (e) {
+ console.error(e); // eslint-disable-line no-console
+ throw e;
+ } finally {
+ setIsBusy(false);
+ }
+ };
+
+ // eslint-disable-next-line react/jsx-no-constructed-context-values
+ const contextValue = {
+ currentWeightingConfiguration,
+ isBusy,
+ isManual,
+ save,
+ setWeightingForPostType,
+ weightableFields,
+ };
+
+ /**
+ * Render.
+ */
+ return {children} ;
+};
+
+/**
+ * Use the API Search context.
+ *
+ * @returns {object} API Search Context.
+ */
+export const useWeightingSettings = () => {
+ return useContext(Context);
+};
diff --git a/assets/js/weighting/style.css b/assets/js/weighting/style.css
new file mode 100644
index 0000000000..8ab58bb81c
--- /dev/null
+++ b/assets/js/weighting/style.css
@@ -0,0 +1,4 @@
+@import "./css/action.css";
+@import "./css/add-new.css";
+@import "./css/field.css";
+@import "./css/post-type.css";
diff --git a/includes/classes/Feature/Search/Search.php b/includes/classes/Feature/Search/Search.php
index c43781077e..415d5b6df9 100644
--- a/includes/classes/Feature/Search/Search.php
+++ b/includes/classes/Feature/Search/Search.php
@@ -107,6 +107,7 @@ public function search_setup() {
add_action( 'ep_highlighting_pre_add_highlight', [ $this, 'allow_excerpt_html' ] );
add_action( 'init', [ $this, 'register_meta' ], 20 );
+ add_filter( 'ep_prepare_meta_allowed_keys', [ $this, 'add_exclude_from_search' ] );
add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_assets' ] );
add_filter( 'ep_post_filters', [ $this, 'exclude_posts_from_search' ], 10, 3 );
add_action( 'post_submitbox_misc_actions', [ $this, 'output_exclude_from_search_setting' ] );
@@ -688,6 +689,18 @@ public function register_meta() {
);
}
+ /**
+ * Add ep_exclude_from_search to the allowed meta fields list.
+ *
+ * @since 5.0.0
+ * @param array $keys List of allowed meta fields
+ * @return array
+ */
+ public function add_exclude_from_search( $keys ) {
+ $keys[] = 'ep_exclude_from_search';
+ return $keys;
+ }
+
/**
* Enqueue block editor assets.
*/
diff --git a/includes/classes/Feature/Search/Weighting.php b/includes/classes/Feature/Search/Weighting.php
index efd18eeb0e..4a7324edc1 100644
--- a/includes/classes/Feature/Search/Weighting.php
+++ b/includes/classes/Feature/Search/Weighting.php
@@ -8,6 +8,7 @@
namespace ElasticPress\Feature\Search;
use ElasticPress\Features;
+use ElasticPress\Indexables;
use ElasticPress\Feature;
use ElasticPress\Indexable\Post\Post;
use ElasticPress\Utils;
@@ -36,9 +37,9 @@ public function setup() {
}
add_action( 'admin_menu', [ $this, 'add_weighting_submenu_page' ], 15 );
- add_action( 'admin_post_ep-weighting', [ $this, 'handle_save' ] );
add_filter( 'ep_formatted_args', [ $this, 'do_weighting' ], 20, 2 ); // After date decay, etc are injected
add_filter( 'ep_query_weighting_fields', [ $this, 'adjust_weight_for_cross_fields' ], 10, 5 );
+ add_action( 'rest_api_init', [ $this, 'register_rest_routes' ] );
}
/**
@@ -83,7 +84,7 @@ public function get_weightable_fields_for_post_type( $post_type ) {
$taxonomies = array_intersect( $public_taxonomies, $post_type_taxonomies );
- if ( $taxonomies ) {
+ if ( ! empty( $taxonomies ) ) {
$fields['taxonomies'] = [
'label' => __( 'Taxonomies', 'elasticpress' ),
'children' => [],
@@ -100,6 +101,39 @@ public function get_weightable_fields_for_post_type( $post_type ) {
}
}
+ $fields['ep_metadata'] = [
+ 'label' => 'Metadata',
+ 'children' => [],
+ ];
+
+ $empty_post = new \WP_Post( new \stdClass() );
+
+ $empty_post->post_type = $post_type;
+
+ /** This filter is documented in includes/classes/Indexable/Post/Post.php */
+ $allowed_protected_keys = apply_filters( 'ep_prepare_meta_allowed_protected_keys', [], $empty_post );
+
+ sort( $allowed_protected_keys, SORT_STRING );
+
+ /** This filter is documented in includes/classes/Indexable/Post/Post.php */
+ $excluded_public_keys = apply_filters( 'ep_prepare_meta_excluded_public_keys', [], $empty_post );
+
+ foreach ( $allowed_protected_keys as $meta_key ) {
+ $key = "meta.$meta_key.value";
+
+ if ( in_array( $key, $excluded_public_keys, true ) ) {
+ continue;
+ }
+
+ $required = in_array( $meta_key, $allowed_protected_keys, true );
+
+ $fields['ep_metadata']['children'][ $key ] = [
+ 'key' => $key,
+ 'label' => $meta_key,
+ 'required' => $required,
+ ];
+ }
+
/**
* Filter weighting fields for a post type
*
@@ -111,6 +145,52 @@ public function get_weightable_fields_for_post_type( $post_type ) {
return apply_filters( 'ep_weighting_fields_for_post_type', $fields, $post_type );
}
+ /**
+ * Get weightable fields for all searchable post types.
+ *
+ * @since 5.0.0
+ * @return array
+ */
+ public function get_weightable_fields() {
+ $weightable = array();
+ $post_types = Features::factory()->get_registered_feature( 'search' )->get_searchable_post_types();
+
+ foreach ( $post_types as $post_type ) {
+ $post_type_object = get_post_type_object( $post_type );
+ $post_type_labels = get_post_type_labels( $post_type_object );
+
+ $weightable_fields = $this->get_weightable_fields_for_post_type( $post_type );
+
+ $groups = [];
+ $fields = [];
+
+ foreach ( $weightable_fields as $group => $weightable_field ) {
+ $groups[] = [
+ 'key' => $group,
+ 'label' => $weightable_field['label'],
+ ];
+
+ foreach ( $weightable_field['children'] as $field ) {
+ $fields[] = [
+ 'group' => $group,
+ 'key' => $field['key'],
+ 'label' => $field['label'],
+ 'required' => isset( $field['required'] ) ? $field['required'] : false,
+ ];
+ }
+ }
+
+ $weightable[] = [
+ 'key' => $post_type,
+ 'label' => $post_type_labels->menu_name,
+ 'groups' => $groups,
+ 'fields' => $fields,
+ ];
+ }
+
+ return $weightable;
+ }
+
/**
* Returns default settings for any post type
*
@@ -192,6 +272,57 @@ public function get_weighting_configuration() {
return apply_filters( 'ep_weighting_configuration', get_option( 'elasticpress_weighting', [] ) );
}
+ /**
+ * Returns the current weighting configuration with defaults for any
+ * missing fields.
+ *
+ * @return array Current weighting configuration with defaults.
+ * @since 5.0.0
+ */
+ public function get_weighting_configuration_with_defaults() {
+ $search = Features::factory()->get_registered_feature( 'search' );
+
+ $post_types = $search->get_searchable_post_types();
+ $weighting = $this->get_weighting_configuration();
+
+ foreach ( $post_types as $post_type ) {
+ $current = isset( $weighting[ $post_type ] ) ? $weighting[ $post_type ] : [];
+ $defaults = $this->get_post_type_default_settings( $post_type );
+
+ $weighting[ $post_type ] = wp_parse_args( $current, $defaults );
+ }
+
+ return $weighting;
+ }
+
+ /**
+ * Returns the current meta mode.
+ *
+ * @return array
+ * @since 5.0.0
+ */
+ public function get_meta_mode() {
+ if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
+ return 'auto';
+ }
+
+ /**
+ * Filter meta management mode.
+ *
+ * Setting the meta mode to 'auto' will restore the pre-5.0.0 behavior
+ * of syncing all public meta fields, but without the ability to
+ * add fields to make them searchable through the UI. Weighting settings
+ * will need to be changed, and a sync performed, any time this value
+ * is changed.
+ *
+ * @hook ep_meta_mode
+ * @since 5.0.0
+ * @param string $ep_meta_mode Meta mode.
+ * @return string New meta mode.
+ */
+ return apply_filters( 'ep_meta_mode', 'manual' );
+ }
+
/**
* Adds the submenu page for controlling weighting
*/
@@ -212,211 +343,144 @@ public function add_weighting_submenu_page() {
public function render_settings_page() {
include EP_PATH . '/includes/partials/header.php'; ?>
-
-
-
- render_settings_section( $post_type, $child, $current_values );
- }
- ?>
-
-
- get_post_type_default_settings( $post_type );
-
- $weight = isset( $post_type_settings[ $key ] ) && isset( $post_type_settings[ $key ]['weight'] ) ? (int) $post_type_settings[ $key ]['weight'] : 0;
-
- $range_disabled = '';
-
- $enabled = (
- isset( $post_type_settings ) &&
- isset( $post_type_settings[ $key ] ) &&
- isset( $post_type_settings[ $key ]['enabled'] )
- )
- ? boolval( $post_type_settings[ $key ]['enabled'] ) : false;
-
- if ( ! $enabled ) {
- $range_disabled = 'disabled="disabled" ';
- $weight = 0;
- }
- ?>
-
-
-
-
- id="" name="weighting[][][enabled]">
- ">
-
-
-
- ">
-
-
-
-
-
- " name="weighting[][][weight]" >
-
-
- save_weighting_configuration( $_POST );
-
- $redirect_url = admin_url( 'admin.php?page=elasticpress-weighting' );
- $redirect_url = add_query_arg( 'settings-updated', true, $redirect_url );
-
- $this->redirect( $redirect_url );
+ _doing_it_wrong(
+ __METHOD__,
+ esc_html( 'Weighting settings are now updated using the REST API.' ),
+ 'ElasticPress 5.0.0'
+ );
}
/**
* We need this method to test handle_save properly.
*
* @param string $redirect_url Redirect URL.
+ * @deprecated
*/
protected function redirect( $redirect_url ) {
- // @codeCoverageIgnoreStart
- wp_safe_redirect( $redirect_url );
- exit();
- // @codeCoverageIgnoreEnd
+ _doing_it_wrong(
+ __METHOD__,
+ esc_html( 'Weighting settings are now updated using the REST API, and do not redirect server-side.' ),
+ 'ElasticPress 5.0.0'
+ );
}
/**
- * Save weighting configuration for each searchable post_type
+ * Save weighting configuration for each searchable post_type.
*
* @param array $settings weighting settings
- *
- * @return array final settings
+ * @return void
* @since 3.4.1
+ * @deprecated
*/
public function save_weighting_configuration( $settings ) {
- $new_config = array();
- $previous_config_formatted = array();
- $current_config = $this->get_weighting_configuration();
+ _doing_it_wrong(
+ __METHOD__,
+ esc_html( 'Weighting sections display are now handled via React components.' ),
+ 'ElasticPress 5.0.0'
+ );
+ }
- foreach ( $current_config as $post_type => $post_type_weighting ) {
- // This also ensures the string is safe, since this would return false otherwise
- if ( ! post_type_exists( $post_type ) ) {
- continue;
- }
+ /**
+ * Register REST routes.
+ *
+ * @return void
+ * @since 5.0.0
+ */
+ public function register_rest_routes() {
+ register_rest_route(
+ 'elasticpress/v1',
+ 'weighting',
+ [
+ 'callback' => [ $this, 'update_weighting' ],
+ 'methods' => 'POST',
+ 'permission_callback' => function() {
+ return current_user_can( Utils\get_capability() );
+ },
+ ]
+ );
+ }
- // We need a way to know if fields have been explicitly set before, let's compare a previous state against $_POST['weighting']
- foreach ( $post_type_weighting as $weighting_field => $weighting_values ) {
- $previous_config_formatted[ $post_type ][ sanitize_text_field( $weighting_field ) ] = [
- 'weight' => isset( $settings['weighting'][ $post_type ][ $weighting_field ]['weight'] ) ? intval( $settings['weighting'][ $post_type ][ $weighting_field ]['weight'] ) : 0,
- 'enabled' => isset( $settings['weighting'][ $post_type ][ $weighting_field ]['enabled'] ) && 'on' === $settings['weighting'][ $post_type ][ $weighting_field ]['enabled'] ? true : false,
- ];
- }
- }
+ /**
+ * Handles processing the new weighting values and saving them.
+ *
+ * @param \WP_Rest_Request $request REST API request.
+ * @return array
+ * @since 5.0.0
+ */
+ public function update_weighting( $request = null ) {
+ $meta_mode = $this->get_meta_mode();
+ $weighting = $request->get_json_params();
- $search = Features::factory()->get_registered_feature( 'search' );
- $post_types = $search->get_searchable_post_types();
+ $post_types = Features::factory()->get_registered_feature( 'search' )->get_searchable_post_types();
+ // Add default fields for post types not sent.
foreach ( $post_types as $post_type ) {
- // This also ensures the string is safe, since this would return false otherwise
- if ( ! post_type_exists( $post_type ) ) {
- continue;
+ if ( ! isset( $weighting[ $post_type ] ) ) {
+ $weighting[ $post_type ] = [];
}
+ }
- /** override default post_type settings while saving */
- $new_config[ $post_type ] = array();
+ /**
+ * If metadata is not being managed manually, remove any custom
+ * fields that have not been registered as weightable fields.
+ */
+ if ( 'manual' !== $meta_mode ) {
+ foreach ( $weighting as $post_type => $fields ) {
+ $weightable_fields = $this->get_weightable_fields_for_post_type( $post_type );
- if ( isset( $settings['weighting'][ $post_type ] ) ) {
- foreach ( $settings['weighting'][ $post_type ] as $weighting_field => $weighting_values ) {
- $new_config[ $post_type ][ sanitize_text_field( $weighting_field ) ] = [
- 'weight' => isset( $weighting_values['weight'] ) ? intval( $weighting_values['weight'] ) : 0,
- 'enabled' => isset( $weighting_values['enabled'] ) && 'on' === $weighting_values['enabled'] ? true : false,
- ];
+ foreach ( $fields as $key => $value ) {
+ $is_weightable = false;
+
+ foreach ( $weightable_fields as $group ) {
+ if ( isset( $group['children'][ $key ] ) ) {
+ $is_weightable = true;
+ continue;
+ }
+ }
+
+ if ( ! $is_weightable ) {
+ unset( $weighting[ $post_type ][ $key ] );
+ }
}
}
}
- $final_config = array_replace_recursive( $previous_config_formatted, $new_config );
+ // Cleanup any post type sent (or added via filters) that does not exist.
+ foreach ( $weighting as $post_type => $fields ) {
+ if ( ! post_type_exists( $post_type ) ) {
+ unset( $weighting[ $post_type ] );
+ }
+ }
- update_option( 'elasticpress_weighting', $final_config );
+ update_option( 'elasticpress_weighting', $weighting );
/**
* Fires right after the weighting configuration is saved.
@@ -426,7 +490,10 @@ public function save_weighting_configuration( $settings ) {
*/
do_action( 'ep_saved_weighting_configuration' );
- return $final_config;
+ return [
+ 'data' => $weighting,
+ 'success' => true,
+ ];
}
/**
diff --git a/includes/classes/Feature/SearchOrdering/SearchOrdering.php b/includes/classes/Feature/SearchOrdering/SearchOrdering.php
index d856212b59..4a686bd975 100644
--- a/includes/classes/Feature/SearchOrdering/SearchOrdering.php
+++ b/includes/classes/Feature/SearchOrdering/SearchOrdering.php
@@ -326,6 +326,7 @@ public function register_post_type() {
'show_admin_column' => false,
'query_var' => false,
'rewrite' => false,
+ 'public' => false,
);
/** Features Class @var Features $features */
diff --git a/includes/classes/Feature/WooCommerce/Orders.php b/includes/classes/Feature/WooCommerce/Orders.php
index 6f5c87584a..0301aff448 100644
--- a/includes/classes/Feature/WooCommerce/Orders.php
+++ b/includes/classes/Feature/WooCommerce/Orders.php
@@ -39,7 +39,7 @@ public function __construct( WooCommerce $woocommerce ) {
*/
public function setup() {
add_filter( 'ep_sync_insert_permissions_bypass', [ $this, 'bypass_order_permissions_check' ], 10, 2 );
- add_filter( 'ep_prepare_meta_allowed_protected_keys', [ $this, 'allow_meta_keys' ] );
+ add_filter( 'ep_prepare_meta_allowed_protected_keys', [ $this, 'allow_meta_keys' ], 10, 2 );
add_filter( 'ep_post_sync_args_post_prepare_meta', [ $this, 'add_order_items_search' ], 20, 2 );
add_filter( 'ep_pc_skip_post_content_cleanup', [ $this, 'keep_order_fields' ], 20, 2 );
add_action( 'parse_query', [ $this, 'maybe_hook_woocommerce_search_fields' ], 1 );
@@ -101,10 +101,15 @@ public function get_admin_searchable_post_types() {
/**
* Index WooCommerce orders meta fields
*
- * @param array $meta Existing post meta
+ * @param array $meta Existing post meta
+ * @param \WP_Post $post Post object.
* @return array
*/
- public function allow_meta_keys( $meta ) {
+ public function allow_meta_keys( $meta, $post ) {
+ if ( ! in_array( $post->post_type, [ 'shop_order', 'shop_order_refund' ], true ) ) {
+ return $meta;
+ }
+
return array_unique(
array_merge(
$meta,
diff --git a/includes/classes/Feature/WooCommerce/Products.php b/includes/classes/Feature/WooCommerce/Products.php
index cabdc0e959..6799dd7df5 100644
--- a/includes/classes/Feature/WooCommerce/Products.php
+++ b/includes/classes/Feature/WooCommerce/Products.php
@@ -41,7 +41,7 @@ public function __construct( WooCommerce $woocommerce ) {
*/
public function setup() {
add_action( 'ep_formatted_args', [ $this, 'price_filter' ], 10, 3 );
- add_filter( 'ep_prepare_meta_allowed_protected_keys', [ $this, 'allow_meta_keys' ] );
+ add_filter( 'ep_prepare_meta_allowed_protected_keys', [ $this, 'allow_meta_keys' ], 10, 2 );
add_filter( 'ep_sync_taxonomies', [ $this, 'sync_taxonomies' ] );
add_filter( 'ep_term_suggest_post_type', [ $this, 'suggest_wc_add_post_type' ] );
add_filter( 'ep_facet_include_taxonomies', [ $this, 'add_product_attributes' ] );
@@ -157,10 +157,15 @@ public function price_filter( $args, $query_args, $query ) {
/**
* Index WooCommerce products meta fields
*
- * @param array $meta Existing post meta
+ * @param array $meta Existing post meta
+ * @param \WP_Post $post Post object.
* @return array
*/
- public function allow_meta_keys( $meta ) {
+ public function allow_meta_keys( $meta, $post ) {
+ if ( 'product' !== $post->post_type ) {
+ return $meta;
+ }
+
return array_unique(
array_merge(
$meta,
@@ -314,6 +319,8 @@ public function add_product_attributes_to_weighting( $fields, $post_type ) {
$sku_key = 'meta._sku.value';
+ unset( $fields['ep_metadata']['children'][ $sku_key ] );
+
$fields['attributes']['children'][ $sku_key ] = array(
'key' => $sku_key,
'label' => __( 'SKU', 'elasticpress' ),
@@ -321,6 +328,8 @@ public function add_product_attributes_to_weighting( $fields, $post_type ) {
$variations_skus_key = 'meta._variations_skus.value';
+ unset( $fields['ep_metadata']['children'][ $variations_skus_key ] );
+
$fields['attributes']['children'][ $variations_skus_key ] = array(
'key' => $variations_skus_key,
'label' => __( 'Variations SKUs', 'elasticpress' ),
diff --git a/includes/classes/Indexable/Post/Post.php b/includes/classes/Indexable/Post/Post.php
index e40e00d6a8..e1e9e124e3 100644
--- a/includes/classes/Indexable/Post/Post.php
+++ b/includes/classes/Indexable/Post/Post.php
@@ -842,57 +842,13 @@ public function is_meta_allowed( $meta_key, $post ) {
public function filter_allowed_metas( $metas, $post ) {
$filtered_metas = [];
- /**
- * Filter indexable protected meta keys for posts
- *
- * @hook ep_prepare_meta_allowed_protected_keys
- * @param {array} $keys Allowed protected keys
- * @param {WP_Post} $post Post object
- * @since 1.7
- * @return {array} New keys
- */
- $allowed_protected_keys = apply_filters( 'ep_prepare_meta_allowed_protected_keys', [], $post );
-
- /**
- * Filter public keys to exclude from indexed post
- *
- * @hook ep_prepare_meta_excluded_public_keys
- * @param {array} $keys Excluded protected keys
- * @param {WP_Post} $post Post object
- * @since 1.7
- * @return {array} New keys
- */
- $excluded_public_keys = apply_filters( 'ep_prepare_meta_excluded_public_keys', [], $post );
-
- foreach ( $metas as $key => $value ) {
-
- $allow_index = false;
-
- if ( is_protected_meta( $key ) ) {
-
- if ( true === $allowed_protected_keys || in_array( $key, $allowed_protected_keys, true ) ) {
- $allow_index = true;
- }
- } else {
-
- if ( true !== $excluded_public_keys && ! in_array( $key, $excluded_public_keys, true ) ) {
- $allow_index = true;
- }
- }
-
- /**
- * Filter force whitelisting a meta key
- *
- * @hook ep_prepare_meta_whitelist_key
- * @param {bool} $whitelist True to whitelist key
- * @param {string} $key Meta key
- * @param {WP_Post} $post Post object
- * @return {bool} New whitelist value
- */
- if ( true === $allow_index || apply_filters( 'ep_prepare_meta_whitelist_key', false, $key, $post ) ) {
- $filtered_metas[ $key ] = $value;
- }
+ $search = \ElasticPress\Features::factory()->get_registered_feature( 'search' );
+ if ( $search && ! empty( $search->weighting ) && 'manual' === $search->weighting->get_meta_mode() ) {
+ $filtered_metas = $this->filter_allowed_metas_manual( $metas, $post );
+ } else {
+ $filtered_metas = $this->filter_allowed_metas_auto( $metas, $post );
}
+
return $filtered_metas;
}
@@ -2520,6 +2476,143 @@ protected function parse_tax_query_field( string $field ) : string {
return $from_to[ $field ] ?? 'term_id';
}
+ /**
+ * Filter a list of meta keys down to those chosen by the user or
+ * allowed via a hook.
+ *
+ * This function is used when manual management of metadata fields is
+ * enabled. This is the default behaviour as of 5.0.0 and controlled by the
+ * `ep_meta_mode` filter.
+ *
+ * @param array $metas Key => value pairs of post meta
+ * @param WP_Post $post Post object
+ * @since 5.0.0
+ * @return array
+ */
+ protected function filter_allowed_metas_manual( $metas, $post ) {
+ $filtered_metas = [];
+ $search_feature = \ElasticPress\Features::factory()->get_registered_feature( 'search' );
+
+ if ( empty( $post->post_type ) ) {
+ return $filtered_metas;
+ }
+
+ $weighting = $search_feature->weighting->get_weighting_configuration_with_defaults();
+ $is_searchable = in_array( $search_feature, $search_feature->get_searchable_post_types(), true );
+ if ( empty( $weighting[ $post->post_type ] ) && $is_searchable ) {
+ return $filtered_metas;
+ }
+
+ /** This filter is documented in includes/classes/Indexable/Post/Post.php */
+ $allowed_protected_keys = apply_filters( 'ep_prepare_meta_allowed_protected_keys', [], $post );
+
+ $selected_keys = [];
+ if ( ! empty( $weighting[ $post->post_type ] ) ) {
+ $selected_keys = array_map(
+ function ( $field ) {
+ if ( false === strpos( $field, 'meta.' ) ) {
+ return null;
+ }
+ $field_name_parts = explode( '.', $field );
+ return $field_name_parts[1];
+ },
+ array_keys( $weighting[ $post->post_type ] )
+ );
+ $selected_keys = array_filter( $selected_keys );
+ }
+
+ /**
+ * Filter indexable meta keys for posts
+ *
+ * @hook ep_prepare_meta_allowed_keys
+ * @param {array} $keys Allowed keys
+ * @param {WP_Post} $post Post object
+ * @since 5.0.0
+ * @return {array} New keys
+ */
+ $allowed_keys = apply_filters( 'ep_prepare_meta_allowed_keys', array_merge( $allowed_protected_keys, $selected_keys ), $post );
+
+ foreach ( $metas as $key => $value ) {
+ if ( ! in_array( $key, $allowed_keys, true ) ) {
+ continue;
+ }
+
+ $filtered_metas[ $key ] = $value;
+ }
+
+ return $filtered_metas;
+ }
+
+ /**
+ * Filter a list of meta keys down to public keys or protected keys
+ * allowed via a hook.
+ *
+ * This function is used to filter meta keys when ElasticPress is in
+ * network mode or when the meta mode is set to `auto` via the
+ * `ep_meta_mode` hook. This was the default behaviour prior to 5.0.0.
+ *
+ * @param array $metas Key => value pairs of post meta
+ * @param WP_Post $post Post object
+ * @since 5.0.0
+ * @return array
+ */
+ protected function filter_allowed_metas_auto( $metas, $post ) {
+ $filtered_metas = [];
+
+ /**
+ * Filter indexable protected meta keys for posts
+ *
+ * @hook ep_prepare_meta_allowed_protected_keys
+ * @param {array} $keys Allowed protected keys
+ * @param {WP_Post} $post Post object
+ * @since 1.7
+ * @return {array} New keys
+ */
+ $allowed_protected_keys = apply_filters( 'ep_prepare_meta_allowed_protected_keys', [], $post );
+
+ /**
+ * Filter public keys to exclude from indexed post
+ *
+ * @hook ep_prepare_meta_excluded_public_keys
+ * @param {array} $keys Excluded protected keys
+ * @param {WP_Post} $post Post object
+ * @since 1.7
+ * @return {array} New keys
+ */
+ $excluded_public_keys = apply_filters( 'ep_prepare_meta_excluded_public_keys', [], $post );
+
+ foreach ( $metas as $key => $value ) {
+
+ $allow_index = false;
+
+ if ( is_protected_meta( $key ) ) {
+
+ if ( true === $allowed_protected_keys || in_array( $key, $allowed_protected_keys, true ) ) {
+ $allow_index = true;
+ }
+ } else {
+
+ if ( true !== $excluded_public_keys && ! in_array( $key, $excluded_public_keys, true ) ) {
+ $allow_index = true;
+ }
+ }
+
+ /**
+ * Filter force whitelisting a meta key
+ *
+ * @hook ep_prepare_meta_whitelist_key
+ * @param {bool} $whitelist True to whitelist key
+ * @param {string} $key Meta key
+ * @param {WP_Post} $post Post object
+ * @return {bool} New whitelist value
+ */
+ if ( true === $allow_index || apply_filters( 'ep_prepare_meta_whitelist_key', false, $key, $post ) ) {
+ $filtered_metas[ $key ] = $value;
+ }
+ }
+ return $filtered_metas;
+ }
+
/**
* Return all distinct meta fields in the database.
*
diff --git a/includes/dashboard.php b/includes/dashboard.php
index 47ada75d96..c655a16509 100644
--- a/includes/dashboard.php
+++ b/includes/dashboard.php
@@ -469,7 +469,15 @@ function action_admin_enqueue_dashboard_scripts() {
wp_set_script_translations( 'ep_admin_script', 'elasticpress' );
}
- if ( in_array( Screen::factory()->get_current_screen(), [ 'weighting', 'install' ], true ) ) {
+ if ( 'weighting' === Screen::factory()->get_current_screen() ) {
+
+ wp_enqueue_style(
+ 'ep_weighting_styles',
+ EP_URL . 'dist/css/weighting-script.css',
+ [ 'wp-components', 'wp-edit-post' ],
+ Utils\get_asset_info( 'weighting-script', 'version' )
+ );
+
wp_enqueue_script(
'ep_weighting_script',
EP_URL . 'dist/js/weighting-script.js',
@@ -478,6 +486,24 @@ function action_admin_enqueue_dashboard_scripts() {
true
);
+ $weighting = Features::factory()->get_registered_feature( 'search' )->weighting;
+
+ $api_url = esc_url_raw( rest_url( 'elasticpress/v1/weighting' ) );
+ $meta_mode = $weighting->get_meta_mode();
+ $weightable_fields = $weighting->get_weightable_fields();
+ $weighting_configuration = $weighting->get_weighting_configuration_with_defaults();
+
+ wp_localize_script(
+ 'ep_weighting_script',
+ 'epWeighting',
+ array(
+ 'apiUrl' => $api_url,
+ 'metaMode' => $meta_mode,
+ 'weightableFields' => $weightable_fields,
+ 'weightingConfiguration' => $weighting_configuration,
+ )
+ );
+
wp_set_script_translations( 'ep_weighting_script', 'elasticpress' );
}
diff --git a/package.json b/package.json
index 2f24b31cdd..caaf2ff24e 100644
--- a/package.json
+++ b/package.json
@@ -81,7 +81,7 @@
"synonyms-script": "./assets/js/synonyms/index.js",
"woocommerce-order-search-script": "./assets/js/woocommerce/admin/orders/index.js",
"admin-script": "./assets/js/admin.js",
- "weighting-script": "./assets/js/weighting.js",
+ "weighting-script": "./assets/js/weighting/index.js",
"search-editor-script": "./assets/js/search/editor/index.js",
"autosuggest-styles": "./assets/css/autosuggest.css",
"comments-styles": "./assets/css/comments.css",
diff --git a/tests/cypress/integration/features/facets.cy.js b/tests/cypress/integration/features/facets.cy.js
index bb4696613e..d36a3af580 100644
--- a/tests/cypress/integration/features/facets.cy.js
+++ b/tests/cypress/integration/features/facets.cy.js
@@ -19,6 +19,31 @@ describe('Facets Feature', { tags: '@slow' }, () => {
wp_delete_post( $post, true );
}
`);
+
+ cy.updateWeighting();
+
+ cy.visitAdminPage('admin.php?page=elasticpress-weighting');
+
+ cy.intercept('/wp-json/elasticpress/v1/weighting*').as('apiRequest');
+ cy.contains('h2', 'Posts').closest('.components-panel').as('postsPanel');
+
+ cy.get('@postsPanel').contains('button', 'Metadata').click();
+
+ cy.get('@postsPanel').find('input[type="text"]').as('metaInput');
+ cy.get('@postsPanel').contains('button', 'Add').as('metaAdd');
+
+ cy.get('@metaInput').clearThenType('meta_field_1');
+ cy.get('@metaAdd').click();
+ cy.get('@metaInput').clearThenType('meta_field_2');
+ cy.get('@metaAdd').click();
+ cy.get('@metaInput').clearThenType('numeric_meta_field');
+ cy.get('@metaAdd').click();
+ cy.get('@metaInput').clearThenType('non_numeric_meta_field');
+ cy.get('@metaAdd').click();
+
+ cy.contains('button', 'Save changes').click();
+
+ cy.wait('@apiRequest');
});
/**
diff --git a/tests/cypress/integration/features/search/weighting.cy.js b/tests/cypress/integration/features/search/weighting.cy.js
index ac6157523c..c643fe17b3 100644
--- a/tests/cypress/integration/features/search/weighting.cy.js
+++ b/tests/cypress/integration/features/search/weighting.cy.js
@@ -1,65 +1,318 @@
describe('Post Search Feature - Weighting Functionality', () => {
- it("Can't find a post by title if title is not marked as searchable", () => {
- cy.login();
+ /**
+ * Delete test posts before running tests.
+ */
+ before(() => {
+ cy.wpCli(
+ 'post list --meta_key="_weighting_tests" --meta_value="1" --ep_integrate=false --format=ids',
+ ).then((wpCliResponse) => {
+ if (wpCliResponse.stdout) {
+ cy.wpCli(`post delete ${wpCliResponse.stdout} --force`);
+ }
+ });
+ });
+ /**
+ * Reset weighting settings and log in before each test.
+ */
+ beforeEach(() => {
+ cy.deactivatePlugin('auto-meta-mode', 'wpCli');
cy.updateWeighting();
+ cy.login();
+ });
- cy.publishPost({
- title: 'supercustomtitle',
- });
+ /**
+ * Test that the Searchable checkbox works as expected.
+ */
+ it("Can't find a post by title if title is not marked as searchable", () => {
+ /**
+ * Create post with a unique title.
+ */
+ cy.wpCliEval(
+ `wp_insert_post(
+ [
+ 'post_title' => 'supercustomtitle',
+ 'post_content' => '',
+ 'post_status' => 'publish',
+ 'meta_input' => [
+ '_weighting_tests' => 1,
+ ],
+ ]
+ );`,
+ );
+
+ /**
+ * Sync.
+ */
+ cy.wpCli('wp elasticpress sync --yes').its('stdout').should('contain', 'Success: Done!');
+ cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
+ /**
+ * Search for the new post. It should be returned.
+ */
cy.visit('/?s=supercustomtitle');
- cy.get('.hentry').should('contain.text', 'supercustomtitle');
+ cy.get('.entry-title').should('contain.text', 'supercustomtitle');
+ /**
+ * Make the title non-searchable for Posts.
+ */
cy.visitAdminPage('admin.php?page=elasticpress-weighting');
- cy.get('#post-post_title-enabled').uncheck();
- cy.get('#submit').click();
+ cy.get('.components-panel__header')
+ .contains('Posts')
+ .closest('.components-panel')
+ .find('fieldset')
+ .contains('Title')
+ .closest('fieldset')
+ .find('input[type="checkbox"]')
+ .uncheck();
- cy.visit('/?s=supercustomtitle');
- cy.get('.hentry').should('not.exist');
+ /**
+ * Save weighting settings.
+ */
+ cy.intercept('/wp-json/elasticpress/v1/weighting*').as('apiRequest');
+ cy.contains('button', 'Save changes').click();
+ cy.wait('@apiRequest');
- // Reset setting.
- cy.visitAdminPage('admin.php?page=elasticpress-weighting');
- cy.get('#post-post_title-enabled').check();
- cy.get('#submit').click();
+ /**
+ * Sync.
+ */
+ cy.wpCli('wp elasticpress sync --yes').its('stdout').should('contain', 'Success: Done!');
+ cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
+
+ /**
+ * Search for the post again. No results should be returned.
+ */
+ cy.visit('/?s=supercustomtitle');
+ cy.get('.entry-title').should('not.exist');
});
+ /**
+ * Test that adjusting weighting influences search results as expected.
+ */
it('Can increase post_title weighting and influence search results', () => {
cy.login();
- const postsData = [
- {
- title: 'test weighting content',
- content: 'findbyweighting findbyweighting findbyweighting',
- },
- {
- title: 'test weighting title findbyweighting',
- content: 'Nothing here.',
- },
- ];
-
- postsData.forEach((postData) => {
- cy.publishPost(postData);
- });
+ cy.wpCliEval(
+ `wp_insert_post(
+ [
+ 'post_title' => 'test weighting content',
+ 'post_content' => 'findbyweighting findbyweighting findbyweighting',
+ 'post_status' => 'publish',
+ 'meta_input' => [
+ '_weighting_tests' => 1,
+ ],
+ ]
+ );
- cy.visit('/?s=findbyweighting');
- cy.contains('.site-content article:nth-of-type(1) h2', 'test weighting content').should(
- 'exist',
+ wp_insert_post(
+ [
+ 'post_title' => 'test weighting title findbyweighting',
+ 'post_content' => 'Nothing here.',
+ 'post_status' => 'publish',
+ 'meta_input' => [
+ '_weighting_tests' => 1,
+ ],
+ ]
+ );`,
);
+ /**
+ * Sync.
+ */
+ cy.wpCli('wp elasticpress sync --yes').its('stdout').should('contain', 'Success: Done!');
+ cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
+
+ /**
+ * Search for the test posts. Both should be returned.
+ */
+ cy.visit('/?s=findbyweighting');
+ cy.get('.entry-title').contains('test weighting content').should('exist');
+ cy.get('.entry-title').contains('test weighting title findbyweighting').should('exist');
+
+ /**
+ * Adjust the weighting of the title.
+ */
cy.visitAdminPage('admin.php?page=elasticpress-weighting');
- cy.get('input[name="weighting[post][post_title][weight]"]').invoke('attr', 'value', '20');
- cy.get('#submit').click();
+ cy.get('.components-panel__header')
+ .contains('Posts')
+ .closest('.components-panel')
+ .find('fieldset')
+ .contains('Title')
+ .closest('fieldset')
+ .find('input[type="number"]')
+ .clearThenType(20);
+ /**
+ * Save weighting settings.
+ */
+ cy.intercept('/wp-json/elasticpress/v1/weighting*').as('apiRequest');
+ cy.contains('button', 'Save changes').click();
+ cy.wait('@apiRequest');
+
+ /**
+ * Sync.
+ */
+ cy.wpCli('wp elasticpress sync --yes').its('stdout').should('contain', 'Success: Done!');
+ cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
+
+ /**
+ * Search for the posts again. The post with the search term in the
+ * title should be returned first.
+ */
cy.visit('/?s=findbyweighting');
- cy.contains(
- '.site-content article:nth-of-type(1) h2',
- 'test weighting title findbyweighting',
- ).should('exist');
+ cy.get('.entry-title')
+ .first()
+ .should('contain.text', 'test weighting title findbyweighting');
+ cy.get('.entry-title').last().should('contain.text', 'test weighting content');
+ });
+
+ /**
+ * Test that searching meta fields works as expected.
+ */
+ it('Can add, weight and search meta fields', () => {
+ /**
+ * Create a post with a custom field with a specific value and a post
+ * with the value as content for weighting comparison purposes.
+ */
+ cy.wpCliEval(
+ `wp_insert_post(
+ [
+ 'post_title' => 'Test meta weighting, post meta',
+ 'post_content' => '',
+ 'post_status' => 'publish',
+ 'meta_input' => [
+ '_weighting_tests' => 1,
+ '_my_custom_field' => 'abc123',
+ ],
+ ]
+ );
+
+ wp_insert_post(
+ [
+ 'post_title' => 'Test meta weighting, post content',
+ 'post_content' => 'abc123',
+ 'post_status' => 'publish',
+ 'meta_input' => [
+ '_weighting_tests' => 1,
+ ],
+ ]
+ );`,
+ );
+
+ /**
+ * Sync.
+ */
+ cy.wpCli('wp elasticpress sync --yes').its('stdout').should('contain', 'Success: Done!');
+ cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
+
+ /**
+ * Only the post with the value in its content should appear.
+ */
+ cy.visit('/?s=abc123');
+ cy.get('.entry-title').contains('Test meta weighting, post content').should('exist');
+ cy.get('.entry-title').contains('Test meta weighting, post meta').should('not.exist');
- // Reset setting.
+ /**
+ * Add the custom field to the posts index.
+ */
cy.visitAdminPage('admin.php?page=elasticpress-weighting');
- cy.get('input[name="weighting[post][post_title][weight]"]').invoke('attr', 'value', '1');
- cy.get('#submit').click();
+ cy.get('.components-panel__header')
+ .contains('Posts')
+ .closest('.components-panel')
+ .as('panel')
+ .find('fieldset')
+ .contains('Content')
+ .closest('fieldset')
+ .find('input[type="number"]')
+ .clearThenType(100);
+ cy.get('@panel').find('button').contains('Metadata').click();
+ cy.get('@panel').find('input[type="text"]').clearThenType('_my_custom_field');
+ cy.get('@panel').find('button').contains('Add').click();
+ cy.get('@panel')
+ .find('fieldset')
+ .contains('_my_custom_field')
+ .closest('fieldset')
+ .find('input[type="checkbox"]')
+ .check();
+
+ /**
+ * Save weighting settings.
+ */
+ cy.intercept('/wp-json/elasticpress/v1/weighting*').as('apiRequest');
+ cy.contains('button', 'Save changes').click();
+ cy.wait('@apiRequest');
+
+ /**
+ * Sync.
+ */
+ cy.wpCli('wp elasticpress sync --yes').its('stdout').should('contain', 'Success: Done!');
+ cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
+
+ /**
+ * Both results should be returned, but the post with the value in its
+ * content should be returned first.
+ */
+ cy.visit('/?s=abc123');
+ cy.get('.entry-title').first().should('contain.text', 'Test meta weighting, post content');
+ cy.get('.entry-title').last().should('contain.text', 'Test meta weighting, post meta');
+
+ /**
+ * Update the weighting so the meta field is weighted higher.
+ */
+ cy.visitAdminPage('admin.php?page=elasticpress-weighting');
+ cy.get('.components-panel__header')
+ .contains('Posts')
+ .closest('.components-panel')
+ .as('panel')
+ .find('fieldset')
+ .contains('Content')
+ .closest('fieldset')
+ .find('input[type="number"]')
+ .clearThenType(1);
+ cy.get('@panel').find('button').contains('Metadata').click();
+ cy.get('@panel')
+ .find('fieldset')
+ .contains('_my_custom_field')
+ .closest('fieldset')
+ .find('input[type="number"]')
+ .clearThenType(100);
+
+ /**
+ * Save weighting settings.
+ */
+ cy.intercept('/wp-json/elasticpress/v1/weighting*').as('apiRequest');
+ cy.contains('button', 'Save changes').click();
+ cy.wait('@apiRequest');
+
+ /**
+ * The post with the value in its content should be now be returned
+ * first.
+ */
+ cy.visit('/?s=abc123');
+ cy.get('.entry-title').first().should('contain.text', 'Test meta weighting, post meta');
+ cy.get('.entry-title').last().should('contain.text', 'Test meta weighting, post content');
+
+ /**
+ * Enable automatic indexing of meta management and sync.
+ */
+ cy.activatePlugin('auto-meta-mode', 'wpCli');
+ cy.wpCli('wp elasticpress sync --yes').its('stdout').should('contain', 'Success: Done!');
+ cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
+
+ /**
+ * Weighting settings for custom fields should not be available when
+ * using automatic management.
+ */
+ cy.visitAdminPage('admin.php?page=elasticpress-weighting');
+ cy.get('.components-panel__body-title').contains('Metadata').should('not.exist');
+
+ /**
+ * With automatic meta management the post with a value in content
+ * should be returned, but the post with the value in a protected key
+ * should not be.
+ */
+ cy.visit('/?s=abc123');
+ cy.get('.entry-title').contains('Test meta weighting, post content').should('exist');
+ cy.get('.entry-title').contains('Test meta weighting, post meta').should('not.exist');
});
});
diff --git a/tests/cypress/integration/indexables/post.cy.js b/tests/cypress/integration/indexables/post.cy.js
index b30719ca75..275216b3e2 100644
--- a/tests/cypress/integration/indexables/post.cy.js
+++ b/tests/cypress/integration/indexables/post.cy.js
@@ -9,8 +9,17 @@ describe('Post Indexable', () => {
// Make sure post categories are searchable.
cy.visitAdminPage('admin.php?page=elasticpress-weighting');
- cy.get('#post-terms\\.category\\.name-enabled').check();
- cy.get('#submit').click();
+ cy.intercept('/wp-json/elasticpress/v1/weighting*').as('apiRequest');
+
+ cy.contains('h2', 'Posts').closest('.components-panel').as('postsPanel');
+ cy.get('@postsPanel')
+ .contains('legend', 'Categories')
+ .closest('fieldset')
+ .find('input[type="checkbox"]')
+ .check();
+
+ cy.contains('button', 'Save changes').click();
+ cy.wait('@apiRequest');
cy.setPerIndexCycle();
cy.visitAdminPage('edit-tags.php?taxonomy=category');
diff --git a/tests/cypress/wordpress-files/test-plugins/auto-meta-mode.php b/tests/cypress/wordpress-files/test-plugins/auto-meta-mode.php
new file mode 100644
index 0000000000..498764c90f
--- /dev/null
+++ b/tests/cypress/wordpress-files/test-plugins/auto-meta-mode.php
@@ -0,0 +1,17 @@
+get_registered_feature( 'facets' );
$facet_type = $facet_feature->types['meta'];
diff --git a/tests/php/features/TestWeighting.php b/tests/php/features/TestWeighting.php
index 58e05fdd55..d4aefb6b57 100644
--- a/tests/php/features/TestWeighting.php
+++ b/tests/php/features/TestWeighting.php
@@ -20,44 +20,42 @@ class TestWeighting extends BaseTestCase {
* @var array
*/
public $weighting_settings = [
- 'weighting' => [
- 'post' => [
- 'post_title' => [
- 'weight' => 1,
- 'enabled' => 'on',
- ],
- 'post_content' => [
- 'weight' => 1,
- 'enabled' => 'on',
- ],
- 'post_excerpt' => [
- 'weight' => 1,
- 'enabled' => 'on',
- ],
+ 'post' => [
+ 'post_title' => [
+ 'weight' => 1,
+ 'enabled' => 'on',
+ ],
+ 'post_content' => [
+ 'weight' => 1,
+ 'enabled' => 'on',
+ ],
+ 'post_excerpt' => [
+ 'weight' => 1,
+ 'enabled' => 'on',
+ ],
- 'author_name' => [
- 'weight' => 0,
- 'enabled' => 'on',
- ],
+ 'author_name' => [
+ 'weight' => 0,
+ 'enabled' => 'on',
+ ],
+ ],
+ 'page' => [
+ 'post_title' => [
+ 'weight' => 1,
+ 'enabled' => 'on',
+ ],
+ 'post_content' => [
+ 'weight' => 1,
+ 'enabled' => 'on',
+ ],
+ 'post_excerpt' => [
+ 'weight' => 1,
+ 'enabled' => 'on',
],
- 'page' => [
- 'post_title' => [
- 'weight' => 1,
- 'enabled' => 'on',
- ],
- 'post_content' => [
- 'weight' => 1,
- 'enabled' => 'on',
- ],
- 'post_excerpt' => [
- 'weight' => 1,
- 'enabled' => 'on',
- ],
- 'author_name' => [
- 'weight' => 0,
- 'enabled' => false,
- ],
+ 'author_name' => [
+ 'weight' => 0,
+ 'enabled' => false,
],
],
];
@@ -109,27 +107,26 @@ public function get_weighting_feature() {
}
/**
- * Test searchable post_types exist after configuration change
+ * Test searchable post_types exist after configuration change with meta mode 'auto'
+ *
+ * @group weighting
+ * @since 5.0.0
*/
- public function testWeightablePostType() {
+ public function test_weightable_post_type_auto() {
$search = ElasticPress\Features::factory()->get_registered_feature( 'search' );
$searchable_post_types = $search->get_searchable_post_types();
$weighting_settings = [
- 'weighting' => [
- 'post' => [
- 'post_title' => [
- 'enabled' => 'on',
- 'weight' => 1,
- ],
+ 'post' => [
+ 'post_title' => [
+ 'enabled' => 'on',
+ 'weight' => 1,
],
],
];
- $this->get_weighting_feature()->save_weighting_configuration( $weighting_settings );
-
- $weighting_configuration = $this->get_weighting_feature()->get_weighting_configuration();
+ $weighting_configuration = $this->save_weighting_configuration( $weighting_settings );
$this->assertEquals( count( $searchable_post_types ), count( array_keys( $weighting_configuration ) ) );
@@ -138,9 +135,22 @@ public function testWeightablePostType() {
/**
* Test settings toggle
+ *
+ * @since 5.0.0
+ * @group weighting
+ * @expectedIncorrectUsage ElasticPress\Feature\Search\Weighting::save_weighting_configuration
*/
- public function testWeightingConfiguration() {
+ public function test_weighting_configuration_deprecated() {
+ $this->get_weighting_feature()->save_weighting_configuration( [] );
+ }
+ /**
+ * Test saving weighting configuration
+ *
+ * @since 5.0.0
+ * @group weighting
+ */
+ public function test_weighting_configuration() {
$weighting_ep_test = $this->get_weighting_feature()->get_post_type_default_settings( 'ep_test' );
$this->assertEquals( true, $weighting_ep_test['post_title']['enabled'] );
@@ -148,26 +158,24 @@ public function testWeightingConfiguration() {
$this->assertEmpty( $weighting_configuration );
$weighting_settings = [
- 'weighting' => [
- 'post' => [
- 'post_title' => [
- 'enabled' => 'on',
- 'weight' => 1,
- ],
+ 'post' => [
+ 'post_title' => [
+ 'enabled' => true,
+ 'weight' => 1,
],
],
];
// enable post_title weighting
- $this->get_weighting_feature()->save_weighting_configuration( $weighting_settings );
- $weighting_configuration = $this->get_weighting_feature()->get_weighting_configuration();
+
+ $weighting_configuration = $this->save_weighting_configuration( $weighting_settings );
$this->assertEquals( true, $weighting_configuration['post']['post_title']['enabled'] );
$this->assertEquals( 1, $weighting_configuration['post']['post_title']['weight'] );
// disable post_title weighting
- $weighting_settings['weighting']['post']['post_title']['enabled'] = '';
- $this->get_weighting_feature()->save_weighting_configuration( $weighting_settings );
- $weighting_configuration = $this->get_weighting_feature()->get_weighting_configuration();
+ $weighting_settings['post']['post_title']['enabled'] = false;
+
+ $weighting_configuration = $this->save_weighting_configuration( $weighting_settings );
$this->assertEquals( false, $weighting_configuration['post']['post_title']['enabled'] );
}
@@ -203,8 +211,7 @@ function ( $taxs, $post_type ) {
$this->assertTrue( $post_default_config['terms.post_format.name']['enabled'] );
// `$this->weighting_settings` does not have post_format. So, once saved, the configuration should not have it enabled too.
- $this->get_weighting_feature()->save_weighting_configuration( $this->weighting_settings );
- $weighting_configuration = $this->get_weighting_feature()->get_weighting_configuration();
+ $weighting_configuration = $this->save_weighting_configuration( $this->weighting_settings );
$this->assertArrayNotHasKey( 'post_format', $weighting_configuration['post'] );
$this->assertArrayNotHasKey( 'terms.post_format.name', $weighting_configuration['post'] );
}
@@ -215,7 +222,7 @@ function ( $taxs, $post_type ) {
public function testGetWeightableFieldsForPostType() {
$fields = $this->get_weighting_feature()->get_weightable_fields_for_post_type( 'ep_test' );
- $this->assertEquals( 2, count( $fields ) );
+ $this->assertEquals( 3, count( $fields ) ); // attributes, taxonomies, and ep_metadata
$this->assertContains( 'post_title', array_keys( $fields['attributes']['children'] ) );
$this->assertContains( 'terms.category.name', array_keys( $fields['taxonomies']['children'] ) );
$this->assertContains( 'terms.post_tag.name', array_keys( $fields['taxonomies']['children'] ) );
@@ -247,86 +254,38 @@ public function testRenderSettingsPage() {
$this->get_weighting_feature()->render_settings_page();
$content = ob_get_clean();
- $search = ElasticPress\Features::factory()->get_registered_feature( 'search' );
- $post_types = $search->get_searchable_post_types();
-
- $this->assertStringContainsString( 'Manage Search Fields & Weighting', $content );
-
- foreach ( $post_types as $post_type ) {
- $post_type_object = get_post_type_object( $post_type );
- $this->assertStringContainsString( '' . $post_type_object->labels->menu_name, $content );
- }
- }
-
- /**
- * Test the `render_settings_page` method (success)
- */
- public function testRenderSettingsPageSaveSuccess() {
- $_GET['settings-updated'] = true;
- ob_start();
- $this->get_weighting_feature()->render_settings_page();
- $content = ob_get_clean();
-
- $this->assertStringContainsString( 'Changes Saved', $content );
- }
-
- /**
- * Test the `render_settings_page` method (failed)
- */
- public function testRenderSettingsPageSaveFailed() {
- $_GET['settings-updated'] = false;
- ob_start();
- $this->get_weighting_feature()->render_settings_page();
- $content = ob_get_clean();
-
- $this->assertStringContainsString( 'An error occurred when saving', $content );
+ $this->assertStringContainsString( 'id="ep-weighting-screen"', $content );
}
/**
* Test the `handle_save` method
+ *
+ * @since 5.0.0
+ * @group weighting
+ * @expectedIncorrectUsage ElasticPress\Feature\Search\Weighting::handle_save
*/
- public function testHandleSave() {
- $weighting_class = $this->getMockBuilder( 'ElasticPress\Feature\Search\Weighting' )
- ->setMethods( [ 'redirect' ] )
- ->getMock();
-
- $_POST['ep-weighting-nonce'] = false;
- $this->assertEquals( null, $weighting_class->handle_save() );
-
- // Change to non admin user
- wp_set_current_user( $this->factory->user->create( array( 'role' => 'author' ) ) );
-
- $_POST['ep-weighting-nonce'] = wp_create_nonce( 'save-weighting' );
- $this->assertEquals( null, $weighting_class->handle_save() );
-
- wp_set_current_user( $this->factory->user->create( array( 'role' => 'administrator' ) ) );
- $_POST = [
- 'ep-weighting-nonce' => wp_create_nonce( 'save-weighting' ),
- 'weighting' => [
- 'post' => [
- 'post_title' => [
- 'enabled' => 'on',
- 'weight' => 1,
- ],
- ],
- ],
- ];
-
- $weighting_class->expects( $this->once() )->method( 'redirect' );
- $weighting_class->handle_save();
+ public function test_handle_save() {
+ $this->get_weighting_feature()->handle_save();
}
/**
* Test the `save_weighting_configuration` method (invalid post type)
+ *
+ * @group weighting
*/
public function testSaveWeightingConfigurationInvalidPostType() {
+ add_filter(
+ 'ep_meta_mode',
+ function () {
+ return 'auto';
+ }
+ );
+
$weighting_settings = [
- 'weighting' => [
- 'post' => [
- 'post_title' => [
- 'enabled' => 'on',
- 'weight' => 1,
- ],
+ 'post' => [
+ 'post_title' => [
+ 'enabled' => 'on',
+ 'weight' => 1,
],
],
];
@@ -345,7 +304,7 @@ function( $config ) {
}
);
- $this->assertNotContains( 'invalid_post_type', $this->get_weighting_feature()->save_weighting_configuration( $weighting_settings ) );
+ $this->assertNotContains( 'invalid_post_type', array_keys( $this->save_weighting_configuration( $weighting_settings ) ) );
}
/**
@@ -353,13 +312,16 @@ function( $config ) {
*/
public function testRecursivelyInjectWeightsToFieldsInvalidArgs() {
$invalid_args = '';
- $this->assertEquals( null, $this->get_weighting_feature()->recursively_inject_weights_to_fields( $invalid_args, $this->weighting_settings['weighting']['post'] ) );
+ $this->assertEquals( null, $this->get_weighting_feature()->recursively_inject_weights_to_fields( $invalid_args, $this->weighting_settings['post'] ) );
}
/**
* Test the `post_type_has_fields` method
+ *
+ * @since 5.0.0
+ * @group weighting
*/
- public function testPostTypeHasFieldsWithDefaultConfig() {
+ public function test_post_type_has_fields_with_default_config() {
$this->assertTrue( $this->get_weighting_feature()->post_type_has_fields( 'post' ) );
}
@@ -369,16 +331,14 @@ public function testPostTypeHasFieldsWithDefaultConfig() {
public function testPostTypeHasFieldsWithCustomConfig() {
// Test with configuration saved for post only, page will return false.
$weighting_settings = [
- 'weighting' => [
- 'post' => [
- 'post_title' => [
- 'enabled' => 'on',
- 'weight' => 1,
- ],
+ 'post' => [
+ 'post_title' => [
+ 'enabled' => 'on',
+ 'weight' => 1,
],
],
];
- $this->get_weighting_feature()->save_weighting_configuration( $weighting_settings );
+ $this->save_weighting_configuration( $weighting_settings );
$this->assertTrue( $this->get_weighting_feature()->post_type_has_fields( 'post' ) );
$this->assertFalse( $this->get_weighting_feature()->post_type_has_fields( 'page' ) );
@@ -459,9 +419,12 @@ public function testDoWeightingWithDefaultConfig() {
/**
* Test the `do_weighting` method (with the custom config)
+ *
+ * @since 5.0.0
+ * @group weighting
*/
- public function testDoWeightingWithCustomConfig() {
- $this->get_weighting_feature()->save_weighting_configuration( $this->weighting_settings );
+ public function test_do_weighting_with_custom_config() {
+ $this->save_weighting_configuration( $this->weighting_settings );
$new_formatted_args = $this->get_weighting_feature()->do_weighting( ...$this->getArgs() );
@@ -529,4 +492,19 @@ public function testApplyFilterWhenWeightingConfigWasNotSaved() {
['bool']['should'][0]['multi_match'];
$this->assertEquals( [ 'post_content_filtered^40' ], $query_multi_match['fields'] );
}
+
+ /**
+ * Save the weighting configuration using the REST API endpoint
+ *
+ * @param array $settings New settings
+ * @return array
+ */
+ protected function save_weighting_configuration( $settings ) {
+ $request = new \WP_REST_Request( 'POST', '/elasticpress/v1/update_weighting' );
+ $request->set_header( 'Content-Type', 'application/json' );
+ $request->set_body( wp_json_encode( $settings ) );
+ $this->get_weighting_feature()->update_weighting( $request );
+
+ return $this->get_weighting_feature()->get_weighting_configuration();
+ }
}
diff --git a/tests/php/indexables/TestPost.php b/tests/php/indexables/TestPost.php
index 1d387ecc88..412e9936b5 100644
--- a/tests/php/indexables/TestPost.php
+++ b/tests/php/indexables/TestPost.php
@@ -50,6 +50,25 @@ public function set_up() {
// Need to call this since it's hooked to init
ElasticPress\Features::factory()->get_registered_feature( 'search' )->search_setup();
+
+ // Allow some meta fields to be indexed.
+ add_filter(
+ 'ep_prepare_meta_allowed_keys',
+ function( $allowed_metakeys ) {
+ return array_merge(
+ $allowed_metakeys,
+ [
+ 'test_key',
+ 'test_key1',
+ 'test_key2',
+ 'test_key3',
+ 'test_key4',
+ 'test_key5',
+ 'test_key6',
+ ]
+ );
+ }
+ );
}
/**
@@ -3443,21 +3462,21 @@ public function testMetaQueryMultipleArray() {
$this->ep_factory->post->create(
array(
'post_content' => 'findme',
- 'meta_input' => array( 'meta_key_1' => '1' ),
+ 'meta_input' => array( 'test_key1' => '1' ),
)
);
$this->ep_factory->post->create(
array(
'post_content' => 'findme',
- 'meta_input' => array( 'meta_key_1' => '1' ),
+ 'meta_input' => array( 'test_key1' => '1' ),
)
);
$this->ep_factory->post->create(
array(
'post_content' => 'findme',
'meta_input' => array(
- 'meta_key_1' => '1',
- 'meta_key_2' => '4',
+ 'test_key1' => '1',
+ 'test_key2' => '4',
),
)
);
@@ -3465,8 +3484,8 @@ public function testMetaQueryMultipleArray() {
array(
'post_content' => 'findme',
'meta_input' => array(
- 'meta_key_1' => '1',
- 'meta_key_2' => '0',
+ 'test_key1' => '1',
+ 'test_key2' => '0',
),
)
);
@@ -3474,8 +3493,8 @@ public function testMetaQueryMultipleArray() {
array(
'post_content' => 'findme',
'meta_input' => array(
- 'meta_key_1' => '1',
- 'meta_key_3' => '4',
+ 'test_key1' => '1',
+ 'test_key3' => '4',
),
)
);
@@ -3486,7 +3505,7 @@ public function testMetaQueryMultipleArray() {
's' => 'findme',
'meta_query' => array(
array(
- 'key' => 'meta_key_2',
+ 'key' => 'test_key2',
'value' => '0',
'compare' => '>=',
),
@@ -3504,18 +3523,18 @@ public function testMetaQueryMultipleArray() {
'meta_query' => array(
'relation' => 'AND',
array(
- 'key' => 'meta_key_1',
+ 'key' => 'test_key1',
'value' => '1',
),
array(
'relation' => 'OR',
array(
- 'key' => 'meta_key_2',
+ 'key' => 'test_key2',
'value' => '2',
'compare' => '>=',
),
array(
- 'key' => 'meta_key_3',
+ 'key' => 'test_key3',
'value' => '4',
),
),
@@ -3836,9 +3855,9 @@ public function testPrepareMeta() {
'value 2',
);
- add_post_meta( $post_id, 'test_meta_1', 'value 1' );
- add_post_meta( $post_id, 'test_meta_1', 'value 2' );
- add_post_meta( $post_id, 'test_meta_1', $meta_values );
+ add_post_meta( $post_id, 'test_key1', 'value 1' );
+ add_post_meta( $post_id, 'test_key1', 'value 2' );
+ add_post_meta( $post_id, 'test_key1', $meta_values );
add_post_meta( $post_id, '_test_private_meta_1', 'value 1' );
add_post_meta( $post_id, '_test_private_meta_1', 'value 2' );
add_post_meta( $post_id, '_test_private_meta_1', $meta_values );
@@ -3849,17 +3868,116 @@ public function testPrepareMeta() {
$meta_2 = ElasticPress\Indexables::factory()->get( 'post' )->prepare_meta( $post );
+ add_filter(
+ 'ep_meta_mode',
+ function () {
+ return 'auto';
+ }
+ );
add_filter( 'ep_prepare_meta_excluded_public_keys', array( $this, 'filter_ep_prepare_meta_excluded_public_keys' ) );
$meta_3 = ElasticPress\Indexables::factory()->get( 'post' )->prepare_meta( $post );
$this->assertTrue( is_array( $meta_1 ) && 1 === count( $meta_1 ) );
- $this->assertTrue( is_array( $meta_1 ) && array_key_exists( 'test_meta_1', $meta_1 ) );
+ $this->assertTrue( is_array( $meta_1 ) && array_key_exists( 'test_key1', $meta_1 ) );
$this->assertTrue( is_array( $meta_2 ) && 2 === count( $meta_2 ) );
- $this->assertTrue( is_array( $meta_2 ) && array_key_exists( 'test_meta_1', $meta_2 ) && array_key_exists( '_test_private_meta_1', $meta_2 ) );
+ $this->assertTrue( is_array( $meta_2 ) && array_key_exists( 'test_key1', $meta_2 ) && array_key_exists( '_test_private_meta_1', $meta_2 ) );
$this->assertTrue( is_array( $meta_3 ) && 1 === count( $meta_3 ) );
$this->assertTrue( is_array( $meta_3 ) && array_key_exists( '_test_private_meta_1', $meta_3 ) );
+ }
+
+ /**
+ * Test to verify meta array is built correctly when meta handling is set as "Manual" in the weighting dashboard.
+ *
+ * @since 5.0.0
+ * @group post
+ */
+ public function testPrepareMetaManual() {
+ if ( $this->is_network_activate() ) {
+ $this->markTestSkipped();
+ }
+
+ $change_meta_mode = function() {
+ return 'manual';
+ };
+ add_filter( 'ep_meta_mode', $change_meta_mode );
+
+ $weighting = ElasticPress\Features::factory()->get_registered_feature( 'search' )->weighting;
+ $this->assertSame( $weighting->get_meta_mode(), 'manual' );
+
+ // Set default weighting
+ $weighting_default = $weighting->get_weighting_configuration_with_defaults();
+
+ $set_default_weighting = function() use ( $weighting_default ) {
+ return $weighting_default;
+ };
+
+ add_filter( 'ep_weighting_configuration', $set_default_weighting );
+
+ $post_id = $this->ep_factory->post->create(
+ [
+ 'meta_input' => [
+ 'not_allowed_key1' => 'value 1',
+ 'not_allowed_key2' => 'value 2',
+ '_test_private_meta_1' => 'private value 1',
+ '_test_private_meta_2' => 'private value 2',
+ ],
+ ]
+ );
+
+ $post = get_post( $post_id );
+
+ $prepared_meta = ElasticPress\Indexables::factory()->get( 'post' )->prepare_meta( $post );
+ $this->assertEmpty( $prepared_meta );
+
+ /**
+ * Test addition via the ep_prepare_meta_allowed_protected_keys filter.
+ */
+ $add_meta_via_allowed_protected = function( $fields, $post ) {
+ $this->assertInstanceOf( '\WP_Post', $post );
+ $this->assertIsArray( $fields );
+ return [ '_test_private_meta_1' ];
+ };
+ add_filter( 'ep_prepare_meta_allowed_protected_keys', $add_meta_via_allowed_protected, 10, 2 );
+
+ $prepared_meta = ElasticPress\Indexables::factory()->get( 'post' )->prepare_meta( $post );
+ $this->assertSame( [ '_test_private_meta_1' ], array_keys( $prepared_meta ) );
+
+ /**
+ * Test addition via the ep_prepare_meta_allowed_keys filter.
+ */
+ $add_meta_via_allowed = function( $fields, $post ) {
+ $this->assertInstanceOf( '\WP_Post', $post );
+ $this->assertIsArray( $fields );
+ $fields[] = 'not_allowed_key1';
+ return $fields;
+ };
+ add_filter( 'ep_prepare_meta_allowed_keys', $add_meta_via_allowed, 10, 2 );
+
+ $prepared_meta = ElasticPress\Indexables::factory()->get( 'post' )->prepare_meta( $post );
+ $this->assertSame( [ 'not_allowed_key1', '_test_private_meta_1' ], array_keys( $prepared_meta ) );
+
+ // Set changed weighting
+ remove_filter( 'ep_weighting_configuration', $set_default_weighting );
+ $set_changed_weighting = function() use ( $weighting_default ) {
+ $weighting_default['post']['meta.test_key2.value'] = [
+ 'enabled' => true,
+ 'weight' => 1,
+ ];
+ $weighting_default['post']['meta._test_private_meta_2.value'] = [
+ 'enabled' => true,
+ 'weight' => 1,
+ ];
+ return $weighting_default;
+ };
+ add_filter( 'ep_weighting_configuration', $set_changed_weighting );
+
+ $prepared_meta = ElasticPress\Indexables::factory()->get( 'post' )->prepare_meta( $post );
+ $this->assertSame(
+ [ 'not_allowed_key1', '_test_private_meta_1', '_test_private_meta_2' ],
+ array_keys( $prepared_meta )
+ );
}
/**
@@ -3884,7 +4002,7 @@ public function filter_ep_prepare_meta_allowed_protected_keys( $meta_keys ) {
*/
public function filter_ep_prepare_meta_excluded_public_keys( $meta_keys ) {
- $meta_keys[] = 'test_meta_1';
+ $meta_keys[] = 'test_key1';
return $meta_keys;
@@ -3906,7 +4024,7 @@ public function testEmptyMetaKey() {
'value 1',
'value 2',
);
- add_post_meta( $post_id, 'test_meta_1', $meta_values );
+ add_post_meta( $post_id, 'test_key1', $meta_values );
$wpdb->insert(
$wpdb->postmeta,
@@ -3926,7 +4044,7 @@ public function testEmptyMetaKey() {
$this->assertIsArray( $meta_data );
$this->assertCount( 1, $meta_data );
- $this->assertArrayHasKey( 'test_meta_1', $meta_data );
+ $this->assertArrayHasKey( 'test_key1', $meta_data );
}
/**
@@ -4085,8 +4203,8 @@ public function testMetaKeyQueryMix() {
array(
'post_content' => 'post content findme',
'meta_input' => array(
- 'test_key' => 5,
- 'test_key_2' => 'aaa',
+ 'test_key' => 5,
+ 'test_key2' => 'aaa',
),
)
);
@@ -4098,7 +4216,7 @@ public function testMetaKeyQueryMix() {
'meta_value_num' => 5,
'meta_query' => array(
array(
- 'key' => 'test_key_2',
+ 'key' => 'test_key2',
'value' => 'aaa',
),
),
@@ -6789,7 +6907,7 @@ public function testParseOrderbyMetaValueParams( $meta_value_type, $es_type, $me
$posts = [];
foreach ( $meta_values as $value ) {
- $posts[] = $this->ep_factory->post->create( [ 'meta_input' => [ 'custom_meta_key' => $value ] ] );
+ $posts[] = $this->ep_factory->post->create( [ 'meta_input' => [ 'test_key' => $value ] ] );
}
ElasticPress\Elasticsearch::factory()->refresh_indices();
@@ -6798,14 +6916,14 @@ public function testParseOrderbyMetaValueParams( $meta_value_type, $es_type, $me
'fields' => 'ids',
'orderby' => 'meta_value' . ( $meta_value_type ? "_{$meta_value_type}" : '' ),
'order' => 'asc',
- 'meta_key' => 'custom_meta_key',
+ 'meta_key' => 'test_key',
];
$assert_callback = function( $args ) use ( &$method_executed, $es_type ) {
$method_executed = true;
- $this->assertArrayHasKey( "meta.custom_meta_key.{$es_type}", $args['sort'][0] );
- $this->assertSame( 'asc', $args['sort'][0][ "meta.custom_meta_key.{$es_type}" ]['order'] );
+ $this->assertArrayHasKey( "meta.test_key.{$es_type}", $args['sort'][0] );
+ $this->assertSame( 'asc', $args['sort'][0][ "meta.test_key.{$es_type}" ]['order'] );
return $args;
};
@@ -6840,7 +6958,7 @@ public function testParseOrderbyMetaValueWithoutMetaKeyParams( $meta_value_type,
'order' => 'asc',
'meta_query' => [
[
- 'key' => 'custom_meta_key',
+ 'key' => 'test_key',
'compare' => 'EXISTS',
],
],
@@ -6849,8 +6967,8 @@ public function testParseOrderbyMetaValueWithoutMetaKeyParams( $meta_value_type,
$assert_callback = function( $args ) use ( &$method_executed, $es_type ) {
$method_executed = true;
- $this->assertArrayHasKey( "meta.custom_meta_key.{$es_type}", $args['sort'][0] );
- $this->assertSame( 'asc', $args['sort'][0][ "meta.custom_meta_key.{$es_type}" ]['order'] );
+ $this->assertArrayHasKey( "meta.test_key.{$es_type}", $args['sort'][0] );
+ $this->assertSame( 'asc', $args['sort'][0][ "meta.test_key.{$es_type}" ]['order'] );
return $args;
};
@@ -6882,11 +7000,11 @@ public function testParseOrderbyMetaQueryTypes( $meta_value_type, $es_type ) {
'order' => 'asc',
'meta_query' => [
[
- 'key' => 'unused_key',
+ 'key' => 'test_key1',
'type' => 'NUMERIC',
],
'named_clause' => [
- 'key' => 'custom_meta_key',
+ 'key' => 'test_key',
'type' => $meta_value_type,
],
],
@@ -6895,8 +7013,8 @@ public function testParseOrderbyMetaQueryTypes( $meta_value_type, $es_type ) {
$assert_callback = function( $args ) use ( &$method_executed, $es_type ) {
$method_executed = true;
- $this->assertArrayHasKey( "meta.custom_meta_key.{$es_type}", $args['sort'][0] );
- $this->assertSame( 'asc', $args['sort'][0][ "meta.custom_meta_key.{$es_type}" ]['order'] );
+ $this->assertArrayHasKey( "meta.test_key.{$es_type}", $args['sort'][0] );
+ $this->assertSame( 'asc', $args['sort'][0][ "meta.test_key.{$es_type}" ]['order'] );
return $args;
};
@@ -7337,7 +7455,7 @@ public function testPostSyncQueueEPKill() {
// Turn on the filter to kill syncing.
add_filter( 'ep_post_sync_kill', '__return_true' );
- update_post_meta( $post_id, 'custom_key', 123 );
+ update_post_meta( $post_id, 'test_key', 123 );
// Make sure sync queue is still empty when meta is updated for
// an existing post.
@@ -7356,7 +7474,7 @@ public function testPostSyncQueueEPKill() {
remove_filter( 'ep_post_sync_kill', '__return_true' );
// Now verify the queue when this filter is not enabled.
- update_post_meta( $post_id, 'custom_key', 456 );
+ update_post_meta( $post_id, 'test_key', 456 );
$this->assertNotEmpty( ElasticPress\Indexables::factory()->get( 'post' )->sync_manager->get_sync_queue() );
@@ -7560,8 +7678,8 @@ public function testDeleteAllMetadata() {
array(
'post_title' => 'one',
'meta_input' => array(
- 'common_meta_one' => 'lorem',
- 'common_meta_two' => 'ipsum',
+ 'test_key1' => 'lorem',
+ 'test_key2' => 'ipsum',
),
)
);
@@ -7569,13 +7687,13 @@ public function testDeleteAllMetadata() {
array(
'post_title' => 'two',
'meta_input' => array(
- 'common_meta_one' => 'lorem',
- 'common_meta_two' => 'ipsum',
+ 'test_key1' => 'lorem',
+ 'test_key2' => 'ipsum',
),
)
);
- delete_metadata( 'post', null, 'common_meta_one', 'lorem', true );
+ delete_metadata( 'post', null, 'test_key1', 'lorem', true );
ElasticPress\Indexables::factory()->get( 'post' )->sync_manager->index_sync_queue();
ElasticPress\Elasticsearch::factory()->refresh_indices();
@@ -7584,7 +7702,7 @@ public function testDeleteAllMetadata() {
array(
'post_type' => 'post',
'ep_integrate' => true,
- 'meta_key' => 'common_meta_one',
+ 'meta_key' => 'test_key1',
'meta_value' => 'lorem',
)
);
@@ -7596,7 +7714,7 @@ public function testDeleteAllMetadata() {
array(
'post_type' => 'post',
'ep_integrate' => true,
- 'meta_key' => 'common_meta_two',
+ 'meta_key' => 'test_key2',
'meta_value' => 'ipsum',
)
);
@@ -7913,6 +8031,12 @@ public function testIsMetaAllowed() {
$meta_protected = '_meta';
$meta_protected_allowed = '_meta_allowed';
+ add_filter(
+ 'ep_prepare_meta_allowed_keys',
+ function( $allowed_metakeys ) {
+ return array_merge( $allowed_metakeys, [ 'meta' ] );
+ }
+ );
add_filter(
'ep_prepare_meta_allowed_protected_keys',
function () use ( $meta_protected_allowed ) {
@@ -7927,12 +8051,13 @@ function () use ( $meta_not_protected_excluded ) {
);
$indexable = \ElasticPress\Indexables::factory()->get( 'post' );
+ $post = new \WP_Post( (object) [ 'post_type' => 'post' ] );
- $this->assertTrue( $indexable->is_meta_allowed( $meta_not_protected, null ) );
- $this->assertTrue( $indexable->is_meta_allowed( $meta_protected_allowed, null ) );
+ $this->assertTrue( $indexable->is_meta_allowed( $meta_not_protected, $post ) );
+ $this->assertTrue( $indexable->is_meta_allowed( $meta_protected_allowed, $post ) );
- $this->assertFalse( $indexable->is_meta_allowed( $meta_not_protected_excluded, null ) );
- $this->assertFalse( $indexable->is_meta_allowed( $meta_protected, null ) );
+ $this->assertFalse( $indexable->is_meta_allowed( $meta_not_protected_excluded, $post ) );
+ $this->assertFalse( $indexable->is_meta_allowed( $meta_protected, $post ) );
}
/**
@@ -7944,16 +8069,16 @@ function () use ( $meta_not_protected_excluded ) {
public function testGetDistinctMetaFieldKeys() {
$indexable = \ElasticPress\Indexables::factory()->get( 'post' );
- $this->ep_factory->post->create( array( 'meta_input' => array( 'new_meta_key_1' => '' ) ) );
- $this->ep_factory->post->create( array( 'meta_input' => array( 'new_meta_key_2' => '' ) ) );
+ $this->ep_factory->post->create( array( 'meta_input' => array( 'test_key1' => '' ) ) );
+ $this->ep_factory->post->create( array( 'meta_input' => array( 'test_key2' => '' ) ) );
ElasticPress\Elasticsearch::factory()->refresh_indices();
$distinct_meta_field_keys = $indexable->get_distinct_meta_field_keys();
$this->assertIsArray( $distinct_meta_field_keys );
- $this->assertContains( 'new_meta_key_1', $distinct_meta_field_keys );
- $this->assertContains( 'new_meta_key_2', $distinct_meta_field_keys );
+ $this->assertContains( 'test_key1', $distinct_meta_field_keys );
+ $this->assertContains( 'test_key2', $distinct_meta_field_keys );
}
/**
@@ -7965,36 +8090,36 @@ public function testGetDistinctMetaFieldKeys() {
public function testGetAllDistinctValues() {
$indexable = \ElasticPress\Indexables::factory()->get( 'post' );
- $this->ep_factory->post->create( array( 'meta_input' => array( 'new_meta_key_1' => 'foo' ) ) );
- $this->ep_factory->post->create( array( 'meta_input' => array( 'new_meta_key_1' => 'bar' ) ) );
- $this->ep_factory->post->create( array( 'meta_input' => array( 'new_meta_key_1' => 'foobar' ) ) );
+ $this->ep_factory->post->create( array( 'meta_input' => array( 'test_key1' => 'foo' ) ) );
+ $this->ep_factory->post->create( array( 'meta_input' => array( 'test_key1' => 'bar' ) ) );
+ $this->ep_factory->post->create( array( 'meta_input' => array( 'test_key1' => 'foobar' ) ) );
- $this->ep_factory->post->create( array( 'meta_input' => array( 'new_meta_key_2' => 'lorem' ) ) );
- $this->ep_factory->post->create( array( 'meta_input' => array( 'new_meta_key_2' => 'ipsum' ) ) );
+ $this->ep_factory->post->create( array( 'meta_input' => array( 'test_key2' => 'lorem' ) ) );
+ $this->ep_factory->post->create( array( 'meta_input' => array( 'test_key2' => 'ipsum' ) ) );
ElasticPress\Elasticsearch::factory()->refresh_indices();
- $distinct_values = $indexable->get_all_distinct_values( 'meta.new_meta_key_1.raw' );
+ $distinct_values = $indexable->get_all_distinct_values( 'meta.test_key1.raw' );
$this->assertCount( 3, $distinct_values );
$this->assertContains( 'foo', $distinct_values );
$this->assertContains( 'bar', $distinct_values );
$this->assertContains( 'foobar', $distinct_values );
- $distinct_values = $indexable->get_all_distinct_values( 'meta.new_meta_key_1.raw', 1 );
+ $distinct_values = $indexable->get_all_distinct_values( 'meta.test_key1.raw', 1 );
$this->assertCount( 1, $distinct_values );
$this->assertContains( 'bar', $distinct_values );
$change_bucket_size = function( $count, $field ) {
- return ( 'meta.new_meta_key_1.raw' === $field ) ? 1 : $count;
+ return ( 'meta.test_key1.raw' === $field ) ? 1 : $count;
};
add_filter( 'ep_post_all_distinct_values', $change_bucket_size, 10, 2 );
- $distinct_values_1 = $indexable->get_all_distinct_values( 'meta.new_meta_key_1.raw' );
+ $distinct_values_1 = $indexable->get_all_distinct_values( 'meta.test_key1.raw' );
$this->assertCount( 1, $distinct_values_1 );
$this->assertContains( 'bar', $distinct_values_1 );
- $distinct_values_2 = $indexable->get_all_distinct_values( 'meta.new_meta_key_2.raw' );
+ $distinct_values_2 = $indexable->get_all_distinct_values( 'meta.test_key2.raw' );
$this->assertCount( 2, $distinct_values_2 );
$this->assertContains( 'lorem', $distinct_values_2 );
$this->assertContains( 'ipsum', $distinct_values_2 );
@@ -8465,7 +8590,7 @@ public function testGetDistinctMetaFieldKeysDbPerPostType() {
$this->setupDistinctMetaFieldKeysDbPerPostType();
- $meta_keys = [ '_private_key', 'test_key_1', 'test_key_2' ];
+ $meta_keys = [ '_private_key', 'test_key1', 'test_key2' ];
$this->assertSame( $meta_keys, $indexable->get_distinct_meta_field_keys_db_per_post_type( 'ep_test' ) );
/**
@@ -8547,8 +8672,8 @@ public function testGetIndexableMetaKeysPerPostType() {
'post_type' => 'ep_test',
'meta_input' => [
'_private_key' => 'private-meta',
- 'test_key_1' => 'meta value 1',
- 'test_key_2' => 'meta value 2.1',
+ 'test_key1' => 'meta value 1',
+ 'test_key2' => 'meta value 2.1',
],
]
);
@@ -8556,21 +8681,21 @@ public function testGetIndexableMetaKeysPerPostType() {
[
'post_type' => 'ep_test_2',
'meta_input' => [
- 'test_key_2' => 'meta value 2.2',
- 'test_key_3' => 'meta value 3',
+ 'test_key2' => 'meta value 2.2',
+ 'test_key3' => 'meta value 3',
],
]
);
- $meta_keys = [ 'test_key_1', 'test_key_2' ];
+ $meta_keys = [ 'test_key1', 'test_key2' ];
$this->assertEqualsCanonicalizing( $meta_keys, $indexable->get_indexable_meta_keys_per_post_type( 'ep_test' ) );
$change_allowed_meta = function () {
- return [ 'test_key_1' => 'meta value 1' ];
+ return [ 'test_key1' => 'meta value 1' ];
};
add_filter( 'ep_prepare_meta_data', $change_allowed_meta );
- $meta_keys = [ 'test_key_1' ];
+ $meta_keys = [ 'test_key1' ];
$this->assertEqualsCanonicalizing( $meta_keys, $indexable->get_indexable_meta_keys_per_post_type( 'ep_test' ) );
}
@@ -8588,8 +8713,8 @@ public function testGetPredictedIndexableMetaKeys() {
'post_type' => 'ep_test',
'meta_input' => [
'_private_key' => 'private-meta',
- 'test_key_1' => 'meta value 1',
- 'test_key_2' => 'meta value 2.1',
+ 'test_key1' => 'meta value 1',
+ 'test_key2' => 'meta value 2.1',
],
]
);
@@ -8597,21 +8722,21 @@ public function testGetPredictedIndexableMetaKeys() {
[
'post_type' => 'ep_test_2',
'meta_input' => [
- 'test_key_2' => 'meta value 2.2',
- 'test_key_3' => 'meta value 3',
+ 'test_key2' => 'meta value 2.2',
+ 'test_key3' => 'meta value 3',
],
]
);
- $meta_keys = [ 'test_key_1', 'test_key_2', 'test_key_3' ];
+ $meta_keys = [ 'test_key1', 'test_key2', 'test_key3' ];
$this->assertEqualsCanonicalizing( $meta_keys, $indexable->get_predicted_indexable_meta_keys() );
$change_allowed_meta = function () {
- return [ 'test_key_1' => 'meta value 1' ];
+ return [ 'test_key1' => 'meta value 1' ];
};
add_filter( 'ep_prepare_meta_data', $change_allowed_meta );
- $meta_keys = [ 'test_key_1' ];
+ $meta_keys = [ 'test_key1' ];
$this->assertEqualsCanonicalizing( $meta_keys, $indexable->get_predicted_indexable_meta_keys() );
}
@@ -8657,8 +8782,8 @@ protected function setupDistinctMetaFieldKeysDbPerPostType() {
'post_type' => 'ep_test',
'meta_input' => [
'_private_key' => 'private-meta',
- 'test_key_1' => 'meta value 1',
- 'test_key_2' => 'meta value 2.1',
+ 'test_key1' => 'meta value 1',
+ 'test_key2' => 'meta value 2.1',
],
]
);
@@ -8666,8 +8791,8 @@ protected function setupDistinctMetaFieldKeysDbPerPostType() {
[
'post_type' => 'ep_test_2',
'meta_input' => [
- 'test_key_2' => 'meta value 2.2',
- 'test_key_3' => 'meta value 3',
+ 'test_key2' => 'meta value 2.2',
+ 'test_key3' => 'meta value 3',
],
]
);
diff --git a/tests/php/screen/TestStatusReport.php b/tests/php/screen/TestStatusReport.php
index 8ce68f74e2..9c63158f25 100644
--- a/tests/php/screen/TestStatusReport.php
+++ b/tests/php/screen/TestStatusReport.php
@@ -236,6 +236,15 @@ public function testIndexableContentReport() {
$meta_fields = array();
$distinct_meta_keys = array();
+ $allow_metakeys = function ( $keys ) use ( $post_types ) {
+ $keys[] = 'shared_meta_key';
+ foreach ( $post_types as $post_type ) {
+ $keys[] = "unique_meta_key_{$post_type}";
+ }
+ return $keys;
+ };
+ add_filter( 'ep_prepare_meta_allowed_keys', $allow_metakeys );
+
foreach ( $post_types as $post_type ) {
$this->ep_factory->post->create_many(
10,
diff --git a/uninstall.php b/uninstall.php
index 95c7cb312a..782eea27cf 100644
--- a/uninstall.php
+++ b/uninstall.php
@@ -44,6 +44,8 @@ class EP_Uninstaller {
'ep_bulk_setting',
'ep_sync_history',
+ 'elasticpress_weighting',
+
// Admin notices options
'ep_hide_host_error_notice',
'ep_hide_es_below_compat_notice',