diff --git a/bin/wp-cli.php b/bin/wp-cli.php index 1df75ba2ee..b244f7c381 100644 --- a/bin/wp-cli.php +++ b/bin/wp-cli.php @@ -1,7 +1,9 @@ $feature ) { if( $feature['active'] ) { WP_CLI::line( $key ); @@ -148,7 +150,7 @@ public function list_features( $args, $assoc_args ) { } else { WP_CLI::line( __( 'Registered features:', 'elasticpress' ) ); $features = wp_list_pluck( EP_Features::factory()->registered_features, 'slug' ); - + foreach ( $features as $feature ) { WP_CLI::line( $feature ); } @@ -507,7 +509,7 @@ private function _index_helper( $args ) { if ( $no_bulk ) { // index the posts one-by-one. not sure why someone may want to do this. $result = ep_sync_post( get_the_ID() ); - + $this->reset_transient(); do_action( 'ep_cli_post_index', get_the_ID() ); @@ -651,7 +653,7 @@ private function bulk_index( $show_bulk_errors = false ) { // decode the response $response = ep_bulk_index_posts( $body ); - + $this->reset_transient(); do_action( 'ep_cli_post_bulk_index', $this->posts ); @@ -688,7 +690,7 @@ private function bulk_index( $show_bulk_errors = false ) { /** * Formatting bulk error message recursively - * + * * @param array $message_array * @since 2.2 * @return string @@ -780,8 +782,9 @@ public function stats() { if (isset( $body['indices'][$current_index] ) ) { WP_CLI::log( '====== Stats for: ' . $current_index . " ======" ); - WP_CLI::log( 'Documents: ' . $body['indices'][$current_index]['total']['docs']['count'] ); - WP_CLI::log( 'Index Size: ' . size_format($body['indices'][$current_index]['total']['store']['size_in_bytes'], 2 ) ); + WP_CLI::log( 'Documents: ' . $body['indices'][$current_index]['primaries']['docs']['count'] ); + WP_CLI::log( 'Index Size: ' . size_format($body['indices'][$current_index]['primaries']['store']['size_in_bytes'], 2 ) ); + WP_CLI::log( 'Index Size (including replicas): ' . size_format($body['indices'][$current_index]['total']['store']['size_in_bytes'], 2 ) ); WP_CLI::log( '====== End Stats ======' ); } else { WP_CLI::warning( $current_index . ' is not currently indexed.' ); @@ -862,14 +865,14 @@ private function stop_the_insanity() { */ private function _connect_check() { $host = ep_get_host(); - + if ( empty( $host) ) { WP_CLI::error( __( 'There is no Elasticsearch host set up. Either add one through the dashboard or define one in wp-config.php', 'elasticpress' ) ); } elseif ( ! ep_get_elasticsearch_version( true ) ) { WP_CLI::error( __( 'Unable to reach Elasticsearch Server! Check that service is running.', 'elasticpress' ) ); } } - + /** * Reset transient while indexing * diff --git a/classes/class-ep-api.php b/classes/class-ep-api.php index b4b0b3e879..8495b30bba 100644 --- a/classes/class-ep-api.php +++ b/classes/class-ep-api.php @@ -333,23 +333,25 @@ public function delete_post( $post_id, $blocking = true ) { * @return array */ public function format_request_headers() { - $headers = array(); + $headers = array( + 'Content-Type' => 'application/json', + ); // Check for ElasticPress API key and add to header if needed. if ( defined( 'EP_API_KEY' ) && EP_API_KEY ) { $headers['X-ElasticPress-API-Key'] = EP_API_KEY; } - /** - * ES Shield Username & Password - * Adds username:password basic authentication headers - * - * Define the constant ES_SHIELD in your wp-config.php - * Format: 'username:password' (colon separated) - * Example: define( 'ES_SHIELD', 'es_admin:password' ); - * - * @since 1.9 - */ + /** + * ES Shield Username & Password + * Adds username:password basic authentication headers + * + * Define the constant ES_SHIELD in your wp-config.php + * Format: 'username:password' (colon separated) + * Example: define( 'ES_SHIELD', 'es_admin:password' ); + * + * @since 1.9 + */ if ( defined( 'ES_SHIELD' ) && ES_SHIELD ) { $headers['Authorization'] = 'Basic ' . base64_encode( ES_SHIELD ); } @@ -692,8 +694,13 @@ private function prepare_terms( $post ) { $allow_hierarchy = apply_filters( 'ep_sync_terms_allow_hierarchy', false ); foreach ( $selected_taxonomies as $taxonomy ) { + // If we get a taxonomy name, we need to convert it to taxonomy object + if ( ! is_object( $taxonomy ) && taxonomy_exists( (string) $taxonomy ) ) { + $taxonomy = get_taxonomy( $taxonomy ); + } + // We check if the $taxonomy object as name property. Backward compatibility since WP_Taxonomy introduced in WP 4.7 - if ( ! property_exists( $taxonomy, 'name' ) ) { + if ( ! is_a( $taxonomy, '\WP_Taxonomy' ) || ! property_exists( $taxonomy, 'name' ) ) { continue; } diff --git a/classes/class-ep-features.php b/classes/class-ep-features.php index ca8fe99f0c..e9bfc63a8e 100644 --- a/classes/class-ep-features.php +++ b/classes/class-ep-features.php @@ -14,7 +14,7 @@ class EP_Features { /** * Stores all features that have been properly included (both active and inactive) - * + * * @since 2.1 * @var array */ @@ -22,35 +22,36 @@ class EP_Features { /** * Initiate class actions - * + * * @since 2.1 */ public function setup() { - add_action( 'plugins_loaded', array( $this, 'handle_feature_activation' ), 12 ); + // hooks order matters, please, make sure feature activation goes before features setup + add_action( 'init', array( $this, 'handle_feature_activation' ), 0 ); add_action( 'init', array( $this, 'setup_features' ), 0 ); } /** * Registers a feature for use in ElasticPress - * + * * @param string $slug * @param array $feature_args - * + * * Supported array parameters: - * + * * "title" (string) - Pretty title for feature * "default_settings" (array) - Array of default settings. Only needed if you plan on adding custom settings * "requirements_status_cb" (callback) - Callback to a function that determines the "requirements" status of - * the given feature. 0 means everything is okay. 1 means the feature can be used but there is a warning. - * 2 means the feature cannot be active. This callback needs to return an EP_Feature_Requirements_Status + * the given feature. 0 means everything is okay. 1 means the feature can be used but there is a warning. + * 2 means the feature cannot be active. This callback needs to return an EP_Feature_Requirements_Status * object where the "code" property is one of the values above. * "setup_cb" (callback) - Callback to a function to be called on each page load when the feature is activated * "post_activation_cb" (callback) - Callback to a function to be called after a feature is first activated * "feature_box_summary_cb" (callback) - Callback to a function that outputs HTML feature box summary (short description of feature) * "feature_box_long_cb" (callback) - Callback to a function that outputs HTML feature box full description * "feature_box_settings_cb" (callback) - Callback to a function that outputs custom feature settings fields - * - * @since 2.1 + * + * @since 2.1 * @return boolean */ public function register_feature( $slug, $feature_args ) { @@ -67,7 +68,7 @@ public function register_feature( $slug, $feature_args ) { /** * Activate or deactivate a feature - * + * * @param string $slug * @param array $settings * @param bool $force @@ -80,7 +81,7 @@ public function update_feature( $slug, $settings, $force = true ) { if ( empty( $feature ) ) { return false; } - + $original_state = $feature->is_active(); if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { @@ -136,7 +137,7 @@ public function update_feature( $slug, $settings, $force = true ) { /** * When plugins are adjusted, we need to determine how to activate/deactivate features - * + * * @since 2.2 */ public function handle_feature_activation() { @@ -175,7 +176,7 @@ public function handle_feature_activation() { if ( false === $feature_settings ) { $registered_features = $this->registered_features; - + foreach ( $registered_features as $slug => $feature ) { if ( 0 === $feature->requirements_status()->code ) { ep_activate_feature( $slug ); @@ -278,7 +279,7 @@ public static function factory() { /** * Main function for registering new feature. Since comment above for details - * + * * @param string $slug * @param array $feature_args * @since 2.1 @@ -290,7 +291,7 @@ function ep_register_feature( $slug, $feature_args ) { /** * Update a feature - * + * * @param string $slug * @param array $settings * @param bool $force @@ -303,7 +304,7 @@ function ep_update_feature( $slug, $settings, $force = true ) { /** * Activate a feature - * + * * @param string $slug * @since 2.2 */ @@ -313,7 +314,7 @@ function ep_activate_feature( $slug ) { /** * Dectivate a feature - * + * * @param string $slug * @param bool $force * @since 2.2 diff --git a/classes/class-ep-wp-query-integration.php b/classes/class-ep-wp-query-integration.php index ab4faaf7cd..b4ec817e8d 100644 --- a/classes/class-ep-wp-query-integration.php +++ b/classes/class-ep-wp-query-integration.php @@ -247,18 +247,7 @@ public function filter_posts_request( $request, $query ) { $query_vars['post_type'] = apply_filters( 'ep_query_post_type', $query_vars['post_type'], $query ); if ( 'any' === $query_vars['post_type'] ) { - unset( $query_vars['post_type'] ); - } - - /** - * If not search and not set default to post. If not set and is search, use searchable post tpyes - */ - if ( empty( $query_vars['post_type'] ) ) { - if ( empty( $query_vars['s'] ) ) { - $query_vars['post_type'] = 'post'; - } else { - $query_vars['post_type'] = array_values( get_post_types( array( 'exclude_from_search' => false ) ) ); - } + $query_vars['post_type'] = 'post'; } if ( empty( $query_vars['post_type'] ) ) { diff --git a/composer.json b/composer.json index 155bf80285..8b4b570750 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Supercharge WordPress with Elasticsearch.", "type": "wordpress-plugin", "keywords": ["wordpress", "plugin", "elasticsearch", "elasticpress", "search"], - "license": ["GPLv2"], + "license": ["GPL-2.0-only"], "authors": [ { "name": "Aaron Holbrook", diff --git a/elasticpress.php b/elasticpress.php index 804227edcf..62a4b3222c 100644 --- a/elasticpress.php +++ b/elasticpress.php @@ -3,7 +3,7 @@ /** * Plugin Name: ElasticPress * Description: A fast and flexible search and query engine for WordPress. - * Version: 2.4 + * Version: 2.4.1 * Author: Taylor Lovett, Matt Gross, Aaron Holbrook, 10up * Author URI: http://10up.com * License: GPLv2 or later @@ -22,7 +22,7 @@ define( 'EP_URL', plugin_dir_url( __FILE__ ) ); define( 'EP_PATH', plugin_dir_path( __FILE__ ) ); -define( 'EP_VERSION', '2.4' ); +define( 'EP_VERSION', '2.4.1' ); /** * We compare the current ES version to this compatibility version number. Compatibility is true when: @@ -33,7 +33,7 @@ * * @since 2.2 */ -define( 'EP_ES_VERSION_MAX', '5.6' ); +define( 'EP_ES_VERSION_MAX', '6.1' ); define( 'EP_ES_VERSION_MIN', '1.7' ); require_once( 'classes/class-ep-config.php' ); @@ -102,6 +102,7 @@ function ep_handle_upgrades() { $reindex_versions = apply_filters( 'ep_reindex_versions', array( '2.2', '2.3.1', + '2.4', ) ); $need_upgrade_sync = false; diff --git a/features/autosuggest/assets/js/autosuggest.min.js b/features/autosuggest/assets/js/autosuggest.min.js index 21803be6d5..80d3f958d2 100644 --- a/features/autosuggest/assets/js/autosuggest.min.js +++ b/features/autosuggest/assets/js/autosuggest.min.js @@ -1 +1 @@ -!function(e){"use strict";function t(e){e.closest("form").submit()}function s(e,t){e.val(t)}function o(e,t){return window.location.href=t}function a(e,a){if("navigate"===epas.action)return o(e,a.dataset.url);s(e,a.innerText),t(e)}function n(e,t){var s=null;return function(){var o=this,a=arguments;window.clearTimeout(s),s=window.setTimeout(function(){e.apply(o,a)},t)}}function i(e,t,s,o){"all"!==t&&void 0!==t&&""!==t||(t="all"),""===s&&(t="publish");var a={sort:[{_score:{order:"desc"}}],query:{multi_match:{query:e,fields:o}}};return"string"==typeof t&&"all"!==t&&(t=t.split(",")),"string"==typeof s&&(s=s.split(",")),a.post_filter={bool:{must:[{terms:{post_status:s}}]}},"all"!==t&&a.post_filter.bool.must.push({terms:{"post_type.raw":t}}),a}function u(t){return jQuery.support.cors=!0,e.ajax({url:epas.endpointUrl,type:"post",dataType:"json",crossDomain:!0,data:JSON.stringify(t)})}function r(t,s){var o,n=s.closest(".ep-autosuggest-container").find(".ep-autosuggest"),i=n.find(".autosuggest-list");for(i.empty(),e(".autosuggest-item").off(),t.length>0?n.show():n.hide(),o=0;o'+u+"").appendTo(i)}e(".autosuggest-item").on("click",function(e){a(s,e.srcElement)}),s.off("keydown"),s.on("keydown",function(e){if(38!==e.keyCode&&40!==e.keyCode&&13!==e.keyCode);else{var t,o=s.closest(".ep-autosuggest-container").find(".autosuggest-list li"),n=o.filter(".selected");switch(e.keyCode){case 38:t=n.prev();break;case 40:o.hasClass("selected")?t=n.next():(o.first().addClass("selected"),t=o.first());break;case 13:return o.hasClass("selected")?(a(s,n.children("span").get(0)),!1):void 0}if(t.is("li")?(n.removeClass("selected"),t.addClass("selected")):o.removeClass("selected"),38===e.keyCode)return!1}})}function l(){e(".autosuggest-list").empty(),e(".ep-autosuggest").hide()}if(epas.endpointUrl&&""!==epas.endpointUrl){var c=e('.ep-autosuggest, input[type="search"], .search-field'),d=e('
');c.each(function(t,s){var o=e('
'),a=e(s);a.attr("autocomplete","off"),o.insertAfter(a);var n=a.siblings("label");a.closest("form").find(".ep-autosuggest-container").append(n).append(a),d.clone().insertAfter(a),a.trigger("elasticpress.input.moved")}),d.css({top:c.outerHeight()-1,"background-color":c.css("background-color")}),e(c).each(function(t,s){e(s).on("keyup keydown keypress",function(e){38!==e.keyCode&&40!==e.keyCode||e.preventDefault(),27===e.keyCode&&l()})}),c.each(function(t,s){var o=e(s);o.on("keyup",n(function(t){if(38!==t.keyCode&&40!==t.keyCode&&13!==t.keyCode&&27!==t.keyCode){var s=o.val(),a=epas.postType,n=epas.postStatus,c=epas.searchFields;s.length>=2?u(i(s,a,n,c)).done(function(t){if(t._shards.successful>0){var s={},a=[];e.each(t.hits.hits,function(e,t){var o=t._source.post_title,n=t._source.permalink,i=t._source.post_id;s[i]||(s[i]=!0,a.push({text:o,url:n}))}),0===a.length?l():r(a,o)}else l()}):0===s.length&&l()}},200))}),window.epasAPI={hideAutosuggestBox:l,updateAutosuggestBox:r,esSearch:u,buildSearchQuery:i}}}(jQuery); \ No newline at end of file +!function(e){"use strict";function t(e){e.closest("form").submit()}function s(e,t){e.val(t)}function o(e,t){return window.location.href=t}function a(e,a){if("navigate"===epas.action)return o(e,a.dataset.url);s(e,a.innerText),t(e)}function n(e,t){var s=null;return function(){var o=this,a=arguments;window.clearTimeout(s),s=window.setTimeout(function(){e.apply(o,a)},t)}}function i(e,t,s,o){"all"!==t&&void 0!==t&&""!==t||(t="all"),""===s&&(t="publish");var a={sort:[{_score:{order:"desc"}}],query:{multi_match:{query:e,fields:o}}};return"string"==typeof t&&"all"!==t&&(t=t.split(",")),"string"==typeof s&&(s=s.split(",")),a.post_filter={bool:{must:[{terms:{post_status:s}}]}},"all"!==t&&a.post_filter.bool.must.push({terms:{"post_type.raw":t}}),a}function u(t){return jQuery.support.cors=!0,e.ajax({url:epas.endpointUrl,type:"post",dataType:"json",crossDomain:!0,data:JSON.stringify(t)})}function r(t,s){var o,n=s.closest(".ep-autosuggest-container").find(".ep-autosuggest"),i=n.find(".autosuggest-list");for(i.empty(),e(".autosuggest-item").off(),t.length>0?n.show():n.hide(),o=0;o'+u+"").appendTo(i)}e(".autosuggest-item").on("click",function(e){a(s,e.target)}),s.off("keydown"),s.on("keydown",function(e){if(38!==e.keyCode&&40!==e.keyCode&&13!==e.keyCode);else{var t,o=s.closest(".ep-autosuggest-container").find(".autosuggest-list li"),n=o.filter(".selected");switch(e.keyCode){case 38:t=n.prev();break;case 40:o.hasClass("selected")?t=n.next():(o.first().addClass("selected"),t=o.first());break;case 13:return o.hasClass("selected")?(a(s,n.children("span").get(0)),!1):void 0}if(t.is("li")?(n.removeClass("selected"),t.addClass("selected")):o.removeClass("selected"),38===e.keyCode)return!1}})}function l(){e(".autosuggest-list").empty(),e(".ep-autosuggest").hide()}if(epas.endpointUrl&&""!==epas.endpointUrl){var c=e('.ep-autosuggest, input[type="search"], .search-field'),d=e('
    ');c.each(function(t,s){var o=e('
    '),a=e(s);a.attr("autocomplete","off"),o.insertAfter(a);var n=a.siblings("label");a.closest("form").find(".ep-autosuggest-container").append(n).append(a),d.clone().insertAfter(a),a.trigger("elasticpress.input.moved")}),d.css({top:c.outerHeight()-1,"background-color":c.css("background-color")}),e(c).each(function(t,s){e(s).on("keyup keydown keypress",function(e){38!==e.keyCode&&40!==e.keyCode||e.preventDefault(),27===e.keyCode&&l()})}),c.each(function(t,s){var o=e(s);o.on("keyup",n(function(t){if(38!==t.keyCode&&40!==t.keyCode&&13!==t.keyCode&&27!==t.keyCode){var s=o.val(),a=epas.postType,n=epas.postStatus,c=epas.searchFields;s.length>=2?u(i(s,a,n,c)).done(function(t){if(t._shards.successful>0){var s={},a=[];e.each(t.hits.hits,function(e,t){var o=t._source.post_title,n=t._source.permalink,i=t._source.post_id;s[i]||(s[i]=!0,a.push({text:o,url:n}))}),0===a.length?l():r(a,o)}else l()}):0===s.length&&l()}},200))}),window.epasAPI={hideAutosuggestBox:l,updateAutosuggestBox:r,esSearch:u,buildSearchQuery:i}}}(jQuery); \ No newline at end of file diff --git a/features/autosuggest/assets/js/src/autosuggest.js b/features/autosuggest/assets/js/src/autosuggest.js index 1e8d683843..40eb67fc15 100644 --- a/features/autosuggest/assets/js/src/autosuggest.js +++ b/features/autosuggest/assets/js/src/autosuggest.js @@ -190,7 +190,7 @@ // Listen to items to auto-fill search box and submit form $( '.autosuggest-item' ).on( 'click', function( event ) { - selectItem( $localInput, event.srcElement ); + selectItem( $localInput, event.target ); } ); $localInput.off( 'keydown' ); diff --git a/features/woocommerce/woocommerce.php b/features/woocommerce/woocommerce.php index 324f122a11..84662c2331 100644 --- a/features/woocommerce/woocommerce.php +++ b/features/woocommerce/woocommerce.php @@ -201,7 +201,7 @@ function ep_wc_translate_args( $query ) { /** * Do nothing for single product queries */ - if ( ! empty( $product_name ) ) { + if ( ! empty( $product_name ) || $query->is_single() ) { return; } diff --git a/readme.txt b/readme.txt index 57c43240b6..f062c5d16d 100644 --- a/readme.txt +++ b/readme.txt @@ -38,13 +38,15 @@ Please refer to [Github](https://github.com/10up/ElasticPress) for detailed usag == Changelog == -= 2.3.1, 2.3.2 = += 2.4.1 = -Version 2.3.1-2.3.2 is a bug fix release. Here are a listed of issues that have been resolved: +Version 2.4.1 is a bug fix and maintenance release. Here are a listed of issues that have been resolved: -* Cache ES plugins request. This is super important. Instead of checking the status of ES on every page load, do it every 5 minutes. If ES isn't available, show admin notification that allows you to retry the host. -* Fix broken upgrade sync notification. -* Properly respect WC product visibility. Props [ivankristianto](https://github.com/ivankristianto). This requires a re-index if you are using the WooCommerce feature. +* Support Elasticsearch 6.1 and properly send Content-Type header with application/json. Props [eugene-manuilov](https://github.com/eugene-manuilov). +* Fix autosuggest event target issue bug. Props [eugene-manuilov](https://github.com/eugene-manuilov). +* Fix widget init bug. Props [eugene-manuilov](https://github.com/eugene-manuilov). +* Fix taxonomy sync parameter warning. Props [eugene-manuilov](https://github.com/eugene-manuilov). +* Increase maximum Elasticsearch compatibility to 6.1 = 2.4 = @@ -74,6 +76,14 @@ Here is a comphrensive list of changes: * Add escaping per VIP standards. Props [jasonbahl](https://github.com/jasonbahl). * Fix WooCommerce post type warnings. += 2.3.1, 2.3.2 = + +Version 2.3.1-2.3.2 is a bug fix release. Here are a listed of issues that have been resolved: + +* Cache ES plugins request. This is super important. Instead of checking the status of ES on every page load, do it every 5 minutes. If ES isn't available, show admin notification that allows you to retry the host. +* Fix broken upgrade sync notification. +* Properly respect WC product visibility. Props [ivankristianto](https://github.com/ivankristianto). This requires a re-index if you are using the WooCommerce feature. + = 2.3 = Version 2.3 introduces the Documents feature which indexes text inside of popular file types, and adds those files types to search results. We've also officially added support for Elasticsearch 5.3. diff --git a/tests/features/test-search.php b/tests/features/test-search.php index d4ca98ae00..19f8da209d 100644 --- a/tests/features/test-search.php +++ b/tests/features/test-search.php @@ -117,12 +117,12 @@ public function testSearchIndexDeleted(){ * @group search */ public function testDecayingEnabled() { - delete_site_option( 'ep_feature_requirement_statuses' ); - delete_site_option( 'ep_feature_settings' ); - - EP_Features::factory()->handle_feature_activation(); + ep_activate_feature( 'search' ); EP_Features::factory()->setup_features(); + // Need to call this since it's hooked to init + ep_search_setup(); + ep_update_feature( 'search', array( 'active' => true, 'decaying_enabled' => true, @@ -135,6 +135,7 @@ public function testDecayingEnabled() { $query = new WP_Query( array( 's' => 'test', ) ); + $this->assertTrue( isset( $this->fired_actions['ep_formatted_args'] ) ); $this->assertTrue( isset( $this->fired_actions['ep_formatted_args']['query'], @@ -154,12 +155,12 @@ public function testDecayingEnabled() { * @group search */ public function testDecayingDisabled() { - delete_site_option( 'ep_feature_requirement_statuses' ); - delete_site_option( 'ep_feature_settings' ); - - EP_Features::factory()->handle_feature_activation(); + ep_activate_feature( 'search' ); EP_Features::factory()->setup_features(); + // Need to call this since it's hooked to init + ep_search_setup(); + ep_update_feature( 'search', array( 'active' => true, 'decaying_enabled' => false,