├── assets
├── css
│ └── main.css
└── js
│ └── main.js
├── classes
├── CommonPanel.php
├── EP_Debug_Bar_ElasticPress.php
├── QueryFormatter.php
├── QueryLog.php
├── QueryMonitorCollector.php
├── QueryMonitorOutput.php
└── QueryOutput.php
├── debug-bar-elasticpress.php
├── lang
└── debug-bar-elasticpress.pot
└── readme.txt
/assets/css/main.css:
--------------------------------------------------------------------------------
1 | .ep-debug-bar-warning {
2 | background-color: #ffffe0;
3 | border: 1px solid #e6db55;
4 | clear: both;
5 | padding: 0.5em 10px;
6 | }
7 |
8 | .ep-queries-debug pre {
9 | padding: 10px;
10 | }
11 |
12 | .ep-queries-debug .dashicons {
13 | cursor: pointer;
14 | }
15 |
16 | .ep-queries-debug .dashicons::before {
17 | content: "\f140";
18 | }
19 |
20 | .ep-queries-debug .hide-query-results .query-results,
21 | .ep-queries-debug .hide-query-args .query-args,
22 | .ep-queries-debug .hide-query-headers .query-headers,
23 | .ep-queries-debug .hide-query-errors .query-errors,
24 | .ep-queries-debug .hide-query-body .query-body {
25 | display: none;
26 | }
27 |
28 | .ep-queries-debug .query-body,
29 | .ep-queries-debug .query-args,
30 | .ep-queries-debug .query-headers,
31 | .ep-queries-debug .query-errors,
32 | .ep-queries-debug .query-results {
33 | background-color: white;
34 | }
35 |
36 | .ep-queries-debug .hide-query-results .query-result-toggle::before,
37 | .ep-queries-debug .hide-query-args .query-args-toggle::before,
38 | .ep-queries-debug .hide-query-headers .query-headers-toggle::before,
39 | .ep-queries-debug .hide-query-errors .query-errors-toggle::before,
40 | .ep-queries-debug .hide-query-body .query-body-toggle::before {
41 | content: "\f142";
42 | }
43 |
44 | .ep-queries-debug .ep-query-failed .ep-query-response-code {
45 | color: red;
46 | font-weight: bold;
47 | }
48 |
49 | .ep-queries-buttons-wrapper {
50 | align-items: center;
51 | clear: both;
52 | display: flex;
53 | gap: 10px;
54 | padding: 1em 0;
55 | }
56 |
57 | .ep-queries-debug-container .copy-curl {
58 | border-color: #000;
59 | border-radius: 3px;
60 | border-style: solid;
61 | border-width: 1px;
62 | color: #000;
63 | cursor: pointer;
64 | display: inline-block;
65 | font-size: 13px;
66 | line-height: 2.1538;
67 | min-height: 30px;
68 | padding: 0 10px;
69 | text-decoration: none;
70 | }
71 |
72 | .ep-queries-debug-container {
73 | clear: left;
74 | }
75 |
76 | /* stylelint-disable selector-id-pattern */
77 |
78 | /* The giant list of selectors here is needed to
79 | * override QM's important rules
80 | */
81 | #debug-menu-target-EP_Debug_Bar_ElasticPress .button,
82 | #debug-menu-target-EP_Debug_Bar_ElasticPress a.button,
83 | #qm-elasticpress .button,
84 | #qm-elasticpress a.button {
85 | background: #f6f7f7 !important;
86 | border: 1px solid #2271b1 !important;
87 | border-radius: 3px !important;
88 |
89 | /* Overriding some Debug Bar "important" rules */
90 | color: #2271b1 !important;
91 | cursor: pointer;
92 | display: inline-block;
93 | font-family: inherit;
94 | font-size: 13px;
95 | line-height: 2.1538 !important;
96 | padding: 0 10px !important;
97 | text-decoration: none !important;
98 | text-shadow: none;
99 | }
100 |
101 | #debug-menu-target-EP_Debug_Bar_ElasticPress .button:hover,
102 | #query-monitor-main #qm-elasticpress .button:hover {
103 | background: #f0f0f1;
104 | border-color: #0a4b78;
105 | color: #0a4b78 !important;
106 | text-decoration: none !important;
107 | }
108 |
109 | #debug-menu-target-EP_Debug_Bar_ElasticPress .button:active,
110 | #query-monitor-main #qm-elasticpress .button:hover {
111 | background: #f6f7f7 !important;
112 | border-color: #8c8f94 !important;
113 | box-shadow: none;
114 | }
115 |
116 | #debug-menu-target-EP_Debug_Bar_ElasticPress .button:focus,
117 | #query-monitor-main #qm-elasticpress .button:focus {
118 | outline: none;
119 | }
120 |
121 | /* Overriding some Debug Bar "important" rules */
122 | #debug-menu-target-EP_Debug_Bar_ElasticPress .button-primary,
123 | #debug-menu-target-EP_Debug_Bar_ElasticPress a.button-primary,
124 | #debug-menu-target-EP_Debug_Bar_ElasticPress button.button-primary,
125 | #query-monitor-main #qm-elasticpress .button-primary {
126 | background: #007cba !important;
127 | border: 1px solid #007cba !important;
128 | color: #fff !important;
129 | }
130 |
131 | #debug-menu-target-EP_Debug_Bar_ElasticPress a.button-primary:hover,
132 | #debug-menu-target-EP_Debug_Bar_ElasticPress a.button-primary:focus,
133 | #query-monitor-main #qm-elasticpress a.button-primary:hover,
134 | #query-monitor-main #qm-elasticpress a.button-primary:focus {
135 | background: #007cba !important;
136 | color: #fff !important;
137 | text-decoration: none !important;
138 | }
139 |
140 | #query-monitor-main #qm-elasticpress h3,
141 | #query-monitor-main #qm-elasticpress p {
142 | margin: 0 !important;
143 | padding: 0 !important;
144 | text-align: center !important;
145 | }
146 |
147 | #query-monitor-main #qm-elasticpress li {
148 | border-top: 1px solid var(--qm-panel-separator) !important;
149 | line-height: 20px !important;
150 | padding: 20px 0 !important;
151 | }
152 |
153 | /* stylelint-enable selector-id-pattern */
154 |
--------------------------------------------------------------------------------
/assets/js/main.js:
--------------------------------------------------------------------------------
1 | /* global ClipboardJS */
2 |
3 | wp.domReady(() => {
4 | const copyBtn = document.querySelectorAll('.ep-copy-button');
5 | const clipboard = new ClipboardJS(copyBtn);
6 |
7 | /**
8 | * Handle successful copy.
9 | *
10 | * @param {Event} event Copy event.
11 | * @returns {void}
12 | */
13 | const onSuccess = (event) => {
14 | event.trigger.nextElementSibling.style.display = 'initial';
15 | setTimeout(() => {
16 | event.trigger.nextElementSibling.style.display = 'none';
17 | }, 3000);
18 | event.clearSelection();
19 | };
20 |
21 | /**
22 | * Bind copy button events.
23 | */
24 | clipboard.on('success', onSuccess);
25 |
26 | let queries = document.querySelectorAll('.ep-queries-debug');
27 |
28 | if (queries.length > 0) {
29 | queries = queries[0];
30 |
31 | queries.addEventListener('click', function (event) {
32 | let queryWrapper = event.target;
33 |
34 | while (event.currentTarget.contains(queryWrapper)) {
35 | if (queryWrapper.nodeName === 'LI') {
36 | if (event.target.className.match(/query-body-toggle/i)) {
37 | if (queryWrapper.className.match(/hide-query-body/i)) {
38 | queryWrapper.className = queryWrapper.className.replace(
39 | /hide-query-body/i,
40 | '',
41 | );
42 | } else {
43 | queryWrapper.className += ' hide-query-body';
44 | }
45 | }
46 |
47 | if (event.target.className.match(/query-result-toggle/i)) {
48 | if (queryWrapper.className.match(/hide-query-results/i)) {
49 | queryWrapper.className = queryWrapper.className.replace(
50 | /hide-query-results/i,
51 | '',
52 | );
53 | } else {
54 | queryWrapper.className += ' hide-query-results';
55 | }
56 | }
57 |
58 | if (event.target.className.match(/query-args-toggle/i)) {
59 | if (queryWrapper.className.match(/hide-query-args/i)) {
60 | queryWrapper.className = queryWrapper.className.replace(
61 | /hide-query-args/i,
62 | '',
63 | );
64 | } else {
65 | queryWrapper.className += ' hide-query-args';
66 | }
67 | }
68 |
69 | if (event.target.className.match(/query-headers-toggle/i)) {
70 | if (queryWrapper.className.match(/hide-query-headers/i)) {
71 | queryWrapper.className = queryWrapper.className.replace(
72 | /hide-query-headers/i,
73 | '',
74 | );
75 | } else {
76 | queryWrapper.className += ' hide-query-headers';
77 | }
78 | }
79 |
80 | if (event.target.className.match(/query-errors-toggle/i)) {
81 | if (queryWrapper.className.match(/hide-query-errors/i)) {
82 | queryWrapper.className = queryWrapper.className.replace(
83 | /hide-query-errors/i,
84 | '',
85 | );
86 | } else {
87 | queryWrapper.className += ' hide-query-errors';
88 | }
89 | }
90 |
91 | break;
92 | } else {
93 | queryWrapper = queryWrapper.parentNode;
94 | }
95 | }
96 | });
97 | }
98 | });
99 |
--------------------------------------------------------------------------------
/classes/CommonPanel.php:
--------------------------------------------------------------------------------
1 | get_query_log() );
24 |
25 | if ( $queries_count ) {
26 | return sprintf(
27 | /* translators: %d: number of queries */
28 | esc_html__( 'ElasticPress (%d)', 'debug-bar-elasticpress' ),
29 | $queries_count
30 | );
31 | }
32 |
33 | return esc_html__( 'ElasticPress', 'debug-bar-elasticpress' );
34 | }
35 |
36 | /**
37 | * Enqueue scripts for front end and admin
38 | */
39 | public function enqueue_scripts_styles() {
40 | if ( ! is_user_logged_in() ) {
41 | return;
42 | }
43 |
44 | wp_enqueue_script( 'debug-bar-elasticpress', EP_DEBUG_URL . 'assets/js/main.js', array( 'wp-dom-ready', 'clipboard' ), EP_DEBUG_VERSION, true );
45 | wp_enqueue_style( 'debug-bar-elasticpress', EP_DEBUG_URL . 'assets/css/main.css', array(), EP_DEBUG_VERSION );
46 | }
47 |
48 | /**
49 | * Show the contents of the panel
50 | */
51 | public function render() {
52 | $queries = \ElasticPress\Elasticsearch::factory()->get_query_log();
53 |
54 | if ( function_exists( '\ElasticPress\Utils\is_indexing' ) && \ElasticPress\Utils\is_indexing() ) {
55 | ?>
56 |
57 |
58 |
59 | render_buttons();
64 | $debug_bar_output->render_additional_buttons();
65 | $debug_bar_output->render_queries();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/classes/EP_Debug_Bar_ElasticPress.php:
--------------------------------------------------------------------------------
1 | title( esc_html__( 'ElasticPress', 'debug-bar-elasticpress' ) );
39 |
40 | $this->common_panel = new \DebugBarElasticPress\CommonPanel();
41 | $this->common_panel->enqueue_scripts_styles();
42 | }
43 |
44 | /**
45 | * Enqueue scripts for front end and admin
46 | */
47 | public function enqueue_scripts_styles() {
48 | _deprecated_function( __METHOD__, '3.1.0', 'DebugBarElasticPress\EP_Panel::enqueue_scripts_styles()' );
49 | }
50 |
51 | /**
52 | * Show the menu item in Debug Bar.
53 | */
54 | public function prerender() {
55 | $this->set_visible( true );
56 | }
57 |
58 | /**
59 | * Show the contents of the panel
60 | */
61 | public function render() {
62 | $queries = \ElasticPress\Elasticsearch::factory()->get_query_log();
63 | $total_query_time = 0;
64 |
65 | foreach ( $queries as $query ) {
66 | if ( ! empty( $query['time_start'] ) && ! empty( $query['time_finish'] ) ) {
67 | $total_query_time += ( $query['time_finish'] - $query['time_start'] );
68 | }
69 | }
70 |
71 | ?>
72 |
73 |
74 | Total ElasticPress Queries: %d', 'debug-bar-elasticpress' ), count( $queries ) )
78 | );
79 | ?>
80 |
81 |
82 | Total Blocking ElasticPress Query Time: %d ms', 'debug-bar-elasticpress' ), (int) ( $total_query_time * 1000 ) )
86 | );
87 | ?>
88 |
89 |
90 | common_panel->render();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/classes/QueryFormatter.php:
--------------------------------------------------------------------------------
1 | esc_html__( 'Page URL', 'debug-bar-elasticpress' ),
32 | 'es_req' => esc_html__( 'Elasticsearch Request', 'debug-bar-elasticpress' ),
33 | 'request_id' => esc_html__( 'Request ID', 'debug-bar-elasticpress' ),
34 | 'timestamp' => esc_html__( 'Time', 'debug-bar-elasticpress' ),
35 | 'query_time' => esc_html__( 'Time Spent (ms)', 'debug-bar-elasticpress' ),
36 | 'wp_args' => esc_html__( 'WP Query Args', 'debug-bar-elasticpress' ),
37 | 'status_code' => esc_html__( 'HTTP Status Code', 'debug-bar-elasticpress' ),
38 | 'body' => esc_html__( 'Query Body', 'debug-bar-elasticpress' ),
39 | 'result' => esc_html__( 'Query Result', 'debug-bar-elasticpress' ),
40 | ];
41 |
42 | $failed_queries_obj = new \ElasticPress\StatusReport\FailedQueries( $this );
43 |
44 | foreach ( $queries as $query ) {
45 | $query = $this->format_log_entry( $query, 'query' );
46 | list( $error, $solution ) = $failed_queries_obj->analyze_log( $query );
47 |
48 | $fields = [];
49 | if ( ! empty( $error ) ) {
50 | $fields['error'] = [
51 | 'label' => __( 'Error', 'debug-bar-elasticpress' ),
52 | 'value' => $error,
53 | ];
54 | $fields['recommended_solution'] = [
55 | 'label' => __( 'Recommended Solution', 'debug-bar-elasticpress' ),
56 | 'value' => $solution,
57 | ];
58 | }
59 |
60 | foreach ( $query as $field => $value ) {
61 | // Already outputted in the title
62 | if ( in_array( $field, [ 'wp_url', 'timestamp' ], true ) ) {
63 | continue;
64 | }
65 |
66 | $fields[ $field ] = [
67 | 'label' => $labels[ $field ] ?? $field,
68 | 'value' => $value,
69 | ];
70 | }
71 |
72 | $formatted_queries[] = [
73 | 'title' => sprintf( '%s (%s)', $query['wp_url'], date_i18n( 'Y-m-d H:i:s', $query['timestamp'] ) ),
74 | 'fields' => $fields,
75 | ];
76 | }
77 |
78 | return $formatted_queries;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/classes/QueryLog.php:
--------------------------------------------------------------------------------
1 | sanitize_enable_logging( $_POST['ep_enable_logging'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
65 | if ( isset( $_POST['ep_query_log_by_status'] ) ) {
66 | update_site_option( 'ep_query_log_by_status', sanitize_text_field( wp_unslash( $_POST['ep_query_log_by_status'] ) ) );
67 | }
68 | if ( ! empty( $_POST['ep_query_log_by_context'] ) ) {
69 | $ep_query_log_by_context = array_map( 'sanitize_text_field', wp_unslash( $_POST['ep_query_log_by_context'] ) );
70 | update_site_option( 'ep_query_log_by_context', $ep_query_log_by_context );
71 | } else {
72 | update_site_option( 'ep_query_log_by_context', [] );
73 | }
74 | } else {
75 | register_setting(
76 | 'ep-debug',
77 | 'ep_enable_logging',
78 | [ 'sanitize_callback' => [ $this, 'sanitize_enable_logging' ] ]
79 | );
80 | register_setting(
81 | 'ep-debug',
82 | 'ep_query_log_by_status',
83 | [ 'sanitize_callback' => 'sanitize_text_field' ]
84 | );
85 | register_setting(
86 | 'ep-debug',
87 | 'ep_query_log_by_context',
88 | [
89 | 'sanitize_callback' => function ( $value ) {
90 | return ! empty( $value ) ? array_map( 'sanitize_text_field', $value ) : [];
91 | },
92 | ]
93 | );
94 | }
95 | }
96 |
97 | /**
98 | * Clear query log
99 | *
100 | * @since 1.3
101 | */
102 | public function maybe_clear_log() {
103 | if (
104 | empty( $_GET['ep_clear_query_log'] )
105 | || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['ep_clear_query_log'] ) ), 'ep_clear_query_log' )
106 | ) {
107 | return;
108 | }
109 |
110 | Utils\delete_option( 'ep_query_log' );
111 |
112 | wp_safe_redirect( remove_query_arg( 'ep_clear_query_log' ) );
113 | exit();
114 | }
115 |
116 | /**
117 | * Add options page
118 | *
119 | * @since 1.3
120 | * @return void
121 | */
122 | public function action_admin_menu() {
123 | add_submenu_page(
124 | 'elasticpress',
125 | esc_html__( 'Query Log', 'debug-bar-elasticpress' ),
126 | esc_html__( 'Query Log', 'debug-bar-elasticpress' ),
127 | 'manage_options',
128 | 'ep-query-log',
129 | array( $this, 'screen_options' )
130 | );
131 | }
132 |
133 | /**
134 | * Only log delete index error if not 2xx AND not 404
135 | *
136 | * @param array $query Remote request arguments
137 | * @since 1.3
138 | * @return bool
139 | */
140 | public function maybe_log_delete_index( $query ) {
141 | $response_code = wp_remote_retrieve_response_code( $query['request'] );
142 |
143 | return ( ( $response_code < 200 || $response_code > 299 ) && 404 !== $response_code );
144 | }
145 |
146 | /**
147 | * Log all non-200 requests
148 | *
149 | * @param array $query Remote request arguments
150 | * @since 1.3
151 | * @return bool
152 | */
153 | public function is_query_error( $query ) {
154 | if ( is_wp_error( $query['request'] ) ) {
155 | return true;
156 | }
157 |
158 | $response_code = wp_remote_retrieve_response_code( $query['request'] );
159 |
160 | return ( $response_code < 200 || $response_code > 299 );
161 | }
162 |
163 | /**
164 | * Check the request body, as usually bulk indexing does not return a status error.
165 | *
166 | * @since 2.1.0
167 | * @param array $query Remote request arguments
168 | * @return boolean
169 | */
170 | public function is_bulk_index_error( $query ) {
171 | if ( $this->is_query_error( $query ) ) {
172 | return true;
173 | }
174 |
175 | $request_body = json_decode( wp_remote_retrieve_body( $query['request'] ), true );
176 | return ! empty( $request_body['errors'] );
177 | }
178 |
179 | /**
180 | * Conditionally save a query to the log which is stored in options. This is a big performance hit so be careful.
181 | *
182 | * @param array $query Remote request arguments
183 | * @param string $type Request type
184 | * @since 1.3
185 | */
186 | public function log_query( $query, $type ) {
187 | if ( ! $this->is_enabled() ) {
188 | return;
189 | }
190 |
191 | if ( ! $this->should_log_by_context() ) {
192 | return;
193 | }
194 |
195 | if ( ! $this->should_log_by_status( $query, $type ) ) {
196 | return;
197 | }
198 |
199 | $log = Utils\get_option( 'ep_query_log', [] );
200 |
201 | $log[] = array(
202 | 'query' => $query,
203 | 'type' => $type,
204 | );
205 |
206 | // Storing this log would exceed the limit
207 | if ( mb_strlen( maybe_serialize( $log ) ) > $this->get_logging_storage_limit() ) {
208 | return;
209 | }
210 |
211 | Utils\update_option( 'ep_query_log', $log );
212 | }
213 |
214 | /**
215 | * Output query log page
216 | *
217 | * @since 1.3
218 | */
219 | public function screen_options() {
220 | $log = Utils\get_option( 'ep_query_log', array() );
221 | $enabled = Utils\get_option( 'ep_enable_logging' );
222 | $by_status = Utils\get_option( 'ep_query_log_by_status', 'failed' );
223 | $by_context = Utils\get_option( 'ep_query_log_by_context', [] );
224 |
225 | if ( is_array( $log ) ) {
226 | $log = array_reverse( $log );
227 | }
228 |
229 | $action = 'options.php';
230 |
231 | if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
232 | $action = '';
233 | }
234 |
235 | $is_time_limit = ! empty( $enabled ) && ! in_array( $enabled, [ '0', 0, '-1', -1 ], true );
236 | ?>
237 |
238 |
239 |
240 |
241 |
329 |
330 | render_buttons();
340 | $debug_bar_output->render_queries( [ 'display_context' => true ] );
341 | ?>
342 |
343 | setup();
358 | }
359 |
360 | return $instance;
361 | }
362 |
363 | /**
364 | * Store the queries as JSON objects.
365 | *
366 | * This is necessary because otherwise, WP will run it thought `maybe_unserialize()` and break it.
367 | *
368 | * @param mixed $value The ep_query_log option value.
369 | * @return string
370 | */
371 | public function json_encode_query_log( $value ) {
372 | return wp_json_encode( $value );
373 | }
374 |
375 | /**
376 | * Decode the queries back to an associative array.
377 | *
378 | * @param string $value A JSON string.
379 | * @return array
380 | */
381 | public function json_decode_query_log( $value ) {
382 | return ( is_string( $value ) ) ? json_decode( $value, true ) : $value;
383 | }
384 |
385 | /**
386 | * Conditionally add the request type to the request args
387 | *
388 | * @since 3.1.0
389 | * @param array $args Request args
390 | * @param string $path Site URL to retrieve
391 | * @param array $query_args The query args originally passed to WP_Query.
392 | * @param string|null $type Type of request, used for debugging.
393 | * @return array New request args
394 | */
395 | public function maybe_add_request_type( array $args, string $path, array $query_args, $type ): array {
396 | if ( ! empty( $args['ep_query_type'] ) ) {
397 | return $args;
398 | }
399 |
400 | if ( ! empty( $type ) ) {
401 | $args['ep_query_type'] = $type;
402 |
403 | if ( 'get' === $type ) {
404 | $args['ep_query_type'] = esc_html__( 'Raw ES document', 'debug-bar-elasticpress' );
405 | }
406 | }
407 |
408 | if ( '_nodes/plugins' === $path ) {
409 | $args['ep_query_type'] = esc_html__( 'Elasticsearch check', 'debug-bar-elasticpress' );
410 | }
411 |
412 | return $args;
413 | }
414 |
415 | /**
416 | * Conditionally add the context of the query
417 | *
418 | * @param array $args Request args
419 | * @return array
420 | */
421 | public function maybe_add_request_context( array $args ): array {
422 | $args['ep_context'] = $this->get_current_context();
423 |
424 | return $args;
425 | }
426 |
427 | /**
428 | * Get the current context
429 | *
430 | * @since 3.1.0
431 | * @return string
432 | */
433 | protected function get_current_context(): string {
434 | $context = 'public';
435 |
436 | if ( is_admin() ) {
437 | $context = 'admin';
438 | }
439 |
440 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
441 | $context = 'ajax';
442 | }
443 |
444 | if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
445 | $context = 'rest';
446 | }
447 |
448 | return $context;
449 | }
450 |
451 | /**
452 | * Conditionally add the request type to the request args (for query requests)
453 | *
454 | * @since 3.1.0
455 | * @param array $request_args Request arguments
456 | * @param string $path Request path
457 | * @param string $index Index name
458 | * @param string $type Index type
459 | * @param array $query Prepared Elasticsearch query
460 | * @param array $query_args Query arguments
461 | * @param mixed $query_object Could be WP_Query, WP_User_Query, etc.
462 | * @return array New request arguments
463 | */
464 | public function maybe_add_request_query_type( array $request_args, string $path, string $index, string $type, array $query, array $query_args, $query_object ): array {
465 | $request_args['ep_query_type'] = $this->determine_request_query_type( $request_args, $path, $index, $type, $query, $query_args, $query_object );
466 | return $request_args;
467 | }
468 |
469 | /**
470 | * Enqueue assets if we are in the correct admin screen
471 | *
472 | * @since 3.1.0
473 | */
474 | public function admin_enqueue_scripts() {
475 | $current_screen = get_current_screen();
476 |
477 | if ( ! isset( $current_screen->id ) || 'elasticpress_page_ep-query-log' !== $current_screen->id ) {
478 | return;
479 | }
480 |
481 | ( new CommonPanel() )->enqueue_scripts_styles();
482 | }
483 |
484 | /**
485 | * Conditionally add the request type to the request args (for query requests)
486 | *
487 | * @since 3.1.0
488 | * @param array $request_args Request arguments
489 | * @param string $path Request path
490 | * @param string $index Index name
491 | * @param string $type Index type
492 | * @param array $query Prepared Elasticsearch query
493 | * @param array $query_args Query arguments
494 | * @param mixed $query_object Could be WP_Query, WP_User_Query, etc.
495 | * @return string Request type
496 | */
497 | protected function determine_request_query_type( array $request_args, string $path, string $index, string $type, array $query, array $query_args, $query_object ): string {
498 | if ( $query_object instanceof \WP_Query && $query_object->is_main_query() ) {
499 | return esc_html__( 'Main query', 'debug-bar-elasticpress' );
500 | }
501 |
502 | if ( empty( $query['query'] ) && ! empty( $query['aggs'] ) ) {
503 | return esc_html__( 'Possible values for EP filter', 'debug-bar-elasticpress' );
504 | }
505 |
506 | $search_term = $query_args['s'] ?? '';
507 | if ( '' !== $search_term ) {
508 | $type = 'Search';
509 | if ( apply_filters( 'ep_autosuggest_query_placeholder', 'ep_autosuggest_placeholder' ) === $search_term ) {
510 | return esc_html__( 'Autosuggest template', 'debug-bar-elasticpress' );
511 | }
512 |
513 | return esc_html__( 'Search', 'debug-bar-elasticpress' );
514 | }
515 |
516 | return $type;
517 | }
518 |
519 | /**
520 | * Whether logging is enabled or not
521 | *
522 | * @since 3.1.0
523 | * @return boolean
524 | */
525 | protected function is_enabled(): bool {
526 | $enabled = Utils\get_option( 'ep_enable_logging' );
527 |
528 | return ! empty( $enabled );
529 | }
530 |
531 | /**
532 | * Whether the current context should or not be logged
533 | *
534 | * @since 3.1.0
535 | * @return boolean
536 | */
537 | protected function should_log_by_context() {
538 | $by_context = Utils\get_option( 'ep_query_log_by_context', [] );
539 |
540 | return empty( $by_context ) || in_array( $this->get_current_context(), $by_context, true );
541 | }
542 |
543 | /**
544 | * Whether a query (and a type) should be logged or not
545 | *
546 | * @since 3.1.0
547 | * @param array $query Remote request arguments
548 | * @param string $type Query type
549 | * @return boolean
550 | */
551 | protected function should_log_by_status( array $query, $type ): bool {
552 | $by_status = Utils\get_option( 'ep_query_log_by_status', 'failed' );
553 |
554 | if ( 'all' === $by_status ) {
555 | return true;
556 | }
557 |
558 | /**
559 | * This filter allows you to map query types to callables. If the callable returns true,
560 | * that query will be logged.
561 | *
562 | * @var array
563 | * @since 1.3
564 | * @since 2.1.0 Added `bulk_index`
565 | */
566 | $allowed_log_types = apply_filters(
567 | 'ep_debug_bar_allowed_log_types',
568 | array(
569 | 'put_mapping' => array( $this, 'is_query_error' ),
570 | 'delete_network_alias' => array( $this, 'is_query_error' ),
571 | 'create_network_alias' => array( $this, 'is_query_error' ),
572 | 'bulk_index' => array( $this, 'is_bulk_index_error' ),
573 | 'bulk_index_posts' => array( $this, 'is_query_error' ),
574 | 'delete_index' => array( $this, 'maybe_log_delete_index' ),
575 | 'create_pipeline' => array( $this, 'is_query_error' ),
576 | 'get_pipeline' => array( $this, 'is_query_error' ),
577 | 'query' => array( $this, 'is_query_error' ),
578 | ),
579 | $query,
580 | $type
581 | );
582 |
583 | if ( ! isset( $allowed_log_types[ $type ] ) ) {
584 | return false;
585 | }
586 |
587 | return call_user_func( $allowed_log_types[ $type ], $query );
588 | }
589 |
590 | /**
591 | * Return the size limit for stored logs
592 | *
593 | * @since 3.1.0
594 | * @return integer
595 | */
596 | protected function get_logging_storage_limit(): int {
597 | /**
598 | * Filter the log size limit
599 | *
600 | * @since 3.1.0
601 | * @hook ep_debug_bar_log_size_limit
602 | * @param {int} $number Log size limit
603 | * @return {int} New limit
604 | */
605 | return apply_filters( 'ep_debug_bar_log_size_limit', MB_IN_BYTES );
606 | }
607 |
608 | /**
609 | * Conditionally disable logging based on period
610 | *
611 | * @since 3.1.0
612 | */
613 | public function maybe_disable() {
614 | $enabled = Utils\get_option( 'ep_enable_logging' );
615 |
616 | $is_time_limit = ! empty( $enabled ) && ! in_array( $enabled, [ '0', 0, '-1' ], true );
617 | if ( ! $is_time_limit || $enabled > wp_date( 'U' ) ) {
618 | return;
619 | }
620 |
621 | Utils\update_option( 'ep_enable_logging', 0 );
622 | }
623 |
624 | /**
625 | * Sanitize the ep_enable_logging option, conditionally setting it as a time limit
626 | *
627 | * @since 3.1.0
628 | * @param mixed $value Value sent
629 | * @return mixed
630 | */
631 | public function sanitize_enable_logging( $value ) {
632 | if ( 'time_limit' === $value ) {
633 | $value = wp_date( 'U', strtotime( '+5 minutes' ) );
634 | } else {
635 | $value = ! empty( $value ) ? -1 : 0;
636 | }
637 |
638 | return $value;
639 | }
640 | }
641 |
--------------------------------------------------------------------------------
/classes/QueryMonitorCollector.php:
--------------------------------------------------------------------------------
1 | common_panel = new CommonPanel();
33 |
34 | add_filter( 'qm/output/menus', [ $this, 'admin_menu' ] );
35 | }
36 |
37 | /**
38 | * Panel title
39 | *
40 | * @return string
41 | */
42 | public function name(): string {
43 | return $this->common_panel->get_title();
44 | }
45 |
46 | /**
47 | * Echoes the output
48 | *
49 | * @return void
50 | */
51 | public function output() {
52 | ?>
53 |
54 | render_summary(); ?>
55 | common_panel->render(); ?>
56 |
57 | get_query_log();
67 | $total_query_time = 0;
68 |
69 | foreach ( $queries as $query ) {
70 | if ( ! empty( $query['time_start'] ) && ! empty( $query['time_finish'] ) ) {
71 | $total_query_time += ( $query['time_finish'] - $query['time_start'] );
72 | }
73 | }
74 | ?>
75 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
96 |
97 |
98 |
99 | queries = $queries;
36 | }
37 |
38 | /**
39 | * Render the download and copy&paste buttons
40 | *
41 | * @since 3.0.0
42 | * @return void
43 | */
44 | public function render_buttons() {
45 | if ( empty( $this->queries ) ) {
46 | return;
47 | }
48 |
49 | $copy_paste_output = $this->get_copy_paste_report();
50 | ?>
51 |
62 |
74 |
75 |
76 | queries ) ) {
78 | ?>
79 |
80 | queries as $query ) {
83 | $type = $query['args']['ep_query_type'] ?? '';
84 | $context = ( ! empty( $args['display_context'] ) && ! empty( $query['args']['ep_context'] ) ) ?
85 | $query['args']['ep_context'] :
86 | '';
87 | $this->render_query( $query, $type, $context );
88 | }
89 | }
90 | ?>
91 |
92 |
93 | = 300 ? 'ep-query-failed' : '';
110 | $log['result'] = json_decode( $result, true );
111 |
112 | if ( class_exists( '\ElasticPress\StatusReport\FailedQueries' ) && class_exists( 'ElasticPress\QueryLogger' ) ) {
113 | $query_logger = apply_filters( 'ep_query_logger', new \ElasticPress\QueryLogger() );
114 | if ( $query_logger ) {
115 | $failed_queries = new \ElasticPress\StatusReport\FailedQueries( $query_logger );
116 | $error = $failed_queries->analyze_log( $log );
117 | $error = array_filter( $error );
118 | }
119 | }
120 |
121 | $curl_request = 'curl -X' . strtoupper( $query['args']['method'] );
122 |
123 | if ( ! empty( $query['args']['headers'] ) ) {
124 | foreach ( $query['args']['headers'] as $key => $value ) {
125 | $curl_request .= " -H '$key: $value'";
126 | }
127 | }
128 |
129 | if ( ! empty( $query['args']['body'] ) ) {
130 | $curl_request .= " -d '" . wp_json_encode( json_decode( $query['args']['body'], true ) ) . "'";
131 | }
132 |
133 | $curl_request .= " '" . $query['url'] . "'";
134 |
135 | ?>
136 |
137 |
138 |
139 |
140 |
141 | Error: %s', 'debug-bar-elasticpress' ), $error[0] )
145 | );
146 | ?>
147 |
148 |
149 | Recommended Solution: %s', 'debug-bar-elasticpress' ), $error[1] )
153 | );
154 | ?>
155 |
156 |
157 |
158 |
159 |
160 |
errors, JSON_PRETTY_PRINT ) ); ?>
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 | Time Taken: %d ms', 'debug-bar-elasticpress' ), ( $query_time * 1000 ) )
189 | );
190 | else :
191 | echo wp_kses_post(
192 | __( 'Time Taken: -', 'debug-bar-elasticpress' )
193 | );
194 | endif;
195 | ?>
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
213 |
214 |
215 |
216 |
220 |
221 |
222 |
223 |
236 |
237 |
238 |
239 |
240 | Query Response Code: HTTP %d', 'debug-bar-elasticpress' ), (int) $response )
244 | );
245 | ?>
246 |
247 |
251 |
252 |
253 |
254 |
255 |
256 | ">
257 |
258 |
259 |
260 |
261 |
262 |
263 | format_queries_for_display( $this->queries );
280 |
281 | foreach ( $formatted_queries as $query ) {
282 | $output .= "### {$query['title']} ###\n";
283 | foreach ( $query['fields'] as $slug => $field ) {
284 | $value = $field['value'] ?? '';
285 |
286 | $output .= "{$slug}: ";
287 | $output .= $this->render_value( $value );
288 | $output .= "\n";
289 | }
290 | $output .= "\n";
291 | }
292 |
293 | return $output;
294 | }
295 |
296 | /**
297 | * Render a value based on its type
298 | *
299 | * @since 3.0.0
300 | * @param mixed $value The value
301 | * @return string
302 | */
303 | protected function render_value( $value ) {
304 | if ( is_array( $value ) || is_object( $value ) ) {
305 | return var_export( $value, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
306 | }
307 |
308 | if ( is_bool( $value ) ) {
309 | return $value ? 'true' : 'false';
310 | }
311 |
312 | return (string) $value;
313 | }
314 |
315 | /**
316 | * Render the additional buttons.
317 | *
318 | * @since 3.1.0
319 | * @return void
320 | */
321 | public function render_additional_buttons() {
322 | $buttons = [
323 | $this->get_explain_query_button(),
324 | $this->get_retrieve_raw_document_button(),
325 | ];
326 |
327 | /**
328 | * Filter the additional buttons.
329 | *
330 | * @since 3.1.0
331 | * @hook ep_debug_bar_additional_buttons
332 | * @param array $buttons Buttons.
333 | * @return array
334 | */
335 | apply_filters( 'ep_debug_bar_additional_buttons', $buttons );
336 |
337 | $buttons = array_filter( $buttons );
338 |
339 | if ( empty( $buttons ) ) {
340 | return;
341 | }
342 |
343 | ?>
344 |
345 |
350 |
351 | queries ) ) {
362 | return '';
363 | }
364 |
365 | $button_link = add_query_arg(
366 | [
367 | 'explain' => '1',
368 | ],
369 | isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''
370 | );
371 |
372 | return sprintf(
373 | '
374 | %s
375 | ',
376 | esc_url( $button_link ),
377 | esc_html__( 'Explain queries', 'debug-bar-elasticpress' )
378 | );
379 | }
380 |
381 | /**
382 | * Get the retrieve raw document button.
383 | *
384 | * @since 3.1.0
385 | * @return string
386 | */
387 | public function get_retrieve_raw_document_button(): string {
388 | if ( ! is_indexable_singular() ) {
389 | return '';
390 | }
391 |
392 | $button_link = add_query_arg(
393 | [
394 | 'ep-retrieve-es-document' => '1',
395 | '_wpnonce' => wp_create_nonce( 'ep-retrieve-es-document' ),
396 | ],
397 | isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''
398 | );
399 |
400 | return sprintf(
401 | '
402 | %s
403 | ',
404 | esc_url( $button_link ),
405 | esc_html__( 'Reload and retrieve raw ES document', 'debug-bar-elasticpress' )
406 | );
407 | }
408 | }
409 |
--------------------------------------------------------------------------------
/debug-bar-elasticpress.php:
--------------------------------------------------------------------------------
1 | get_elasticsearch_version();
127 | }
128 | if ( function_exists( '\ElasticPress\Utils\is_epio' ) && \ElasticPress\Utils\is_epio() ) {
129 | $elasticsearch_version = esc_html__( 'ElasticPress.io Managed Platform', 'debug-bar-elasticpress' );
130 | }
131 | $stati[] = array(
132 | 'es_version',
133 | esc_html__( 'Elasticsearch Version', 'debug-bar-elasticpress' ),
134 | $elasticsearch_version,
135 | );
136 | return $stati;
137 | }
138 |
139 | /**
140 | * Add explain=true to elastic post query
141 | *
142 | * @param array $formatted_args Formatted Elasticsearch query
143 | * @return array
144 | */
145 | function add_explain_args( $formatted_args ) {
146 | if ( isset( $_GET['explain'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
147 | $formatted_args['explain'] = true;
148 | }
149 | return $formatted_args;
150 | }
151 |
152 |
153 | /**
154 | * Render an admin notice about the absence of the minimum ElasticPress plugin version.
155 | *
156 | * @since 3.0.0
157 | */
158 | function admin_notice_min_ep_version() {
159 | ?>
160 |
171 | get( 'post' );
189 | $indexable_post_types = $post_indexable->get_indexable_post_types();
190 |
191 | return in_array( $post_type, $indexable_post_types, true );
192 | }
193 |
194 | /**
195 | * Get document from Elasticsearch.
196 | *
197 | * @since 3.1.0
198 | * @return void
199 | */
200 | function retrieve_raw_document_from_es() {
201 | if ( empty( $_GET['ep-retrieve-es-document'] ) || empty( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'ep-retrieve-es-document' ) ) {
202 | return;
203 | }
204 |
205 | if ( ! is_indexable_singular() ) {
206 | return;
207 | }
208 |
209 | \ElasticPress\Indexables::factory()->get( 'post' )->get( get_the_ID() );
210 | }
211 |
212 | /**
213 | * Include our QM Output
214 | *
215 | * @since 3.1.0
216 | * @param array $output Array of registered output
217 | * @return array
218 | */
219 | function register_qm_output( $output ) {
220 | $collector = \QM_Collectors::get( 'elasticpress' );
221 |
222 | if ( $collector ) {
223 | $output['elasticpress'] = new QueryMonitorOutput( $collector );
224 | }
225 |
226 | return $output;
227 | }
228 |
--------------------------------------------------------------------------------
/lang/debug-bar-elasticpress.pot:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2024 10up
2 | # This file is distributed under the GPLv2.
3 | msgid ""
4 | msgstr ""
5 | "Project-Id-Version: ElasticPress Debugging Add-On 3.1.1\n"
6 | "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/debug-bar-elasticpress\n"
7 | "Last-Translator: FULL NAME \n"
8 | "Language-Team: LANGUAGE \n"
9 | "MIME-Version: 1.0\n"
10 | "Content-Type: text/plain; charset=UTF-8\n"
11 | "Content-Transfer-Encoding: 8bit\n"
12 | "POT-Creation-Date: 2024-12-11T17:24:37+00:00\n"
13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14 | "X-Generator: WP-CLI 2.8.1\n"
15 | "X-Domain: debug-bar-elasticpress\n"
16 |
17 | #. Plugin Name of the plugin
18 | msgid "ElasticPress Debugging Add-On"
19 | msgstr ""
20 |
21 | #. Plugin URI of the plugin
22 | msgid "https://wordpress.org/plugins/debug-bar-elasticpress"
23 | msgstr ""
24 |
25 | #. Description of the plugin
26 | msgid "Extends the Query Monitor and Debug Bar plugins for ElasticPress queries."
27 | msgstr ""
28 |
29 | #. Author of the plugin
30 | msgid "10up"
31 | msgstr ""
32 |
33 | #. Author URI of the plugin
34 | msgid "https://10up.com"
35 | msgstr ""
36 |
37 | #. translators: %d: number of queries
38 | #: classes/CommonPanel.php:28
39 | msgid "ElasticPress (%d)"
40 | msgstr ""
41 |
42 | #: classes/CommonPanel.php:33
43 | #: classes/EP_Debug_Bar_ElasticPress.php:38
44 | msgid "ElasticPress"
45 | msgstr ""
46 |
47 | #: classes/CommonPanel.php:57
48 | msgid "ElasticPress is currently indexing."
49 | msgstr ""
50 |
51 | #. translators: queries count.
52 | #: classes/EP_Debug_Bar_ElasticPress.php:77
53 | msgid "Total ElasticPress Queries: %d"
54 | msgstr ""
55 |
56 | #. translators: blocking query time.
57 | #: classes/EP_Debug_Bar_ElasticPress.php:85
58 | msgid "Total Blocking ElasticPress Query Time: %d ms"
59 | msgstr ""
60 |
61 | #: classes/QueryFormatter.php:31
62 | msgid "Page URL"
63 | msgstr ""
64 |
65 | #: classes/QueryFormatter.php:32
66 | msgid "Elasticsearch Request"
67 | msgstr ""
68 |
69 | #: classes/QueryFormatter.php:33
70 | msgid "Request ID"
71 | msgstr ""
72 |
73 | #: classes/QueryFormatter.php:34
74 | msgid "Time"
75 | msgstr ""
76 |
77 | #: classes/QueryFormatter.php:35
78 | msgid "Time Spent (ms)"
79 | msgstr ""
80 |
81 | #: classes/QueryFormatter.php:36
82 | msgid "WP Query Args"
83 | msgstr ""
84 |
85 | #: classes/QueryFormatter.php:37
86 | msgid "HTTP Status Code"
87 | msgstr ""
88 |
89 | #: classes/QueryFormatter.php:38
90 | msgid "Query Body"
91 | msgstr ""
92 |
93 | #: classes/QueryFormatter.php:39
94 | msgid "Query Result"
95 | msgstr ""
96 |
97 | #: classes/QueryFormatter.php:51
98 | msgid "Error"
99 | msgstr ""
100 |
101 | #: classes/QueryFormatter.php:55
102 | msgid "Recommended Solution"
103 | msgstr ""
104 |
105 | #: classes/QueryLog.php:125
106 | #: classes/QueryLog.php:126
107 | msgid "Query Log"
108 | msgstr ""
109 |
110 | #: classes/QueryLog.php:239
111 | msgid "ElasticPress Query Log"
112 | msgstr ""
113 |
114 | #: classes/QueryLog.php:250
115 | msgid "Enable or disable query logging:"
116 | msgstr ""
117 |
118 | #: classes/QueryLog.php:255
119 | msgid "Disable"
120 | msgstr ""
121 |
122 | #: classes/QueryLog.php:256
123 | msgid "Enable for 5 minutes"
124 | msgstr ""
125 |
126 | #: classes/QueryLog.php:257
127 | msgid "Keep enabled"
128 | msgstr ""
129 |
130 | #: classes/QueryLog.php:262
131 | msgid "Note that query logging can have severe performance implications on your website."
132 | msgstr ""
133 |
134 | #. translators: date
135 | #: classes/QueryLog.php:267
136 | msgid "Logging queries until %s."
137 | msgstr ""
138 |
139 | #: classes/QueryLog.php:277
140 | msgid "Log by status:"
141 | msgstr ""
142 |
143 | #: classes/QueryLog.php:280
144 | msgid "Only failed queries"
145 | msgstr ""
146 |
147 | #: classes/QueryLog.php:281
148 | msgid "All queries"
149 | msgstr ""
150 |
151 | #: classes/QueryLog.php:286
152 | msgid "Log by context:"
153 | msgstr ""
154 |
155 | #: classes/QueryLog.php:290
156 | msgid "Public"
157 | msgstr ""
158 |
159 | #: classes/QueryLog.php:294
160 | msgid "Admin"
161 | msgstr ""
162 |
163 | #: classes/QueryLog.php:298
164 | msgid "AJAX"
165 | msgstr ""
166 |
167 | #: classes/QueryLog.php:302
168 | msgid "REST API"
169 | msgstr ""
170 |
171 | #. translators: Current limit
172 | #: classes/QueryLog.php:314
173 | msgid "Please note that logs are stored until the storage limit is reached. The current limit is: %s"
174 | msgstr ""
175 |
176 | #: classes/QueryLog.php:322
177 | msgid "Save Changes"
178 | msgstr ""
179 |
180 | #: classes/QueryLog.php:325
181 | msgid "Empty Log"
182 | msgstr ""
183 |
184 | #: classes/QueryLog.php:404
185 | msgid "Raw ES document"
186 | msgstr ""
187 |
188 | #: classes/QueryLog.php:409
189 | msgid "Elasticsearch check"
190 | msgstr ""
191 |
192 | #: classes/QueryLog.php:499
193 | msgid "Main query"
194 | msgstr ""
195 |
196 | #: classes/QueryLog.php:503
197 | msgid "Possible values for EP filter"
198 | msgstr ""
199 |
200 | #: classes/QueryLog.php:510
201 | msgid "Autosuggest template"
202 | msgstr ""
203 |
204 | #: classes/QueryLog.php:513
205 | msgid "Search"
206 | msgstr ""
207 |
208 | #: classes/QueryMonitorOutput.php:78
209 | msgid "Total ElasticPress Queries:"
210 | msgstr ""
211 |
212 | #: classes/QueryMonitorOutput.php:84
213 | msgid "Total Blocking ElasticPress Query Time:"
214 | msgstr ""
215 |
216 | #. translators: time spent
217 | #: classes/QueryMonitorOutput.php:91
218 | msgid "%d ms"
219 | msgstr ""
220 |
221 | #: classes/QueryOutput.php:53
222 | msgid "Download Requests Info"
223 | msgstr ""
224 |
225 | #: classes/QueryOutput.php:56
226 | msgid "Copy Requests Info to Clipboard"
227 | msgstr ""
228 |
229 | #: classes/QueryOutput.php:59
230 | #: classes/QueryOutput.php:260
231 | msgid "Copied!"
232 | msgstr ""
233 |
234 | #: classes/QueryOutput.php:79
235 | msgid "No queries to show"
236 | msgstr ""
237 |
238 | #. translators: Debug bar elasticpress error message
239 | #: classes/QueryOutput.php:144
240 | msgid "Error: %s"
241 | msgstr ""
242 |
243 | #. translators: Debug bar elasticpress recommended solution for the error
244 | #: classes/QueryOutput.php:152
245 | msgid "Recommended Solution: %s"
246 | msgstr ""
247 |
248 | #: classes/QueryOutput.php:159
249 | msgid "Errors:"
250 | msgstr ""
251 |
252 | #: classes/QueryOutput.php:166
253 | msgid "Type:"
254 | msgstr ""
255 |
256 | #: classes/QueryOutput.php:173
257 | msgid "Context:"
258 | msgstr ""
259 |
260 | #: classes/QueryOutput.php:179
261 | msgid "Host:"
262 | msgstr ""
263 |
264 | #. translators: time spent running the query.
265 | #: classes/QueryOutput.php:188
266 | msgid "Time Taken: %d ms"
267 | msgstr ""
268 |
269 | #: classes/QueryOutput.php:192
270 | msgid "Time Taken: -"
271 | msgstr ""
272 |
273 | #: classes/QueryOutput.php:199
274 | msgid "URL:"
275 | msgstr ""
276 |
277 | #: classes/QueryOutput.php:204
278 | msgid "Method:"
279 | msgstr ""
280 |
281 | #: classes/QueryOutput.php:210
282 | msgid "Headers:"
283 | msgstr ""
284 |
285 | #: classes/QueryOutput.php:217
286 | msgid "Query Args:"
287 | msgstr ""
288 |
289 | #: classes/QueryOutput.php:224
290 | msgid "Query Body:"
291 | msgstr ""
292 |
293 | #. translators: Query HTTP Code response
294 | #: classes/QueryOutput.php:243
295 | msgid "Query Response Code: HTTP %d"
296 | msgstr ""
297 |
298 | #: classes/QueryOutput.php:248
299 | msgid "Query Result:"
300 | msgstr ""
301 |
302 | #: classes/QueryOutput.php:253
303 | msgid "Query Response Code:"
304 | msgstr ""
305 |
306 | #: classes/QueryOutput.php:253
307 | msgid "Request Error"
308 | msgstr ""
309 |
310 | #: classes/QueryOutput.php:257
311 | msgid "Copy cURL Request"
312 | msgstr ""
313 |
314 | #: classes/QueryOutput.php:275
315 | msgid "Queries info"
316 | msgstr ""
317 |
318 | #: classes/QueryOutput.php:377
319 | msgid "Explain queries"
320 | msgstr ""
321 |
322 | #: classes/QueryOutput.php:405
323 | msgid "Reload and retrieve raw ES document"
324 | msgstr ""
325 |
326 | #: debug-bar-elasticpress.php:117
327 | msgid "ElasticPress Version"
328 | msgstr ""
329 |
330 | #: debug-bar-elasticpress.php:129
331 | msgid "ElasticPress.io Managed Platform"
332 | msgstr ""
333 |
334 | #: debug-bar-elasticpress.php:133
335 | msgid "Elasticsearch Version"
336 | msgstr ""
337 |
338 | #. translators: Min. EP version
339 | #: debug-bar-elasticpress.php:165
340 | msgid "ElasticPress Debugging Add-On needs at least ElasticPress %s to work properly."
341 | msgstr ""
342 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === ElasticPress Debugging Add-On ===
2 | Contributors: tlovett1, 10up
3 | Tags: debug, debug bar, elasticpress, elasticsearch
4 | Requires at least: 4.6
5 | Tested up to: 6.7
6 | Requires PHP: 7.0
7 | Stable tag: 3.1.1
8 | License: GPLv2
9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html
10 |
11 | Extends the Query Monitor and Debug Bar plugins for ElasticPress queries.
12 |
13 | == Description ==
14 |
15 | Allows you to examine every ElasticPress query running on any given request by adding an [ElasticPress](https://wordpress.org/plugins/elasticpress) panel to [Debug Bar](https://wordpress.org/plugins/debug-bar/) and/or [Query Monitor](https://wordpress.org/plugins/query-monitor/) plugins.
16 |
17 | Alternatively, go to ElasticPress > Query Log and set it to record ElasticPress queries.
18 |
19 | = Requirements: =
20 |
21 | * [ElasticPress 4.4.0+](https://wordpress.org/plugins/elasticpress)
22 | * [Debug Bar 1.0+](https://wordpress.org/plugins/debug-bar/)
23 | * PHP 7.0+
24 |
25 | == Installation ==
26 | 1. Install [ElasticPress](https://wordpress.org/plugins/elasticpress).
27 | 2. Optionally install [Debug Bar](https://wordpress.org/plugins/debug-bar/) or [Query Monitor](https://wordpress.org/plugins/query-monitor/).
28 | 3. Install the plugin in WordPress.
29 |
30 | == Changelog ==
31 |
32 | = 3.1.1 - 2024-12-11 =
33 |
34 | __Added:__
35 |
36 | * Display the number of queries in Query Monitor's tab title. Props [@felipeelia](https://github.com/felipeelia) and [@burhandodhy](https://github.com/burhandodhy).
37 | * ElasticPress as a plugin dependency. Props [@jeffpaul](https://github.com/jeffpaul).
38 |
39 | __Changed:__
40 |
41 | * More modern versions of GitHub Actions, node, and node packages. Props [@felipeelia](https://github.com/felipeelia).
42 |
43 | __Fixed:__
44 |
45 | * Notices related to i18n calls. Props [@felipeelia](https://github.com/felipeelia) and [@archon810](https://github.com/archon810).
46 | * Use new plugin name in the admin notice. Props [@burhandodhy](https://github.com/burhandodhy).
47 |
48 | = 3.1.0 - 2023-09-20 =
49 |
50 | __Added:__
51 |
52 | * New button to explain ES queries. Props [@burhandodhy](https://github.com/burhandodhy), [@felipeelia](https://github.com/felipeelia), [@MARQAS](https://github.com/MARQAS), and [@brandwaffle](https://github.com/brandwaffle).
53 | * New button to Reload and retrieve raw ES document. Props [@burhandodhy](https://github.com/burhandodhy), [@felipeelia](https://github.com/felipeelia), and [@brandwaffle](https://github.com/brandwaffle).
54 | * Query types (and context when listing queries in the Query Log admin screen.) Props [@felipeelia](https://github.com/felipeelia) and [@burhandodhy](https://github.com/burhandodhy).
55 | * Log query by context, status, and fixed time. Props [@felipeelia](https://github.com/felipeelia).
56 | * Official support to Query Monitor. Props [@felipeelia](https://github.com/felipeelia).
57 |
58 | __Security:__
59 |
60 | * Bumped `tough-cookie` from 4.1.2 to 4.1.3. Props [@dependabot](https://github.com/dependabot).
61 | * Bumped `word-wrap` from 1.2.3 to 1.2.4. Props [@dependabot](https://github.com/dependabot).
62 |
63 | = 3.0.0 - 2023-03-23 =
64 |
65 | This release drops the support for older versions of ElasticPress and PHP.
66 |
67 | __Added:__
68 |
69 | * Instructions with error code for failed queries. Props [@MARQAS](https://github.com/MARQAS) and [@felipeelia](https://github.com/felipeelia).
70 | * Buttons to copy or download all requests info. Props [@MARQAS](https://github.com/MARQAS), [@felipeelia](https://github.com/felipeelia), and [@burhandodhy](https://github.com/burhandodhy).
71 | * Compatibility with the WordPress localization system. Props [@burhandodhy](https://github.com/burhandodhy) and [@felipeelia](https://github.com/felipeelia).
72 | * SECURITY.md file. Props [@felipeelia](https://github.com/felipeelia).
73 |
74 | __Changed:__
75 |
76 | * Set minimum requirement for PHP to 7.0 and ElasticPress to 4.4.0. Props [@burhandodhy](https://github.com/burhandodhy) and [@felipeelia](https://github.com/felipeelia).
77 | * CSS and JS code lint by 10up toolkit. Props [@burhandodhy](https://github.com/burhandodhy).
78 |
79 | __Fixed:__
80 |
81 | * Unnecessary `stripslashes()` call when outputting JSON objects. Props [@felipeelia](https://github.com/felipeelia), [@goldenapples](https://github.com/goldenapples), and [@mattonomics](https://github.com/mattonomics).
82 | * JS error on copy action. Props [@burhandodhy](https://github.com/burhandodhy).
83 |
84 | __Security:__
85 |
86 | * Bumped `minimatch` from 3.0.4 to 3.1.2. Props [@dependabot](https://github.com/dependabot).
87 | * Bumped `json5` from 2.2.0 to 2.2.3. Props [@dependabot](https://github.com/dependabot).
88 | * Bumped `webpack` from 5.75.0 to 5.76.2. Props [@dependabot](https://github.com/dependabot).
89 |
90 |
91 | = 2.1.1 - 2022-08-04 =
92 |
93 | __Security:__
94 |
95 | * Fix XSS vulnerability. Props [@piotr-bajer](https://github.com/piotr-bajer) and [@felipeelia](https://github.com/felipeelia).
96 | * Bumped `path-parse` from 1.0.6 to 1.0.7. Props [@dependabot](https://github.com/dependabot).
97 | * Bumps `minimist` from 1.2.5 to 1.2.6. Props [@dependabot](https://github.com/dependabot).
98 | * Bumps `ansi-regex` from 5.0.0 to 5.0.1. Props [@dependabot](https://github.com/dependabot).
99 |
100 |
101 | = 2.1.0 =
102 |
103 | __Added:__
104 |
105 | * ElasticPress and Elasticsearch versions. Props to [@oscarssanchez](https://github.com/oscarssanchez) and [@felipeelia](https://github.com/felipeelia).
106 | * Log of bulk_index requests. Props [@felipeelia](https://github.com/felipeelia).
107 | * Warning when ElasticPress is indexing. Props [@nathanielks](https://github.com/nathanielks) and [@felipeelia](https://github.com/felipeelia).
108 |
109 | __Changed:__
110 |
111 | * Only load CSS and JS files for logged-in users. Props [@cbratschi](https://github.com/cbratschi) and [@felipeelia](https://github.com/felipeelia).
112 |
113 | = 2.0.0 =
114 | This release drops the support for older versions of WordPress Core, ElasticPress and Debug Bar.
115 |
116 | * Code refactoring. Props [@felipeelia](https://github.com/felipeelia)
117 | * Fixed Query Logs in EP Dashboard [@felipeelia](https://github.com/felipeelia)
118 | * Fixed typo from "clsas" to "class" in the query output. Props [@Rahmon](https://github.com/Rahmon)
119 |
120 | = 1.4 =
121 | * Support ElasticPress 3.0+
122 |
123 | = 1.3 =
124 | * Add query log
125 |
126 | = 1.2 =
127 | * Show query errors (i.e. cURL timeout)
128 | * Add ?explain to query if GET param is set
129 |
130 | = 1.1.1 =
131 | * Only show query body if it exits
132 |
133 | = 1.1 =
134 | * Improve formatting
135 | * Show original query args (EP 2.1+)
136 |
137 | = 1.0 =
138 | * Initial release
139 |
--------------------------------------------------------------------------------