From d887e72588d8eee92c033f76aca83c52cc553fd0 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Wed, 17 Sep 2025 18:49:37 +0100 Subject: [PATCH 01/12] Fixed selecting active filter. --- .../Templates/wpgraphql-logger-filters.php | 28 +++++++++---------- .../wpgraphql-logging/src/Events/Events.php | 18 ------------ 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php b/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php index 91dc67f1..15f5db81 100644 --- a/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php +++ b/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php @@ -7,26 +7,26 @@ } // Current filter values. -$current_level = $_GET['level_filter'] ?? ''; -$current_start_date = $_GET['start_date'] ?? ''; -$current_end_date = $_GET['end_date'] ?? ''; +$current_level = $_POST['level_filter'] ?? ''; +$current_start_date = $_POST['start_date'] ?? ''; +$current_end_date = $_POST['end_date'] ?? ''; $log_levels = [ 'debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency' ]; ?>
- - - diff --git a/plugins/wpgraphql-logging/src/Events/Events.php b/plugins/wpgraphql-logging/src/Events/Events.php index 53b732d0..231e4903 100644 --- a/plugins/wpgraphql-logging/src/Events/Events.php +++ b/plugins/wpgraphql-logging/src/Events/Events.php @@ -60,5 +60,4 @@ final class Events { * @var string */ public const REQUEST_RESULTS = 'graphql_request_results'; - } diff --git a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php index 83d77685..4ec5a1ce 100644 --- a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php +++ b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php @@ -28,7 +28,7 @@ protected function is_logging_enabled( array $config, ?string $query_string = nu $is_enabled = false; } - // Do not log the seedQuery for Faust.js + // Do not log the seedQuery for Faust.js. if ( $is_enabled && ( 'query GetSeedNode' === trim( $query_string ) ) ) { $is_enabled = false; } From 86632948c1c7d0e6c58d1dbba6bb4b65522ba819 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Wed, 17 Sep 2025 19:17:13 +0100 Subject: [PATCH 03/12] Fixed psalm errors. --- .../wpgraphql-logging/src/Admin/View/List/List_Table.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/wpgraphql-logging/src/Admin/View/List/List_Table.php b/plugins/wpgraphql-logging/src/Admin/View/List/List_Table.php index 0f0913a5..670d8e12 100644 --- a/plugins/wpgraphql-logging/src/Admin/View/List/List_Table.php +++ b/plugins/wpgraphql-logging/src/Admin/View/List/List_Table.php @@ -131,7 +131,7 @@ public function process_bulk_action(): void { } $nonce_action = 'bulk-' . esc_attr( $this->_args['plural'] ); - $nonce_value = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( (string) $_REQUEST['_wpnonce'] ) ) : ''; + $nonce_value = isset( $_REQUEST['_wpnonce'] ) && is_string( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : ''; $nonce = is_string( $nonce_value ) ? $nonce_value : ''; @@ -168,8 +168,8 @@ public function process_bulk_action(): void { $filter_keys = [ 'level_filter', 'start_date', 'end_date' ]; foreach ( $filter_keys as $key ) { - $value = isset( $_REQUEST[ $key ] ) ? sanitize_text_field( wp_unslash( (string) $_REQUEST[ $key ] ) ) : null; - if ( ! empty( $value ) && is_string( $value ) ) { + $value = isset( $_REQUEST[ $key ] ) && is_string( $_REQUEST[ $key ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $key ] ) ) : null; + if ( ! empty( $value ) ) { $preserved_filters[ $key ] = $value; } } From d7850671b88cd88a27b78ba5cdeb7bd1292dc012 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Wed, 17 Sep 2025 19:38:00 +0100 Subject: [PATCH 04/12] Added config options on whether to log the Faust.js seed query and response logs. --- .../Fields/Tab/Basic_Configuration_Tab.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php b/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php index ac69e1f5..b78c3244 100644 --- a/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php +++ b/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php @@ -52,6 +52,20 @@ class Basic_Configuration_Tab implements Settings_Tab_Interface { */ public const EVENT_LOG_SELECTION = 'event_log_selection'; + /** + * The field ID for the seed query exclusion for Faust.js. + * + * @var string + */ + public const SEED_QUERY = 'seed_query'; + + /** + * The field ID for whether to log the response from the WPGGraphQL query into the context object. + * + * @var string + */ + public const LOG_RESPONSE = 'log_response'; + /** * Get the name/identifier of the tab. */ @@ -134,6 +148,23 @@ public function get_fields(): array { true ); + + $fields[ self::SEED_QUERY ] = new Checkbox_Field( + self::SEED_QUERY, + $this->get_name(), + __( 'Log Seed Query', 'wpgraphql-logging' ), + '', + __( 'Whether or not to log the Faust.js seed query.', 'wpgraphql-logging' ), + ); + + $fields[ self::LOG_RESPONSE ] = new Checkbox_Field( + self::LOG_RESPONSE, + $this->get_name(), + __( 'Log Response', 'wpgraphql-logging' ), + '', + __( 'Whether or not to log the response from the WPGraphQL query into the context object.', 'wpgraphql-logging' ), + ); + return apply_filters( 'wpgraphql_logging_basic_configuration_fields', $fields ); } } From c61606ec077e78cb368462187396f22fc253e8d8 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 10:11:34 +0100 Subject: [PATCH 05/12] Refactored is_logging_enabled into a rule builder to reduce complexity. --- .../src/Events/QueryFilterLogger.php | 18 ++-- .../src/Logger/LoggingHelper.php | 100 +++++++----------- .../src/Logger/Rules/AdminUserRule.php | 41 +++++++ .../src/Logger/Rules/EnabledRule.php | 35 ++++++ .../Logger/Rules/IntrospectionQueryRule.php | 33 ++++++ .../src/Logger/Rules/IpRestrictionsRule.php | 52 +++++++++ .../src/Logger/Rules/LoggingRuleInterface.php | 29 +++++ .../src/Logger/Rules/QueryNullRule.php | 33 ++++++ .../src/Logger/Rules/RuleManager.php | 39 +++++++ .../src/Logger/Rules/SamplingRateRule.php | 37 +++++++ 10 files changed, 351 insertions(+), 66 deletions(-) create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/AdminUserRule.php create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/EnabledRule.php create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/LoggingRuleInterface.php create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/QueryNullRule.php create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/RuleManager.php create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/SamplingRateRule.php diff --git a/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php b/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php index 72c70cb8..ea6acf85 100644 --- a/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php +++ b/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php @@ -9,6 +9,7 @@ use WPGraphQL\Logging\Admin\Settings\Fields\Tab\Basic_Configuration_Tab; use WPGraphQL\Logging\Logger\LoggerService; use WPGraphQL\Logging\Logger\LoggingHelper; +use WPGraphQL\Logging\Logger\Rules\EnabledRule; use WPGraphQL\Request; /** @@ -62,10 +63,6 @@ public function __construct( LoggerService $logger, array $config ) { */ public function log_graphql_request_data( array $query_data ): array { try { - if ( ! $this->is_logging_enabled( $this->config ) ) { - return $query_data; - } - $selected_events = $this->config[ Basic_Configuration_Tab::EVENT_LOG_SELECTION ] ?? []; if ( ! is_array( $selected_events ) || empty( $selected_events ) ) { return $query_data; @@ -74,8 +71,13 @@ public function log_graphql_request_data( array $query_data ): array { return $query_data; } + $query_string = $query_data['query'] ?? null; + if ( ! $this->is_logging_enabled( $this->config, $query_string ) ) { + return $query_data; + } + $context = [ - 'query' => $query_data['query'] ?? null, + 'query' => $query_string, 'variables' => $query_data['variables'] ?? null, 'operation_name' => $query_data['operationName'] ?? null, ]; @@ -115,7 +117,7 @@ public function log_graphql_request_results( ?string $query_id ): array|ExecutionResult { try { - if ( ! $this->is_logging_enabled( $this->config ) ) { + if ( ! $this->is_logging_enabled( $this->config, $query ) ) { return $response; } @@ -169,7 +171,9 @@ public function log_graphql_request_results( * @return array The filtered array of headers. */ public function add_logging_headers( array $headers ): array { - if ( ! $this->is_logging_enabled( $this->config ) ) { + + $rule = new EnabledRule(); + if ( ! $rule->passes( $this->config ) ) { return $headers; } diff --git a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php index 4ec5a1ce..47cb4e4f 100644 --- a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php +++ b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php @@ -4,64 +4,59 @@ namespace WPGraphQL\Logging\Logger; -use WPGraphQL\Logging\Admin\Settings\Fields\Tab\Basic_Configuration_Tab; +use WPGraphQL\Logging\Logger\Rules\AdminUserRule; +use WPGraphQL\Logging\Logger\Rules\EnabledRule; +use WPGraphQL\Logging\Logger\Rules\IntrospectionQueryRule; +use WPGraphQL\Logging\Logger\Rules\IpRestrictionsRule; +use WPGraphQL\Logging\Logger\Rules\QueryNullRule; +use WPGraphQL\Logging\Logger\Rules\RuleManager; +use WPGraphQL\Logging\Logger\Rules\SamplingRateRule; /** * Trait for shared logging helper methods. + * + * @package WPGraphQL\Logging + * + * @since 0.0.1 */ trait LoggingHelper { /** - * Checks if logging is enabled based on user settings. - * - * @param array $config The logging configuration. + * The rule manager instance. * - * phpcs:disable Generic.Metrics.CyclomaticComplexity, SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh + * @var \WPGraphQL\Logging\Logger\Rules\RuleManager|null */ - protected function is_logging_enabled( array $config, ?string $query_string = null ): bool { - if ( null === $query_string ) { - return false; - } - - $is_enabled = true; - // Check the main "Enabled" checkbox. - if ( ! (bool) ( $config[ Basic_Configuration_Tab::ENABLED ] ?? false ) ) { - $is_enabled = false; - } + protected ?RuleManager $rule_manager = null; - // Do not log the seedQuery for Faust.js. - if ( $is_enabled && ( 'query GetSeedNode' === trim( $query_string ) ) ) { - $is_enabled = false; - } - - // Check if the current user is an admin if that option is enabled. - if ( $is_enabled && ( (bool) ( $config[ Basic_Configuration_Tab::ADMIN_USER_LOGGING ] ?? false ) ) ) { - if ( ! current_user_can( 'manage_options' ) ) { - $is_enabled = false; - } - } - - // Check for IP restrictions. - $ip_restrictions = $config[ Basic_Configuration_Tab::IP_RESTRICTIONS ] ?? ''; - if ( $is_enabled && ! empty( $ip_restrictions ) ) { - $allowed_ips = array_map( 'trim', explode( ',', $ip_restrictions ) ); - $remote_addr = $_SERVER['REMOTE_ADDR'] ?? ''; // @phpcs:ignore - if ( ! in_array( $remote_addr, $allowed_ips, true ) ) { - $is_enabled = false; - } + /** + * Get the rule manager, initializing it if necessary. + */ + protected function get_rule_manager(): RuleManager { + if ( null !== $this->rule_manager ) { + return $this->rule_manager; } + $this->rule_manager = new RuleManager(); + $this->rule_manager->add_rule( new QueryNullRule() ); + $this->rule_manager->add_rule( new SamplingRateRule() ); + $this->rule_manager->add_rule( new EnabledRule() ); + $this->rule_manager->add_rule( new AdminUserRule() ); + $this->rule_manager->add_rule( new IpRestrictionsRule() ); + $this->rule_manager->add_rule( new IntrospectionQueryRule() ); + apply_filters( 'wpgraphql_logging_rule_manager', $this->rule_manager ); + return $this->rule_manager; + } - // Check the data sampling rate. - if ( $is_enabled ) { - $sampling_rate = (int) ( $config[ Basic_Configuration_Tab::DATA_SAMPLING ] ?? 100 ); - if ( wp_rand( 0, 100 ) >= $sampling_rate ) { - $is_enabled = false; - } - } + /** + * Checks if logging is enabled based on user settings. + * + * @param array $config The logging configuration. + */ + protected function is_logging_enabled( array $config, ?string $query_string = null ): bool { - // Check if the query is an introspection query and skip logging if it is. - if ( $is_enabled && $this->is_introspection_query( $query_string ) ) { - $is_enabled = false; - } + $is_enabled = $this->get_rule_manager()->all_rules_pass( $config, $query_string ); + wp_send_json_error( [ + 'is_enabled' => $is_enabled, + 'query_string' => $query_string, + ], 200 ); /** * Filter the final decision on whether to log a request. @@ -71,17 +66,4 @@ protected function is_logging_enabled( array $config, ?string $query_string = nu */ return apply_filters( 'wpgraphql_logging_is_enabled', $is_enabled, $config ); } - - /** - * Checks if a query is an introspection query. - * - * @param string|null $query_string The GraphQL query string. - */ - protected function is_introspection_query( ?string $query_string ): bool { - if ( null === $query_string ) { - return false; - } - - return strpos( $query_string, '__schema' ) !== false; - } } diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/AdminUserRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/AdminUserRule.php new file mode 100644 index 00000000..e4d1e0e2 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/AdminUserRule.php @@ -0,0 +1,41 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + + $is_admin_user = (bool) ( $config[ Basic_Configuration_Tab::ADMIN_USER_LOGGING ] ?? false ); + if ( ! $is_admin_user ) { + return true; + } + + return current_user_can( 'manage_options' ); + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'admin_user_rule'; + } +} diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/EnabledRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/EnabledRule.php new file mode 100644 index 00000000..d8f98415 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/EnabledRule.php @@ -0,0 +1,35 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + return (bool) ( $config[ Basic_Configuration_Tab::ENABLED ] ?? false ); + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'enabled_rule'; + } +} diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php new file mode 100644 index 00000000..2263626f --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php @@ -0,0 +1,33 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + return strpos( $query_string, '__schema' ) === false; + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'introspection_query_rule'; + } +} diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php new file mode 100644 index 00000000..c8324a90 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php @@ -0,0 +1,52 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + + $ip_restrictions = $config[ Basic_Configuration_Tab::IP_RESTRICTIONS ] ?? ''; + if ( empty( $ip_restrictions ) ) { + return true; + } + $allowed_ips = array_map( 'trim', explode( ',', $ip_restrictions ) ); + if ( empty( $allowed_ips ) ) { + return true; + } + if ( ! isset( $_SERVER['REMOTE_ADDR'] ) ) { // @phpcs:ignore WordPressVIPMinimum.Variables.ServerVariables.UserControlledHeaders + return false; + } + + $remote_addr = filter_var( $_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP ); // @phpcs:ignore WordPressVIPMinimum.Variables.ServerVariables.UserControlledHeaders, WordPressVIPMinimum.Variables.RestrictedVariables.cache_constraints___SERVER__REMOTE_ADDR__ + if ( false === $remote_addr ) { + return false; + } + return in_array( $remote_addr, $allowed_ips, true ); + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'ip_restrictions_rule'; + } +} diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/LoggingRuleInterface.php b/plugins/wpgraphql-logging/src/Logger/Rules/LoggingRuleInterface.php new file mode 100644 index 00000000..cab5abd0 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/LoggingRuleInterface.php @@ -0,0 +1,29 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool; + + /** + * Get the rule name for debugging. + */ + public function get_name(): string; +} diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/QueryNullRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/QueryNullRule.php new file mode 100644 index 00000000..b455ef5d --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/QueryNullRule.php @@ -0,0 +1,33 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + return is_string( $query_string ) && '' !== trim( $query_string ); + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'query_null_rule'; + } +} diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/RuleManager.php b/plugins/wpgraphql-logging/src/Logger/Rules/RuleManager.php new file mode 100644 index 00000000..4849f245 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/RuleManager.php @@ -0,0 +1,39 @@ + */ + private array $rules = []; + + /** + * Add a rule to the manager. + */ + public function add_rule(LoggingRuleInterface $rule): void { + $this->rules[ $rule->get_name() ] = $rule; + } + + /** + * Check if all rules pass. + * + * @param array $config + * @param string|null $query_string + */ + public function all_rules_pass(array $config, ?string $query_string = null): bool { + foreach ( $this->rules as $rule ) { + if ( ! $rule->passes( $config, $query_string ) ) { + return false; + } + } + return true; + } +} diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/SamplingRateRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/SamplingRateRule.php new file mode 100644 index 00000000..450a8f65 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/SamplingRateRule.php @@ -0,0 +1,37 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + $sampling_rate = (int) ( $config[ Basic_Configuration_Tab::DATA_SAMPLING ] ?? 100 ); + $rand = wp_rand( 0, 100 ); + return $rand <= $sampling_rate; + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'enabled_rule'; + } +} From 890ecb9e839d6616bef9c5c76bd402960efbd3ab Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 10:59:42 +0100 Subject: [PATCH 06/12] Added SeedQuery check for Faust. --- .../src/Logger/LoggingHelper.php | 6 +-- .../Logger/Rules/IntrospectionQueryRule.php | 3 ++ .../src/Logger/Rules/IpRestrictionsRule.php | 5 +- .../src/Logger/Rules/SeedQueryRule.php | 46 +++++++++++++++++++ 4 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/SeedQueryRule.php diff --git a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php index 47cb4e4f..302ec0ac 100644 --- a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php +++ b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php @@ -11,6 +11,7 @@ use WPGraphQL\Logging\Logger\Rules\QueryNullRule; use WPGraphQL\Logging\Logger\Rules\RuleManager; use WPGraphQL\Logging\Logger\Rules\SamplingRateRule; +use WPGraphQL\Logging\Logger\Rules\SeedQueryRule; /** * Trait for shared logging helper methods. @@ -41,6 +42,7 @@ protected function get_rule_manager(): RuleManager { $this->rule_manager->add_rule( new AdminUserRule() ); $this->rule_manager->add_rule( new IpRestrictionsRule() ); $this->rule_manager->add_rule( new IntrospectionQueryRule() ); + $this->rule_manager->add_rule( new SeedQueryRule() ); apply_filters( 'wpgraphql_logging_rule_manager', $this->rule_manager ); return $this->rule_manager; } @@ -53,10 +55,6 @@ protected function get_rule_manager(): RuleManager { protected function is_logging_enabled( array $config, ?string $query_string = null ): bool { $is_enabled = $this->get_rule_manager()->all_rules_pass( $config, $query_string ); - wp_send_json_error( [ - 'is_enabled' => $is_enabled, - 'query_string' => $query_string, - ], 200 ); /** * Filter the final decision on whether to log a request. diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php index 2263626f..439c5a45 100644 --- a/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php +++ b/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php @@ -21,6 +21,9 @@ class IntrospectionQueryRule implements LoggingRuleInterface { * @return bool True if the rule passes (logging should continue). */ public function passes(array $config, ?string $query_string = null): bool { + if ( null === $query_string ) { + return true; + } return strpos( $query_string, '__schema' ) === false; } diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php index c8324a90..da291574 100644 --- a/plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php +++ b/plugins/wpgraphql-logging/src/Logger/Rules/IpRestrictionsRule.php @@ -29,9 +29,6 @@ public function passes(array $config, ?string $query_string = null): bool { return true; } $allowed_ips = array_map( 'trim', explode( ',', $ip_restrictions ) ); - if ( empty( $allowed_ips ) ) { - return true; - } if ( ! isset( $_SERVER['REMOTE_ADDR'] ) ) { // @phpcs:ignore WordPressVIPMinimum.Variables.ServerVariables.UserControlledHeaders return false; } @@ -47,6 +44,6 @@ public function passes(array $config, ?string $query_string = null): bool { * Get the rule name for debugging. */ public function get_name(): string { - return 'ip_restrictions_rule'; + return 'ip_restrictions'; } } diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/SeedQueryRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/SeedQueryRule.php new file mode 100644 index 00000000..ecdc1555 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/SeedQueryRule.php @@ -0,0 +1,46 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + + if ( null === $query_string ) { + return true; + } + + $allow_query = (bool) $config[ Basic_Configuration_Tab::SEED_QUERY ]; + if ( ! $allow_query ) { + return true; + } + return stripos( $query_string, 'SeedNode' ) === false; + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'faustjs_seed_query_rule'; + } +} From 689944620d62c8a8512c7eaea4f7253de87ce2d5 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 11:34:25 +0100 Subject: [PATCH 07/12] Added configuration for whether we should log the response. --- plugins/wpgraphql-logging/composer.json | 4 +- plugins/wpgraphql-logging/composer.lock | 387 +----------------- .../src/Events/QueryActionLogger.php | 6 + .../src/Events/QueryFilterLogger.php | 4 +- .../src/Logger/LoggingHelper.php | 13 + .../src/Logger/Rules/LogResponseRule.php | 35 ++ 6 files changed, 60 insertions(+), 389 deletions(-) create mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/LogResponseRule.php diff --git a/plugins/wpgraphql-logging/composer.json b/plugins/wpgraphql-logging/composer.json index 6dfc5d5c..6137264d 100644 --- a/plugins/wpgraphql-logging/composer.json +++ b/plugins/wpgraphql-logging/composer.json @@ -53,9 +53,7 @@ "phpstan/phpstan-strict-rules": "^2.0", "slevomat/coding-standard": "^8.0", "szepeviktor/phpstan-wordpress": "^2.0", - "wp-cli/wp-cli-bundle": "^2.8.1", - "wp-graphql/wp-graphql": "^2.3", - "wp-graphql/wp-graphql-testcase": "^3.0.1" + "wp-cli/wp-cli-bundle": "^2.8.1" }, "config": { "allow-plugins": { diff --git a/plugins/wpgraphql-logging/composer.lock b/plugins/wpgraphql-logging/composer.lock index 72fc3786..4dcc5a52 100644 --- a/plugins/wpgraphql-logging/composer.lock +++ b/plugins/wpgraphql-logging/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "39c90e7e58d79f6b447c2e916f498bdc", + "content-hash": "80763354fb1a58eacf78bd70d5e8cfbc", "packages": [ { "name": "league/csv", @@ -407,60 +407,6 @@ ], "time": "2024-04-13T18:00:56+00:00" }, - { - "name": "appsero/client", - "version": "v2.0.4", - "source": { - "type": "git", - "url": "https://github.com/Appsero/client.git", - "reference": "12ff65b9770286d21edf314e7acfcd26fdde3315" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Appsero/client/zipball/12ff65b9770286d21edf314e7acfcd26fdde3315", - "reference": "12ff65b9770286d21edf314e7acfcd26fdde3315", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2", - "phpcompatibility/phpcompatibility-wp": "dev-master", - "phpunit/phpunit": "^8.5.31", - "squizlabs/php_codesniffer": "^3.7", - "tareq1988/wp-php-cs-fixer": "dev-master", - "wp-coding-standards/wpcs": "dev-develop" - }, - "type": "library", - "autoload": { - "psr-4": { - "Appsero\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tareq Hasan", - "email": "tareq@appsero.com" - } - ], - "description": "Appsero Client", - "keywords": [ - "analytics", - "plugin", - "theme", - "wordpress" - ], - "support": { - "issues": "https://github.com/Appsero/client/issues", - "source": "https://github.com/Appsero/client/tree/v2.0.4" - }, - "time": "2024-11-25T05:58:23+00:00" - }, { "name": "automattic/vipwpcs", "version": "3.0.1", @@ -3144,51 +3090,6 @@ }, "time": "2024-04-01T10:36:11+00:00" }, - { - "name": "ivome/graphql-relay-php", - "version": "v0.7.0", - "source": { - "type": "git", - "url": "https://github.com/ivome/graphql-relay-php.git", - "reference": "06bd176103618d896197d85d04a3a17c91e39698" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ivome/graphql-relay-php/zipball/06bd176103618d896197d85d04a3a17c91e39698", - "reference": "06bd176103618d896197d85d04a3a17c91e39698", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "webonyx/graphql-php": "^14.0 || ^15.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "satooshi/php-coveralls": "~1.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "A PHP port of GraphQL Relay reference implementation", - "homepage": "https://github.com/ivome/graphql-relay-php", - "keywords": [ - "Relay", - "api", - "graphql" - ], - "support": { - "issues": "https://github.com/ivome/graphql-relay-php/issues", - "source": "https://github.com/ivome/graphql-relay-php/tree/v0.7.0" - }, - "time": "2023-10-20T15:43:03+00:00" - }, { "name": "johnpbloch/wordpress-core", "version": "6.8.2", @@ -4067,64 +3968,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "php-extended/polyfill-php80-str-utils", - "version": "1.3.7", - "source": { - "type": "git", - "url": "https://gitlab.com/php-extended/polyfill-php80-str-utils.git", - "reference": "0749426252e3e27c526fda939e8d3ff050bf907b" - }, - "dist": { - "type": "zip", - "url": "https://gitlab.com/api/v4/projects/php-extended%2Fpolyfill-php80-str-utils/repository/archive.zip?sha=0749426252e3e27c526fda939e8d3ff050bf907b", - "reference": "0749426252e3e27c526fda939e8d3ff050bf907b", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "php-extended/placeholder-phpunit": "^9" - }, - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "PhpExtended\\Polyfill\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Anastaszor", - "homepage": "https://gitlab.com/Anastaszor", - "role": "developer" - } - ], - "description": "A php implementation of string functions introduced in php8 and above", - "homepage": "https://gitlab.com/php-extended/polyfill-str-utils", - "keywords": [ - "implementation", - "php", - "polyfill", - "str", - "string_ends_with", - "string_starts_with", - "utils" - ], - "support": { - "issues": "https://gitlab.com/php-extended/polyfill-str-utils/issues", - "source": "https://gitlab.com/php-extended/polyfill-str-utils" - }, - "abandoned": "php >= 8.0", - "time": "2024-03-31T13:28:10+00:00" - }, { "name": "php-stubs/wordpress-globals", "version": "v0.2.0", @@ -9446,80 +9289,6 @@ }, "time": "2022-06-03T18:03:27+00:00" }, - { - "name": "webonyx/graphql-php", - "version": "v15.20.0", - "source": { - "type": "git", - "url": "https://github.com/webonyx/graphql-php.git", - "reference": "60feb7ad5023c0ef411efbdf9792d3df5812e28f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/60feb7ad5023c0ef411efbdf9792d3df5812e28f", - "reference": "60feb7ad5023c0ef411efbdf9792d3df5812e28f", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": "^7.4 || ^8" - }, - "require-dev": { - "amphp/amp": "^2.6", - "amphp/http-server": "^2.1", - "dms/phpunit-arraysubset-asserts": "dev-master", - "ergebnis/composer-normalize": "^2.28", - "friendsofphp/php-cs-fixer": "3.73.1", - "mll-lab/php-cs-fixer-config": "5.11.0", - "nyholm/psr7": "^1.5", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "2.1.8", - "phpstan/phpstan-phpunit": "2.0.4", - "phpstan/phpstan-strict-rules": "2.0.4", - "phpunit/phpunit": "^9.5 || ^10.5.21 || ^11", - "psr/http-message": "^1 || ^2", - "react/http": "^1.6", - "react/promise": "^2.0 || ^3.0", - "rector/rector": "^2.0", - "symfony/polyfill-php81": "^1.23", - "symfony/var-exporter": "^5 || ^6 || ^7", - "thecodingmachine/safe": "^1.3 || ^2 || ^3" - }, - "suggest": { - "amphp/http-server": "To leverage async resolving with webserver on AMPHP platform", - "psr/http-message": "To use standard GraphQL server", - "react/promise": "To leverage async resolving on React PHP platform" - }, - "type": "library", - "autoload": { - "psr-4": { - "GraphQL\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A PHP port of GraphQL reference implementation", - "homepage": "https://github.com/webonyx/graphql-php", - "keywords": [ - "api", - "graphql" - ], - "support": { - "issues": "https://github.com/webonyx/graphql-php/issues", - "source": "https://github.com/webonyx/graphql-php/tree/v15.20.0" - }, - "funding": [ - { - "url": "https://opencollective.com/webonyx-graphql-php", - "type": "open_collective" - } - ], - "time": "2025-03-21T08:45:04+00:00" - }, { "name": "wp-cli/cache-command", "version": "v2.2.0", @@ -11787,158 +11556,6 @@ ], "time": "2025-07-24T20:08:31+00:00" }, - { - "name": "wp-graphql/wp-graphql", - "version": "v2.3.3", - "source": { - "type": "git", - "url": "https://github.com/wp-graphql/wp-graphql.git", - "reference": "0b1512b746818bb3a0b0347f0a6841c811426f0f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-graphql/wp-graphql/zipball/0b1512b746818bb3a0b0347f0a6841c811426f0f", - "reference": "0b1512b746818bb3a0b0347f0a6841c811426f0f", - "shasum": "" - }, - "require": { - "appsero/client": "2.0.4", - "ivome/graphql-relay-php": "0.7.0", - "php": "^7.4 || ^8.0", - "webonyx/graphql-php": "15.20.0" - }, - "require-dev": { - "automattic/vipwpcs": "^3.0", - "codeception/module-asserts": "^1.0", - "codeception/module-cli": "^1.0", - "codeception/module-db": "^1.0", - "codeception/module-filesystem": "^1.0", - "codeception/module-phpbrowser": "^1.0", - "codeception/module-rest": "^1.2", - "codeception/module-webdriver": "^1.0", - "codeception/util-universalframework": "^1.0", - "composer/semver": "^3.0", - "dealerdirect/phpcodesniffer-composer-installer": "^1.0", - "lucatume/wp-browser": "<3.5", - "phpcompatibility/php-compatibility": "dev-develop as 9.9.9", - "phpcompatibility/phpcompatibility-wp": "^2.1", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "~2.1.2", - "phpstan/phpstan-deprecation-rules": "^2.0.1", - "phpunit/phpunit": "^9.5", - "slevomat/coding-standard": "^8.9", - "szepeviktor/phpstan-wordpress": "~2.0.1", - "wp-cli/wp-cli-bundle": "^2.8", - "wp-graphql/wp-graphql-testcase": "^3.0" - }, - "type": "wordpress-plugin", - "autoload": { - "files": [], - "psr-4": { - "WPGraphQL\\": "src/" - }, - "classmap": [ - "src/WPGraphQL.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "authors": [ - { - "name": "Jason Bahl", - "email": "jasonbahl@mac.com" - }, - { - "name": "Edwin Cromley" - }, - { - "name": "Ryan Kanner" - }, - { - "name": "Hughie Devore" - }, - { - "name": "Chris Zarate" - } - ], - "description": "GraphQL API for WordPress", - "support": { - "issues": "https://github.com/wp-graphql/wp-graphql/issues", - "source": "https://github.com/wp-graphql/wp-graphql/tree/v2.3.3" - }, - "time": "2025-06-17T14:27:16+00:00" - }, - { - "name": "wp-graphql/wp-graphql-testcase", - "version": "v3.4.0", - "source": { - "type": "git", - "url": "https://github.com/wp-graphql/wp-graphql-testcase.git", - "reference": "572d4c51e9a0a33ec1b99970155fe005f468f4ec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-graphql/wp-graphql-testcase/zipball/572d4c51e9a0a33ec1b99970155fe005f468f4ec", - "reference": "572d4c51e9a0a33ec1b99970155fe005f468f4ec", - "shasum": "" - }, - "require": { - "php-extended/polyfill-php80-str-utils": "^1.3" - }, - "require-dev": { - "automattic/vipwpcs": "^2.3", - "composer/installers": "^1.9", - "johnpbloch/wordpress": "^6.1", - "php-coveralls/php-coveralls": "2.4.3", - "squizlabs/php_codesniffer": "^3.5", - "wp-coding-standards/wpcs": "^2.3", - "wpackagist-plugin/wp-graphql": "^1.26" - }, - "suggest": { - "codeception/module-asserts": "Needed for \\Tests\\WPGraphQL\\TestCase\\WPGraphQLTestcase to work.", - "codeception/util-universalframework": "Needed for \\Tests\\WPGraphQL\\TestCase\\WPGraphQLTestcase to work.", - "guzzlehttp/guzzle": "Needed for \\Tests\\WPGraphQL\\Codeception\\Module\\WPGraphQL to work.", - "lucatume/wp-browser": "Needed for \\Tests\\WPGraphQL\\TestCase\\WPGraphQLTestcase to work.", - "phpunit/phpunit": "Needed for \\Tests\\WPGraphQL\\TestCase\\WPGraphQLUnitTestcase to work.", - "wp-phpunit/wp-phpunit": "Needed for \\Tests\\WPGraphQL\\TestCase\\WPGraphQLUnitTestcase to work.", - "yoast/phpunit-polyfills": "Needed for \\Tests\\WPGraphQL\\TestCase\\WPGraphQLUnitTestcase to work." - }, - "type": "library", - "extra": { - "installer-paths": { - "local/public/wp-content/plugins/{$name}/": [ - "type:wordpress-plugin" - ] - }, - "wordpress-install-dir": "local/public" - }, - "autoload": { - "psr-4": { - "Tests\\WPGraphQL\\": "src/" - }, - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Geoff Taylor", - "email": "geoffrey.taylor@outlook.com" - } - ], - "description": "Codeception module for WPGraphQL API testing", - "support": { - "issues": "https://github.com/wp-graphql/wp-graphql-testcase/issues", - "source": "https://github.com/wp-graphql/wp-graphql-testcase/tree/v3.4.0" - }, - "time": "2024-08-08T18:48:14+00:00" - }, { "name": "wp-hooks/wordpress-core", "version": "1.10.0", @@ -12039,7 +11656,7 @@ "platform": { "php": ">=8.1.2" }, - "platform-dev": [], + "platform-dev": {}, "platform-overrides": { "php": "8.1.2" }, diff --git a/plugins/wpgraphql-logging/src/Events/QueryActionLogger.php b/plugins/wpgraphql-logging/src/Events/QueryActionLogger.php index b35a13a7..015358d4 100644 --- a/plugins/wpgraphql-logging/src/Events/QueryActionLogger.php +++ b/plugins/wpgraphql-logging/src/Events/QueryActionLogger.php @@ -139,6 +139,9 @@ public function log_graphql_before_execute( Request $request ): void { * @param array|null $variables * @param \WPGraphQL\Request $request * @param string|null $query_id + * + * @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh + * @phpcs:disable SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh */ public function log_before_response_returned( array|ExecutionResult $filtered_response, @@ -170,6 +173,9 @@ public function log_before_response_returned( 'request' => $request, 'query_id' => $query_id, ]; + if ( ! $this->should_log_response( $this->config ) ) { + unset( $context['response'] ); + } $level = Level::Info; $message = 'WPGraphQL Response'; $errors = $this->get_response_errors( $response ); diff --git a/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php b/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php index ea6acf85..c6a5ca06 100644 --- a/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php +++ b/plugins/wpgraphql-logging/src/Events/QueryFilterLogger.php @@ -139,7 +139,9 @@ public function log_graphql_request_results( 'request' => $request, 'query_id' => $query_id, ]; - + if ( ! $this->should_log_response( $this->config ) ) { + unset( $context['response'] ); + } $level = Level::Info; $message = 'WPGraphQL Response'; if ( is_array( $response ) && isset( $response['errors'] ) && ! empty( $response['errors'] ) ) { diff --git a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php index 302ec0ac..c6bb0d6b 100644 --- a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php +++ b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php @@ -8,6 +8,7 @@ use WPGraphQL\Logging\Logger\Rules\EnabledRule; use WPGraphQL\Logging\Logger\Rules\IntrospectionQueryRule; use WPGraphQL\Logging\Logger\Rules\IpRestrictionsRule; +use WPGraphQL\Logging\Logger\Rules\LogResponseRule; use WPGraphQL\Logging\Logger\Rules\QueryNullRule; use WPGraphQL\Logging\Logger\Rules\RuleManager; use WPGraphQL\Logging\Logger\Rules\SamplingRateRule; @@ -28,6 +29,18 @@ trait LoggingHelper { */ protected ?RuleManager $rule_manager = null; + /** + * Determines if the response should be logged based on the configuration. + * + * @param array $config The logging configuration. + * + * @return bool True if the response should be logged, false otherwise. + */ + public function should_log_response(array $config): bool { + $rule = new LogResponseRule(); + return $rule->passes( $config ); + } + /** * Get the rule manager, initializing it if necessary. */ diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/LogResponseRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/LogResponseRule.php new file mode 100644 index 00000000..6c734b30 --- /dev/null +++ b/plugins/wpgraphql-logging/src/Logger/Rules/LogResponseRule.php @@ -0,0 +1,35 @@ + $config The logging configuration. + * @param string|null $query_string The GraphQL query string. + * + * @return bool True if the rule passes (logging should continue). + */ + public function passes(array $config, ?string $query_string = null): bool { + return (bool) ( $config[ Basic_Configuration_Tab::LOG_RESPONSE ] ?? false ); + } + + /** + * Get the rule name for debugging. + */ + public function get_name(): string { + return 'log_response_rule'; + } +} From ecafd46cf50d38c3db4d572e7f61b05f56e412eb Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 12:30:12 +0100 Subject: [PATCH 08/12] Fixed QA issues as WPGraphQL installed as a dev-dependency is causing issues. --- plugins/wpgraphql-logging/phpstan.neon.dist | 2 ++ plugins/wpgraphql-logging/psalm.xml | 22 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/plugins/wpgraphql-logging/phpstan.neon.dist b/plugins/wpgraphql-logging/phpstan.neon.dist index 58fb14d1..52477abc 100644 --- a/plugins/wpgraphql-logging/phpstan.neon.dist +++ b/plugins/wpgraphql-logging/phpstan.neon.dist @@ -34,3 +34,5 @@ parameters: - identifier: empty.notAllowed - message: '#Constant WPGRAPHQL_LOGGING.* not found\.#' + - + message: '#GraphQL\\.*#' diff --git a/plugins/wpgraphql-logging/psalm.xml b/plugins/wpgraphql-logging/psalm.xml index 9bf8ed5a..eca593fe 100644 --- a/plugins/wpgraphql-logging/psalm.xml +++ b/plugins/wpgraphql-logging/psalm.xml @@ -18,7 +18,6 @@ - @@ -48,5 +47,26 @@ + + + + + + + + + + + + + + + + + + + + + From 1c7daf82bd0f28807a80683af8dbbc66a6f4b42d Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 14:48:14 +0100 Subject: [PATCH 09/12] Added field to exclude queries rather than multiple rules. --- .../Fields/Tab/Basic_Configuration_Tab.php | 22 ++++++------ .../src/Logger/LoggingHelper.php | 6 ++-- ...SeedQueryRule.php => ExcludeQueryRule.php} | 21 +++++------ .../Logger/Rules/IntrospectionQueryRule.php | 36 ------------------- 4 files changed, 24 insertions(+), 61 deletions(-) rename plugins/wpgraphql-logging/src/Logger/Rules/{SeedQueryRule.php => ExcludeQueryRule.php} (60%) delete mode 100644 plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php diff --git a/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php b/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php index b78c3244..63105b7f 100644 --- a/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php +++ b/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php @@ -53,11 +53,11 @@ class Basic_Configuration_Tab implements Settings_Tab_Interface { public const EVENT_LOG_SELECTION = 'event_log_selection'; /** - * The field ID for the seed query exclusion for Faust.js. + * The field ID for the exclude query text input. * * @var string */ - public const SEED_QUERY = 'seed_query'; + public const EXCLUDE_QUERY = 'exclude_query'; /** * The field ID for whether to log the response from the WPGGraphQL query into the context object. @@ -107,6 +107,15 @@ public function get_fields(): array { __( 'e.g., 192.168.1.1, 10.0.0.1', 'wpgraphql-logging' ) ); + $fields[ self::EXCLUDE_QUERY ] = new Text_Input_Field( + self::EXCLUDE_QUERY, + $this->get_name(), + __( 'Exclude Query', 'wpgraphql-logging' ), + '', + __( 'Comma-separated list of GraphQL query names to exclude from logging.', 'wpgraphql-logging' ), + __( 'e.g., __schema,SeedNode,__typename', 'wpgraphql-logging' ) + ); + $fields[ self::ADMIN_USER_LOGGING ] = new Checkbox_Field( self::ADMIN_USER_LOGGING, $this->get_name(), @@ -148,15 +157,6 @@ public function get_fields(): array { true ); - - $fields[ self::SEED_QUERY ] = new Checkbox_Field( - self::SEED_QUERY, - $this->get_name(), - __( 'Log Seed Query', 'wpgraphql-logging' ), - '', - __( 'Whether or not to log the Faust.js seed query.', 'wpgraphql-logging' ), - ); - $fields[ self::LOG_RESPONSE ] = new Checkbox_Field( self::LOG_RESPONSE, $this->get_name(), diff --git a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php index c6bb0d6b..43734b43 100644 --- a/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php +++ b/plugins/wpgraphql-logging/src/Logger/LoggingHelper.php @@ -6,13 +6,12 @@ use WPGraphQL\Logging\Logger\Rules\AdminUserRule; use WPGraphQL\Logging\Logger\Rules\EnabledRule; -use WPGraphQL\Logging\Logger\Rules\IntrospectionQueryRule; +use WPGraphQL\Logging\Logger\Rules\ExcludeQueryRule; use WPGraphQL\Logging\Logger\Rules\IpRestrictionsRule; use WPGraphQL\Logging\Logger\Rules\LogResponseRule; use WPGraphQL\Logging\Logger\Rules\QueryNullRule; use WPGraphQL\Logging\Logger\Rules\RuleManager; use WPGraphQL\Logging\Logger\Rules\SamplingRateRule; -use WPGraphQL\Logging\Logger\Rules\SeedQueryRule; /** * Trait for shared logging helper methods. @@ -54,8 +53,7 @@ protected function get_rule_manager(): RuleManager { $this->rule_manager->add_rule( new EnabledRule() ); $this->rule_manager->add_rule( new AdminUserRule() ); $this->rule_manager->add_rule( new IpRestrictionsRule() ); - $this->rule_manager->add_rule( new IntrospectionQueryRule() ); - $this->rule_manager->add_rule( new SeedQueryRule() ); + $this->rule_manager->add_rule( new ExcludeQueryRule() ); apply_filters( 'wpgraphql_logging_rule_manager', $this->rule_manager ); return $this->rule_manager; } diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/SeedQueryRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/ExcludeQueryRule.php similarity index 60% rename from plugins/wpgraphql-logging/src/Logger/Rules/SeedQueryRule.php rename to plugins/wpgraphql-logging/src/Logger/Rules/ExcludeQueryRule.php index ecdc1555..2b57fc96 100644 --- a/plugins/wpgraphql-logging/src/Logger/Rules/SeedQueryRule.php +++ b/plugins/wpgraphql-logging/src/Logger/Rules/ExcludeQueryRule.php @@ -7,15 +7,13 @@ use WPGraphQL\Logging\Admin\Settings\Fields\Tab\Basic_Configuration_Tab; /** - * Rule to check if the query is a Faust.js Seed Query. + * Rule to check if the query is excluded from logging. * * @package WPGraphQL\Logging * - * @link https://github.com/wpengine/faustjs/blob/8e8797b1758d34d489236266e08f0657c015ff9f/packages/faustwp-core/src/queries/seedQuery.ts - * * @since 0.0.1 */ -class SeedQueryRule implements LoggingRuleInterface { +class ExcludeQueryRule implements LoggingRuleInterface { /** * Check if the rule passes. * @@ -25,22 +23,25 @@ class SeedQueryRule implements LoggingRuleInterface { * @return bool True if the rule passes (logging should continue). */ public function passes(array $config, ?string $query_string = null): bool { - + $queries = $config[ Basic_Configuration_Tab::EXCLUDE_QUERY ] ?? ''; if ( null === $query_string ) { return true; } - $allow_query = (bool) $config[ Basic_Configuration_Tab::SEED_QUERY ]; - if ( ! $allow_query ) { - return true; + $excluded_queries = array_map( 'trim', explode( ',', $queries ) ); + foreach ( $excluded_queries as $excluded_query ) { + if ( stripos( $query_string, $excluded_query ) !== false ) { + return false; + } } - return stripos( $query_string, 'SeedNode' ) === false; + + return true; } /** * Get the rule name for debugging. */ public function get_name(): string { - return 'faustjs_seed_query_rule'; + return 'exclude_query_rule'; } } diff --git a/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php b/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php deleted file mode 100644 index 439c5a45..00000000 --- a/plugins/wpgraphql-logging/src/Logger/Rules/IntrospectionQueryRule.php +++ /dev/null @@ -1,36 +0,0 @@ - $config The logging configuration. - * @param string|null $query_string The GraphQL query string. - * - * @return bool True if the rule passes (logging should continue). - */ - public function passes(array $config, ?string $query_string = null): bool { - if ( null === $query_string ) { - return true; - } - return strpos( $query_string, '__schema' ) === false; - } - - /** - * Get the rule name for debugging. - */ - public function get_name(): string { - return 'introspection_query_rule'; - } -} From fbe697529f761c7ea0d021721de83962cf384dae Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 18:40:55 +0100 Subject: [PATCH 10/12] Add uninstall option and update settings labels Added documentation and code to support optional database cleanup on plugin deactivation via the WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN constant. Updated admin settings field labels for clarity in the Basic Configuration tab. --- plugins/wpgraphql-logging/README.md | 29 +++++++++++++++++++ .../Fields/Tab/Basic_Configuration_Tab.php | 4 +-- plugins/wpgraphql-logging/src/Plugin.php | 6 +++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/plugins/wpgraphql-logging/README.md b/plugins/wpgraphql-logging/README.md index 3a8de27c..bc21377f 100644 --- a/plugins/wpgraphql-logging/README.md +++ b/plugins/wpgraphql-logging/README.md @@ -48,6 +48,35 @@ Once you have the composer repository setup, please run `composer req wpengine/w Plugin should start logging data, once activated. +--- + +## Uninstallation and Data Cleanup + +By default, WPGraphQL Logging preserves all logged data when the plugin is deactivated to prevent accidental data loss. If you want to completely remove all plugin data (including database tables) when deactivating the plugin, you must explicitly enable this behavior. + +### Enabling Database Cleanup on Deactivation + +To enable automatic database cleanup when the plugin is deactivated, add the following constant to your `wp-config.php` file or in a must-use plugin: + +```php +define( 'WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN', true ); +``` + +> [!WARNING] +> **Data Loss Warning**: When `WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN` is defined as `true`, deactivating the plugin will permanently delete all logged data and drop the plugin's database tables. This action is irreversible. + +### Manual Data Cleanup + +If you prefer to manually clean up data without defining the constant, you can: + +1. Use the plugin's admin interface to clear logs (when available) +2. Manually drop the database table: `{$wpdb->prefix}wpgraphql_logging` +3. Remove plugin options from the WordPress options table + +--- + +@TODO add more info once we have configuration setup. + @TODO add more info once we have configuration setup. diff --git a/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php b/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php index 63105b7f..92d49ed0 100644 --- a/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php +++ b/plugins/wpgraphql-logging/src/Admin/Settings/Fields/Tab/Basic_Configuration_Tab.php @@ -110,7 +110,7 @@ public function get_fields(): array { $fields[ self::EXCLUDE_QUERY ] = new Text_Input_Field( self::EXCLUDE_QUERY, $this->get_name(), - __( 'Exclude Query', 'wpgraphql-logging' ), + __( 'Exclude Queries', 'wpgraphql-logging' ), '', __( 'Comma-separated list of GraphQL query names to exclude from logging.', 'wpgraphql-logging' ), __( 'e.g., __schema,SeedNode,__typename', 'wpgraphql-logging' ) @@ -119,7 +119,7 @@ public function get_fields(): array { $fields[ self::ADMIN_USER_LOGGING ] = new Checkbox_Field( self::ADMIN_USER_LOGGING, $this->get_name(), - __( 'Log only for admin users', 'wpgraphql-logging' ), + __( 'Admin User Logging', 'wpgraphql-logging' ), '', __( 'Log only for admin users.', 'wpgraphql-logging' ) ); diff --git a/plugins/wpgraphql-logging/src/Plugin.php b/plugins/wpgraphql-logging/src/Plugin.php index 61621f8b..fb874379 100644 --- a/plugins/wpgraphql-logging/src/Plugin.php +++ b/plugins/wpgraphql-logging/src/Plugin.php @@ -101,9 +101,13 @@ public static function activate(): void { /** * Deactivation callback for the plugin. + * + * @since 0.0.1 */ public static function deactivate(): void { - // @TODO: Add configuration to determine if the table should be dropped on deactivation. + if ( ! defined( 'WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN' ) ) { + return; + } DatabaseEntity::drop_table(); } From 3474c1c86f3abecbf8cfc068cf4ee17800062725 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 18:48:01 +0100 Subject: [PATCH 11/12] Added clear all button for filters. --- .../src/Admin/View/Templates/wpgraphql-logger-filters.php | 6 ++++++ plugins/wpgraphql-logging/src/Plugin.php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php b/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php index c907dd7a..527f659f 100644 --- a/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php +++ b/plugins/wpgraphql-logging/src/Admin/View/Templates/wpgraphql-logger-filters.php @@ -40,4 +40,10 @@ class="wpgraphql-logging-datepicker" 'margin: 0;' ] ); ?> + + + +
diff --git a/plugins/wpgraphql-logging/src/Plugin.php b/plugins/wpgraphql-logging/src/Plugin.php index fb874379..0c590a96 100644 --- a/plugins/wpgraphql-logging/src/Plugin.php +++ b/plugins/wpgraphql-logging/src/Plugin.php @@ -106,7 +106,7 @@ public static function activate(): void { */ public static function deactivate(): void { if ( ! defined( 'WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN' ) ) { - return; + return; } DatabaseEntity::drop_table(); } From 4aae0fa56aedd64b30add448cf0df43e55b71455 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 18 Sep 2025 18:51:26 +0100 Subject: [PATCH 12/12] Added Changeset --- .changeset/gorgeous-planes-prove.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gorgeous-planes-prove.md diff --git a/.changeset/gorgeous-planes-prove.md b/.changeset/gorgeous-planes-prove.md new file mode 100644 index 00000000..3b588494 --- /dev/null +++ b/.changeset/gorgeous-planes-prove.md @@ -0,0 +1,5 @@ +--- +"@wpengine/wpgraphql-logging-wordpress-plugin": patch +--- + +chore: Various snags.