From 1c5f25d8b0f1cc1634e4bb8a0f45907ef78eb9d4 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:04:27 +0000 Subject: [PATCH 01/12] PHPCS: escape template output and drop the unused var_dump field template - Container start: esc_attr() on the id and class attributes (values were already sanitized, output is unchanged). - Changelog: wp_kses_post() on the generated changelog HTML (p, ul, li, a, code only) and esc_html_e() for the heading. - Error page: esc_html_e() for the heading, a translators comment, and a local variable that no longer shadows the $locale global. - Raw field: documented phpcs:ignore, the field prints plugin-built markup by design. - components/field.php only held two var_dump() calls and is never rendered. --- .../fields/components/container/start.php | 4 ++-- src/templates/fields/components/field.php | 4 ---- src/templates/fields/raw.php | 2 +- src/templates/pages/changelog.php | 4 ++-- src/templates/pages/error.php | 22 ++++++++++++++----- 5 files changed, 21 insertions(+), 15 deletions(-) delete mode 100644 src/templates/fields/components/field.php diff --git a/src/templates/fields/components/container/start.php b/src/templates/fields/components/container/start.php index 0778570a..170d6fd5 100644 --- a/src/templates/fields/components/container/start.php +++ b/src/templates/fields/components/container/start.php @@ -4,6 +4,6 @@ ?> diff --git a/src/templates/fields/components/field.php b/src/templates/fields/components/field.php deleted file mode 100644 index 841d7687..00000000 --- a/src/templates/fields/components/field.php +++ /dev/null @@ -1,4 +0,0 @@ -render( 'components/container/start' ); ?> - get_raw_html(); ?> + get_raw_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, StellarWP.XSS.EscapeOutput.OutputNotEscaped -- A raw field exists to print markup built by plugin code (buttons, inputs); escaping would break it. ?> render( 'components/container/end' ); ?> diff --git a/src/templates/pages/changelog.php b/src/templates/pages/changelog.php index 7a63bf26..fbfc5bd3 100644 --- a/src/templates/pages/changelog.php +++ b/src/templates/pages/changelog.php @@ -16,7 +16,7 @@ }
-

+

changelog->versions as $number => $version ) : ?>

number ); ?> — date ); ?>

- html; ?> + html ); ?>
diff --git a/src/templates/pages/error.php b/src/templates/pages/error.php index b48bd998..97af8c32 100644 --- a/src/templates/pages/error.php +++ b/src/templates/pages/error.php @@ -1,20 +1,30 @@ 'FakerPress', 'related' => 'webord', ]; -$locale = get_locale(); -if ( ! empty( $locale ) ) { - $tweet_args['hashtags'] .= ',' . esc_attr( $locale ); +$site_locale = get_locale(); +if ( ! empty( $site_locale ) ) { + $tweet_args['hashtags'] .= ',' . esc_attr( $site_locale ); } $tweet_url = esc_url_raw( add_query_arg( $tweet_args, 'https://twitter.com/intent/tweet' ) ); ?>
-

+

- poke us on twitter!", 'fakerpress' ), $tweet_url ) ) ); ?> + poke us on twitter!", 'fakerpress' ), + $tweet_url + ) + ) + ); + ?>
From def146c5d7c251c60ecf144f000ea07301b1d961 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:04:27 +0000 Subject: [PATCH 02/12] PHPCS: annotate public helper signatures and the generic request reader Reserved-word parameter names ($array, $default, $var, $class) stay as they are because renaming them breaks named arguments; each gets a targeted ignore. unset_var() documents why its catch is empty. --- src/functions/conditionals.php | 2 +- src/functions/container.php | 8 +++++--- src/functions/variables.php | 10 +++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/functions/conditionals.php b/src/functions/conditionals.php index 2d502f4b..cf2560e8 100644 --- a/src/functions/conditionals.php +++ b/src/functions/conditionals.php @@ -11,7 +11,7 @@ * * @return bool */ -function is_truthy( $var ): bool { +function is_truthy( $var ): bool { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.varFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. if ( is_bool( $var ) ) { return $var; } diff --git a/src/functions/container.php b/src/functions/container.php index 290afc40..4b67b07f 100644 --- a/src/functions/container.php +++ b/src/functions/container.php @@ -61,7 +61,7 @@ * will be called only once after the singleton instance * construction. */ -function singleton( $slug, $class, ?array $after_build_methods = null ) { +function singleton( $slug, $class, ?array $after_build_methods = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.classFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. Container::init()->singleton( $slug, $class, $after_build_methods ); } @@ -125,7 +125,7 @@ function singleton( $slug, $class, ?array $after_build_methods = null ) { * the built object after the `__construct` method; the methods * will be called each time after the instance construction. */ -function bind( $slug, $class, ?array $after_build_methods = null ) { +function bind( $slug, $class, ?array $after_build_methods = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.classFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. Container::init()->bind( $slug, $class, $after_build_methods ); } @@ -189,7 +189,7 @@ function set_var( $slug, $value ) { * @return mixed Either the registered value or the default value if the variable * is not registered. */ -function get_var( $slug, $default = null ) { +function get_var( $slug, $default = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. try { $var = Container::init()->getVar( $slug ); } catch ( \InvalidArgumentException $e ) { @@ -218,6 +218,8 @@ function unset_var( $slug ) { try { Container::init()->offsetUnset( $slug ); } catch ( \Exception $e ) { + // Unsetting a variable that was never registered is not an error. + return; } } diff --git a/src/functions/variables.php b/src/functions/variables.php index b6952c3f..4de6cbdd 100644 --- a/src/functions/variables.php +++ b/src/functions/variables.php @@ -17,7 +17,7 @@ * * @return array Full array with the key set to the specified value. */ -function set( array $array, $key, $value ) { +function set( array $array, $key, $value ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. // Convert strings and such to array. $key = (array) $key; @@ -67,7 +67,7 @@ function set( array $array, $key, $value ) { * * @return mixed The value of the specified index or the default if not found. */ -function get( $variable, $indexes, $default = null ) { +function get( $variable, $indexes, $default = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. if ( is_object( $variable ) ) { $variable = (array) $variable; } @@ -103,7 +103,7 @@ function get( $variable, $indexes, $default = null ) { * * @return mixed The value of the specified index or the default if not found. */ -function get_in_any( array $variables, $indexes, $default = null ) { +function get_in_any( array $variables, $indexes, $default = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. foreach ( $variables as $variable ) { $found = get( $variable, $indexes, '__not_found__' ); if ( '__not_found__' !== $found ) { @@ -132,8 +132,8 @@ function get_in_any( array $variables, $indexes, $default = null ) { * * @return mixed */ -function get_request_var( $indexes, $default = null ) { - return get_in_any( [ $_GET, $_POST, $_REQUEST ], $indexes, $default ); +function get_request_var( $indexes, $default = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. + return get_in_any( [ $_GET, $_POST, $_REQUEST ], $indexes, $default ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing -- Generic request reader, callers verify the nonce or capability before acting on the value. } /** From 1a5b8b8432e1ae7ed996edcd6cb997fef5b370eb Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:09:27 +0000 Subject: [PATCH 03/12] PHPCS: admin pages, translator comments and escaping - Translators comments for the page title and the 'Faked %1$d new %2$s' notices. - 'Contact Support' link text uses esc_html__() (same output as esc_attr__()). - Split chained assignments in Admin::add_message() and Menu::add(); the stored objects are the same. - Group the Menu.php use statements. - Targeted ignores: underscore-prefixed hook callbacks and Menu::add( $parent ) are public API, the submenu relabel needs the $submenu global, and correctly_set_current_screen() keeps its hook argument. --- src/FakerPress/Admin.php | 24 ++++++++++++------- src/FakerPress/Admin/Menu.php | 14 ++++++----- src/FakerPress/Admin/View/Attachment_View.php | 1 + src/FakerPress/Admin/View/Comment_View.php | 1 + src/FakerPress/Admin/View/Post_View.php | 2 ++ src/FakerPress/Admin/View/Term_View.php | 1 + src/FakerPress/Admin/View/User_View.php | 1 + 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/FakerPress/Admin.php b/src/FakerPress/Admin.php index 7cb4b4ce..d759adb6 100644 --- a/src/FakerPress/Admin.php +++ b/src/FakerPress/Admin.php @@ -73,12 +73,14 @@ public static function add_message( $html, $type = 'success', $priority = 10 ) { * @filter fakerpress.messages.allowed_html * @since 0.1.2 */ - self::$messages[] = $message = (object) [ + $message = (object) [ 'html' => wp_kses( wpautop( $html ), apply_filters( 'fakerpress.messages.allowed_html', [] ), [ 'http', 'https' ] ), 'type' => esc_attr( $type ), 'priority' => $priority === 0 ? $priority + 1 : $priority, ]; + self::$messages[] = $message; + usort( self::$messages, 'FakerPress\sort_by_priority' ); return $message; @@ -92,7 +94,7 @@ public static function add_message( $html, $type = 'success', $priority = 10 ) { * @since 0.1.2 * @return null Actions do not return */ - public function _action_admin_notices() { + public function _action_admin_notices() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Public hook callback name, renaming breaks third-party remove_action()/remove_filter() calls. foreach ( self::$messages as $k => $message ) { $classes = [ // Plugin class to give the styling @@ -156,13 +158,17 @@ public function get_base_title(): string { * * @param string $title Which base title will be used. */ - return apply_filters( 'fakerpress.admin.title_base', __( '%s on FakerPress', 'fakerpress' ) ); + return apply_filters( + 'fakerpress.admin.title_base', + /* translators: %s: Title of the current FakerPress admin page. */ + __( '%s on FakerPress', 'fakerpress' ) + ); } /** * @todo refactor */ - public function _filter_set_admin_page_title( $admin_title, $title ) { + public function _filter_set_admin_page_title( $admin_title, $title ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Public hook callback name, renaming breaks third-party remove_action()/remove_filter() calls. if ( ! $this->is_active() ) { return $admin_title; } @@ -176,7 +182,7 @@ public function _filter_set_admin_page_title( $admin_title, $title ) { return $admin_title; } - public function _filter_messages_allowed_html() { + public function _filter_messages_allowed_html() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Public hook callback name, renaming breaks third-party remove_action()/remove_filter() calls. return [ 'a' => [ 'class' => [], @@ -222,12 +228,12 @@ public function _filter_messages_allowed_html() { * @uses \FakerPress\Plugin::$slug * @return string */ - public function _filter_admin_footer_text( $text ) { + public function _filter_admin_footer_text( $text ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Public hook callback name, renaming breaks third-party remove_action()/remove_filter() calls. if ( ! $this->is_active() ) { return $text; } - return '' . esc_attr__( 'Contact Support', 'fakerpress' ) . ' | ' . + return '' . esc_html__( 'Contact Support', 'fakerpress' ) . ' | ' . str_replace( [ '[stars]', '[wp.org]' ], [ @@ -249,7 +255,7 @@ public function _filter_admin_footer_text( $text ) { * @uses \FakerPress\Plugin::$slug * @return string */ - public function _filter_update_footer( $text ) { + public function _filter_update_footer( $text ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Public hook callback name, renaming breaks third-party remove_action()/remove_filter() calls. if ( ! $this->is_active() ) { return $text; } @@ -276,7 +282,7 @@ public function _filter_update_footer( $text ) { return $sponsor . $translate . $version; } - public function _filter_body_class( $classes ) { + public function _filter_body_class( $classes ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Public hook callback name, renaming breaks third-party remove_action()/remove_filter() calls. $more = [ $classes, '__fakerpress', diff --git a/src/FakerPress/Admin/Menu.php b/src/FakerPress/Admin/Menu.php index 6dd32b1a..7c977de1 100644 --- a/src/FakerPress/Admin/Menu.php +++ b/src/FakerPress/Admin/Menu.php @@ -3,11 +3,11 @@ namespace FakerPress\Admin; use FakerPress\Admin\View\Factory as View_Factory; -use function FakerPress\make; - use FakerPress\Plugin; use FakerPress\Admin; +use function FakerPress\make; + /** * Class Menu * @@ -45,10 +45,10 @@ class Menu { * @param callable|null $callback A callback to render this menu item. * @param string|null $parent What is the parent menu. */ - public static function add( string $slug, $title, $label, string $capability = 'manage_options', int $priority = 10, $callback = null, $parent = null ): void { + public static function add( string $slug, $title, $label, string $capability = 'manage_options', int $priority = 10, $callback = null, $parent = null ): void { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.parentFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. $slug = sanitize_key( $slug ); - static::$items[ $slug ] = $menu = (object) [ + $menu = (object) [ 'slug' => $slug, 'title' => esc_attr( $title ), 'hook' => null, // Will be set later from WP. @@ -59,6 +59,8 @@ public static function add( string $slug, $title, $label, string $capability = ' 'parent' => $parent, // Used to set up error page. ]; + static::$items[ $slug ] = $menu; + if ( ! is_callable( $menu->callback ) ) { $menu->callback = static function () use ( $menu ) { $menu = make( Menu::class )->get_current(); @@ -199,7 +201,7 @@ public function register_menus_to_wp() { // Change the Default Submenu for FakerPress menus if ( ! empty( $GLOBALS['submenu'][ Plugin::$slug ] ) ) { - $GLOBALS['submenu'][ Plugin::$slug ][0][0] = esc_attr__( 'Settings', 'fakerpress' ); + $GLOBALS['submenu'][ Plugin::$slug ][0][0] = esc_attr__( 'Settings', 'fakerpress' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Relabels the auto-created first submenu item, which WordPress only exposes through this global. } } @@ -213,7 +215,7 @@ public function register_menus_to_wp() { * * @return void */ - public function correctly_set_current_screen( $screen ) { + public function correctly_set_current_screen( $screen ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Public method called from the current_screen action with the screen argument, kept for BC. $view = make( View_Factory::class )->get_current_view(); if ( ! $view ) { return; diff --git a/src/FakerPress/Admin/View/Attachment_View.php b/src/FakerPress/Admin/View/Attachment_View.php index d9e6d108..b40946a2 100644 --- a/src/FakerPress/Admin/View/Attachment_View.php +++ b/src/FakerPress/Admin/View/Attachment_View.php @@ -97,6 +97,7 @@ public function parse_request() { if ( ! empty( $results ) ) { return Admin::add_message( sprintf( + /* translators: 1: Number of items created, 2: Item type label (singular or plural), 3: Comma-separated links to the new items. */ __( 'Faked %1$d new %2$s: [ %3$s ]', 'fakerpress' ), count( $results ), _n( 'attachment', 'attachments', count( $results ), 'fakerpress' ), diff --git a/src/FakerPress/Admin/View/Comment_View.php b/src/FakerPress/Admin/View/Comment_View.php index 207c711f..f5030bca 100644 --- a/src/FakerPress/Admin/View/Comment_View.php +++ b/src/FakerPress/Admin/View/Comment_View.php @@ -94,6 +94,7 @@ public function parse_request() { if ( ! empty( $results ) ) { return Admin::add_message( sprintf( + /* translators: 1: Number of items created, 2: Item type label (singular or plural), 3: Comma-separated links to the new items. */ __( 'Faked %1$d new %2$s: [ %3$s ]', 'fakerpress' ), count( $results ), _n( 'comment', 'comments', count( $results ), 'fakerpress' ), diff --git a/src/FakerPress/Admin/View/Post_View.php b/src/FakerPress/Admin/View/Post_View.php index 54ca684b..c1741234 100644 --- a/src/FakerPress/Admin/View/Post_View.php +++ b/src/FakerPress/Admin/View/Post_View.php @@ -58,6 +58,7 @@ protected function get_page_data(): array { $default_taxonomy_names = array_values( array_intersect( [ 'category', 'post_tag' ], array_keys( $taxonomies ) ) ); + $default_taxonomy = empty( $default_taxonomy_names ) ? [] : [ @@ -169,6 +170,7 @@ public function parse_request() { if ( ! empty( $results ) ) { return Admin::add_message( sprintf( + /* translators: 1: Number of items created, 2: Item type label (singular or plural), 3: Comma-separated links to the new items. */ __( 'Faked %1$d new %2$s: [ %3$s ]', 'fakerpress' ), count( $results ), _n( 'post', 'posts', count( $results ), 'fakerpress' ), diff --git a/src/FakerPress/Admin/View/Term_View.php b/src/FakerPress/Admin/View/Term_View.php index 432e0179..6d897005 100644 --- a/src/FakerPress/Admin/View/Term_View.php +++ b/src/FakerPress/Admin/View/Term_View.php @@ -93,6 +93,7 @@ public function parse_request() { } else { return Admin::add_message( sprintf( + /* translators: 1: Number of items created, 2: Item type label (singular or plural), 3: Comma-separated links to the new items. */ __( 'Faked %1$d new %2$s: [ %3$s ]', 'fakerpress' ), count( $results ), _n( 'term', 'terms', count( $results ), 'fakerpress' ), diff --git a/src/FakerPress/Admin/View/User_View.php b/src/FakerPress/Admin/View/User_View.php index 06672c18..fec8bbb9 100644 --- a/src/FakerPress/Admin/View/User_View.php +++ b/src/FakerPress/Admin/View/User_View.php @@ -93,6 +93,7 @@ public function parse_request() { if ( ! empty( $results ) ) { return Admin::add_message( sprintf( + /* translators: 1: Number of items created, 2: Item type label (singular or plural), 3: Comma-separated links to the new items. */ __( 'Faked %1$d new %2$s: [ %3$s ]', 'fakerpress' ), count( $results ), _n( 'user', 'users', count( $results ), 'fakerpress' ), From 07a132419f9534152ac3cdb4af09b120239d42f0 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:09:27 +0000 Subject: [PATCH 04/12] PHPCS: REST translator comments and translatable batch labels - Translators comments on the permission errors and the batch success messages. - format_batched_success_message() passed a variable to _n(), which no string extractor can pick up. get_batched_item_label() now uses a literal _n() per known type (post, user, term, comment, attachment) and keeps the old fallback for anything else. - Rename the endpoint closure parameter $class to $endpoint_class. - Targeted ignores for the OpenAPI class name and the term-search 'exclude' argument; align the Terms arg arrays. --- src/FakerPress/REST/Controller.php | 4 +-- src/FakerPress/REST/Endpoints/Attachments.php | 1 + src/FakerPress/REST/Endpoints/Comments.php | 1 + src/FakerPress/REST/Endpoints/Posts.php | 1 + src/FakerPress/REST/Endpoints/Terms.php | 11 +++--- src/FakerPress/REST/Endpoints/Users.php | 1 + src/FakerPress/REST/OpenAPI.php | 2 ++ .../REST/Traits/Handles_Batching.php | 34 ++++++++++++++++++- 8 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/FakerPress/REST/Controller.php b/src/FakerPress/REST/Controller.php index 3af1c986..6a1d17c4 100644 --- a/src/FakerPress/REST/Controller.php +++ b/src/FakerPress/REST/Controller.php @@ -124,8 +124,8 @@ protected function load_endpoints() { ); $endpoints = array_map( - static function ( $class ) { - return class_exists( $class ) ? make( $class ) : null; + static function ( $endpoint_class ) { + return class_exists( $endpoint_class ) ? make( $endpoint_class ) : null; }, $endpoint_classes ); diff --git a/src/FakerPress/REST/Endpoints/Attachments.php b/src/FakerPress/REST/Endpoints/Attachments.php index c69bcf77..687cd319 100644 --- a/src/FakerPress/REST/Endpoints/Attachments.php +++ b/src/FakerPress/REST/Endpoints/Attachments.php @@ -117,6 +117,7 @@ public function generate_attachments( $request ) { if ( ! current_user_can( $permission_required ) ) { return $this->error_response( sprintf( + /* translators: %s: Name of the WordPress capability the current user is missing. */ __( 'Your user needs the "%s" permission to generate attachments.', 'fakerpress' ), $permission_required ), diff --git a/src/FakerPress/REST/Endpoints/Comments.php b/src/FakerPress/REST/Endpoints/Comments.php index 90f22e2f..fc14d3f3 100644 --- a/src/FakerPress/REST/Endpoints/Comments.php +++ b/src/FakerPress/REST/Endpoints/Comments.php @@ -120,6 +120,7 @@ public function generate_comments( $request ) { if ( ! current_user_can( $permission_required ) ) { return $this->error_response( sprintf( + /* translators: %s: Name of the WordPress capability the current user is missing. */ __( 'Your user needs the "%s" permission to generate comments.', 'fakerpress' ), $permission_required ), diff --git a/src/FakerPress/REST/Endpoints/Posts.php b/src/FakerPress/REST/Endpoints/Posts.php index 6d886248..cbadbdfc 100644 --- a/src/FakerPress/REST/Endpoints/Posts.php +++ b/src/FakerPress/REST/Endpoints/Posts.php @@ -134,6 +134,7 @@ public function generate_posts( $request ) { if ( ! current_user_can( $permission_required ) ) { return $this->error_response( sprintf( + /* translators: %s: Name of the WordPress capability the current user is missing. */ __( 'Your user needs the "%s" permission to generate posts.', 'fakerpress' ), $permission_required ), diff --git a/src/FakerPress/REST/Endpoints/Terms.php b/src/FakerPress/REST/Endpoints/Terms.php index 0a9beeae..fa9cacdc 100644 --- a/src/FakerPress/REST/Endpoints/Terms.php +++ b/src/FakerPress/REST/Endpoints/Terms.php @@ -82,7 +82,7 @@ protected function get_routes() { 'items' => [ 'type' => 'string' ], 'default' => [], ], - 'exclude' => [ + 'exclude' => [ // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- REST argument schema key, not a query argument. 'description' => __( 'Term IDs to exclude from the results.', 'fakerpress' ), 'type' => 'array', 'items' => [ 'type' => 'integer' ], @@ -139,7 +139,7 @@ public function search_terms( $request ) { ]; if ( ! empty( $exclude ) ) { - $args['exclude'] = $exclude; + $args['exclude'] = $exclude; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Paginated get_terms() search, the caller passes the term IDs to leave out. } $terms = get_terms( $args ); @@ -238,6 +238,7 @@ public function generate_terms( $request ) { if ( ! current_user_can( $permission_required ) ) { return $this->error_response( sprintf( + /* translators: %s: Name of the WordPress capability the current user is missing. */ __( 'Your user needs the "%s" permission to generate terms.', 'fakerpress' ), $permission_required ), @@ -304,7 +305,7 @@ public function generate_terms( $request ) { protected function get_endpoint_args(): array { return array_merge( [ - 'quantity' => [ + 'quantity' => [ 'description' => __( 'Number of terms to generate.', 'fakerpress' ), 'type' => 'integer', 'minimum' => 1, @@ -314,7 +315,7 @@ protected function get_endpoint_args(): array { return null === $value ? null : absint( $value ); }, ], - 'qty' => [ + 'qty' => [ 'description' => __( 'Quantity range with min/max values.', 'fakerpress' ), 'type' => 'object', 'properties' => [ @@ -339,7 +340,7 @@ protected function get_endpoint_args(): array { 'description' => __( 'Deprecated singular alias for taxonomies — accepts a single taxonomy slug.', 'fakerpress' ), 'type' => 'string', ], - 'meta' => [ + 'meta' => [ 'description' => __( 'Meta data to assign to generated terms.', 'fakerpress' ), 'type' => 'object', ], diff --git a/src/FakerPress/REST/Endpoints/Users.php b/src/FakerPress/REST/Endpoints/Users.php index 75802e70..a035fd09 100644 --- a/src/FakerPress/REST/Endpoints/Users.php +++ b/src/FakerPress/REST/Endpoints/Users.php @@ -121,6 +121,7 @@ public function generate_users( $request ) { if ( ! current_user_can( $permission_required ) ) { return $this->error_response( sprintf( + /* translators: %s: Name of the WordPress capability the current user is missing. */ __( 'Your user needs the "%s" permission to generate users.', 'fakerpress' ), $permission_required ), diff --git a/src/FakerPress/REST/OpenAPI.php b/src/FakerPress/REST/OpenAPI.php index 931a4597..7ea6782e 100644 --- a/src/FakerPress/REST/OpenAPI.php +++ b/src/FakerPress/REST/OpenAPI.php @@ -12,6 +12,7 @@ use FakerPress\Plugin; +// phpcs:disable StellarWP.Classes.ValidClassName.NotSnakeCase -- Public class name, renaming it breaks code that references the class. /** * Class OpenAPI * @@ -20,6 +21,7 @@ * @since 0.9.0 */ class OpenAPI { + // phpcs:enable StellarWP.Classes.ValidClassName.NotSnakeCase /** * Get the base OpenAPI specification structure. diff --git a/src/FakerPress/REST/Traits/Handles_Batching.php b/src/FakerPress/REST/Traits/Handles_Batching.php index abf9c375..77cade77 100644 --- a/src/FakerPress/REST/Traits/Handles_Batching.php +++ b/src/FakerPress/REST/Traits/Handles_Batching.php @@ -117,15 +117,17 @@ protected function build_batched_response_data( $results, $batch_info, $formatte */ protected function format_batched_success_message( $generated_count, $item_type, $batch_info ) { $message = sprintf( + /* translators: 1: Number of items generated, 2: Item type label (singular or plural). */ __( 'Successfully generated %1$d %2$s.', 'fakerpress' ), $generated_count, - _n( $item_type, $item_type . 's', $generated_count, 'fakerpress' ) + $this->get_batched_item_label( $item_type, $generated_count ) ); // Add batching information if this is part of a larger batch. if ( $batch_info['is_capped'] || $batch_info['offset'] > 0 ) { $current_total = $batch_info['offset'] + $batch_info['quantity']; $message .= ' ' . sprintf( + /* translators: 1: Number of items generated so far, 2: Total number of items requested. */ __( '(Batch %1$d of %2$d total)', 'fakerpress' ), $current_total, $batch_info['total'] @@ -134,4 +136,34 @@ protected function format_batched_success_message( $generated_count, $item_type, return $message; } + + /** + * Gets the translated singular or plural label for a generated item type. + * + * Each known type uses a literal `_n()` call so the strings can be extracted for translation. + * + * @since 0.10.0 + * + * @param string $item_type Type of item: post, user, term, comment or attachment. + * @param int $count Number of items, used to pick the singular or plural form. + * + * @return string The label for the item type. + */ + protected function get_batched_item_label( $item_type, $count ) { + switch ( $item_type ) { + case 'post': + return _n( 'post', 'posts', $count, 'fakerpress' ); + case 'user': + return _n( 'user', 'users', $count, 'fakerpress' ); + case 'term': + return _n( 'term', 'terms', $count, 'fakerpress' ); + case 'comment': + return _n( 'comment', 'comments', $count, 'fakerpress' ); + case 'attachment': + return _n( 'attachment', 'attachments', $count, 'fakerpress' ); + default: + // Unknown types keep the untranslated label with a plural "s", as _n() did without a translation. + return 1 === (int) $count ? $item_type : $item_type . 's'; + } + } } From 047ada40d92395e503f890f7216d0914bb9e436a Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:09:34 +0000 Subject: [PATCH 05/12] PHPCS: Template theme paths and Utils JSON encoding - Template lookup uses get_stylesheet_directory() / get_template_directory() instead of the deprecated STYLESHEETPATH / TEMPLATEPATH constants (same paths, WordPress 6.4 deprecated the constants). - Utils::attr() encodes non-scalar attributes with wp_json_encode(). - Targeted ignores for Template::get( $default ), Template::render( $echo ) and the rendered template echo. --- src/FakerPress/Template.php | 10 +++++----- src/FakerPress/Utils.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/FakerPress/Template.php b/src/FakerPress/Template.php index d8224a73..4cbce27b 100644 --- a/src/FakerPress/Template.php +++ b/src/FakerPress/Template.php @@ -188,7 +188,7 @@ public function set_template_context_extract( $value = false ) { * * @return mixed The value of the specified index or the default if not found. */ - final public function get( $index, $default = null, $is_local = true ) { + final public function get( $index, $default = null, $is_local = true ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. $context = $this->get_global_values(); if ( true === $is_local ) { @@ -374,12 +374,12 @@ protected function get_template_path_list() { $folders[] = [ 'id' => 'child-theme', 'priority' => 10, - 'path' => $this->get_template_public_path( STYLESHEETPATH ), + 'path' => $this->get_template_public_path( get_stylesheet_directory() ), ]; $folders[] = [ 'id' => 'parent-theme', 'priority' => 15, - 'path' => $this->get_template_public_path( TEMPLATEPATH ), + 'path' => $this->get_template_public_path( get_template_directory() ), ]; } @@ -466,7 +466,7 @@ public function get_template_file( $name ) { * * @return string|false Either the final content HTML or `false` if no template could be found. */ - public function render( $name, $context = [], $echo = true ) { + public function render( $name, $context = [], $echo = true ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.echoFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. // If name is String make it an Array if ( is_string( $name ) ) { $name = (array) explode( '/', $name ); @@ -607,7 +607,7 @@ public function render( $name, $context = [], $echo = true ) { $html = apply_filters( "fakerpress_template_html:$hook_name", $html, $file, $name, $this ); if ( $echo ) { - echo $html; + echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, StellarWP.XSS.EscapeOutput.OutputNotEscaped -- Rendered template markup, each template escapes its own output. } return $html; diff --git a/src/FakerPress/Utils.php b/src/FakerPress/Utils.php index 0cacaf14..d29728c8 100644 --- a/src/FakerPress/Utils.php +++ b/src/FakerPress/Utils.php @@ -53,7 +53,7 @@ public static function attr( $attributes = [] ) { $value = array_map( 'sanitize_html_class', $value ); $value = implode( ' ', $value ); } else { - $value = htmlspecialchars( json_encode( $value ), ENT_QUOTES, 'UTF-8' ); + $value = htmlspecialchars( wp_json_encode( $value ), ENT_QUOTES, 'UTF-8' ); } } if ( ! is_bool( $value ) || true !== $value ) { From 19eb7e23c5f48f8f2d81850a541346f9c7a00790 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:09:34 +0000 Subject: [PATCH 06/12] PHPCS: clean up the deprecated legacy Field class - is_a( $container, __CLASS__ ) becomes $container instanceof self. - Fold the two empty if branches in Field::parse() into a single negated check (same result). - Option labels use esc_html() (same output as esc_attr()). - Empty __( '' ) calls become plain empty strings. - Meta template closures drop parameters they never used. - Targeted ignores for the public Field::plugin constant, output( $print ) and the balanceTags() echo. --- src/FakerPress/Field.php | 92 ++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/src/FakerPress/Field.php b/src/FakerPress/Field.php index da8e4564..c8647c7f 100644 --- a/src/FakerPress/Field.php +++ b/src/FakerPress/Field.php @@ -9,7 +9,7 @@ */ class Field { - const plugin = 'fakerpress'; + const plugin = 'fakerpress'; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase -- Public constant on a deprecated class, renaming it breaks Field::plugin references. public $type = 'raw'; @@ -186,7 +186,7 @@ public function __construct( $type, $field, $container = [] ) { $this->wrap = $container->wrap; } - public function output( $print = false ) { + public function output( $print = false ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.printFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. if ( ! $this->conditional ) { return false; } @@ -202,7 +202,7 @@ public function output( $print = false ) { $field = apply_filters( self::plugin . '/fields/field-output-' . $this->type, $field, $this ); if ( $print ) { - echo balanceTags( $field ); + echo balanceTags( $field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, StellarWP.XSS.EscapeOutput.OutputNotEscaped -- Field markup from the type_* builders, which escape attribute values through Utils::attr(). } else { return $field; } @@ -512,7 +512,7 @@ public static function parse( $field, &$container = null ) { $field = (object) $field; } - if ( ! is_a( $container, __CLASS__ ) ) { + if ( ! ( $container instanceof self ) ) { $container = (object) wp_parse_args( $container, self::$default_container ); } if ( ! isset( $container->id ) ) { @@ -521,21 +521,13 @@ public static function parse( $field, &$container = null ) { $field = (object) wp_parse_args( $field, ( ! empty( $container->field ) ? $container->field : [] ) ); - // Setup Private Attributes (_*) - if ( isset( $field->_id ) ) { - - } elseif ( empty( $field->id ) ) { - $field->_id = (array) $container->id; - } else { - $field->_id = (array) $field->id; + // Setup Private Attributes (_*), keeping any that were passed in. + if ( ! isset( $field->_id ) ) { + $field->_id = empty( $field->id ) ? (array) $container->id : (array) $field->id; } - if ( isset( $field->_name ) ) { - - } elseif ( ! isset( $field->name ) ) { - $field->_name = (array) ( $container->field->name ?? $field->_id ); - } else { - $field->_name = (array) $field->name; + if ( ! isset( $field->_name ) ) { + $field->_name = isset( $field->name ) ? (array) $field->name : (array) ( $container->field->name ?? $field->_id ); } // Setup Public Attributes @@ -653,7 +645,7 @@ public static function type_input( $field, $container = null, $output = 'string' $content[] = ''; - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -698,7 +690,7 @@ public static function type_heading( $field, $container = null, $output = 'strin $content[] = '
' . $field->description . '
'; } - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -736,7 +728,7 @@ public static function type_radio( $field, $container = null, $output = 'string' $content[] = '
'; } - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -774,7 +766,7 @@ public static function type_checkbox( $field, $container = null, $output = 'stri $content[] = '
'; } - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -812,12 +804,12 @@ public static function type_dropdown( $field, $container = null, $output = 'stri if ( isset( $field->value ) && $field->value === $option['value'] ) { $option['selected'] = true; } - $content[] = '' . esc_attr( $option['text'] ) . ''; + $content[] = '' . esc_html( $option['text'] ) . ''; } $content[] = ''; } - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -894,7 +886,7 @@ public static function type_range( $field, $container = null, $output = 'string' $content[] = '
'; $content[] = self::type_input( $max, null, 'string', [] ); - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -1056,7 +1048,7 @@ public static function type_taxonomy( $field, $container = null, $output = 'stri $content = $table->build( $content ); - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -1187,7 +1179,7 @@ public static function type_meta( $field, $container = null, $output = 'string', $containers->conf->id[] = 'conf'; $containers->conf->type .= '_conf'; $containers->conf->label = __( 'Configuration', 'fakerpress' ); - $containers->conf->description = __( '', 'fakerpress' ); + $containers->conf->description = ''; $containers->conf->class = [ 'meta_conf-container' ]; $containers->conf->blocks = $container_blocks; $containers->conf->attributes = [ @@ -1204,7 +1196,7 @@ public static function type_meta( $field, $container = null, $output = 'string', $content = $table->build( $content ); - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -1267,7 +1259,7 @@ public static function get_meta_types() { $types->numbers = [ 'value' => 'numbers', 'text' => __( 'Number', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $range = clone $field; $range->_id = [ 'meta', 'number' ]; $range->_name = [ 'meta', 'number' ]; @@ -1286,7 +1278,7 @@ public static function get_meta_types() { $types->wp_query = [ 'value' => 'wp_query', 'text' => __( 'WP_Query', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $query = clone $field; $query->_id = [ 'meta', 'query' ]; $query->_name = [ 'meta', 'query' ]; @@ -1306,7 +1298,7 @@ public static function get_meta_types() { $types->attachment = [ 'value' => 'attachment', 'text' => __( 'Attachment', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $store = clone $field; $store->_id = [ 'meta', 'store' ]; $store->_name = [ 'meta', 'store' ]; @@ -1374,7 +1366,7 @@ public static function get_meta_types() { $types->elements = [ 'value' => 'elements', 'text' => __( 'Elements', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $tags = clone $field; $tags->_id = [ 'meta', 'elements' ]; $tags->_name = [ 'meta', 'elements' ]; @@ -1384,7 +1376,7 @@ public static function get_meta_types() { $tags->{'data-tags'} = true; $tags->class = []; $tags->placeholder = __( 'Type all possible elements (Tab or Return)', 'fakerpress' ); - $tags->label = __( '', 'fakerpress' ); + $tags->label = ''; $html[] = Field::wrapper( Field::type_dropdown( $tags, null, 'string' ), $tags ); $html[] = Field::wrapper( Field::type_range( $default->qty, null, 'string' ), $default->qty ); @@ -1398,7 +1390,7 @@ public static function get_meta_types() { $types->letter = [ 'value' => 'letter', 'text' => __( 'Letter', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function () use ( $default ) { $html[] = Field::wrapper( Field::type_number( $default->weight, null, 'string' ), $default->weight ); return implode( "\r\n", $html ); @@ -1408,7 +1400,7 @@ public static function get_meta_types() { $types->words = [ 'value' => 'words', 'text' => __( 'Words', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function () use ( $default ) { $html[] = Field::wrapper( Field::type_range( $default->qty, null, 'string' ), $default->qty ); $html[] = Field::wrapper( Field::type_number( $default->weight, null, 'string' ), $default->weight ); @@ -1420,7 +1412,7 @@ public static function get_meta_types() { $types->text = [ 'value' => 'text', 'text' => __( 'Text', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $text = clone $field; $text->_id = [ 'meta', 'text_type' ]; $text->_name = [ 'meta', 'text_type' ]; @@ -1454,7 +1446,7 @@ public static function get_meta_types() { $types->html = [ 'value' => 'html', 'text' => __( 'HTML', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $elements = clone $field; $elements->_id = [ 'meta', 'elements' ]; $elements->_name = [ 'meta', 'elements' ]; @@ -1477,7 +1469,7 @@ public static function get_meta_types() { $types->lexify = [ 'value' => 'lexify', 'text' => __( 'Lexify', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $template = clone $field; $template->_id = [ 'meta', 'template' ]; $template->_name = [ 'meta', 'template' ]; @@ -1496,7 +1488,7 @@ public static function get_meta_types() { $types->asciify = [ 'value' => 'asciify', 'text' => __( 'Asciify', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $template = clone $field; $template->_id = [ 'meta', 'template' ]; $template->_name = [ 'meta', 'template' ]; @@ -1515,7 +1507,7 @@ public static function get_meta_types() { $types->regexify = [ 'value' => 'regexify', 'text' => __( 'Regexify', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $template = clone $field; $template->_id = [ 'meta', 'template' ]; $template->_name = [ 'meta', 'template' ]; @@ -1534,7 +1526,7 @@ public static function get_meta_types() { $types->person = [ 'value' => 'person', 'text' => __( 'Person', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $template = clone $field; $template->_id = [ 'meta', 'template' ]; $template->_name = [ 'meta', 'template' ]; @@ -1593,7 +1585,7 @@ public static function get_meta_types() { $types->geo = [ 'value' => 'geo', 'text' => __( 'Geo Information', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $template = clone $field; $template->_id = [ 'meta', 'template' ]; $template->_name = [ 'meta', 'template' ]; @@ -1681,7 +1673,7 @@ public static function get_meta_types() { $types->phone = [ 'value' => 'company', 'text' => __( 'Company', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $template = clone $field; $template->_id = [ 'meta', 'template' ]; $template->_name = [ 'meta', 'template' ]; @@ -1721,7 +1713,7 @@ public static function get_meta_types() { $types->date = [ 'value' => 'date', 'text' => __( 'Date', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function ( $field ) use ( $default ) { $template = clone $field; $template->_id = [ 'meta', 'interval' ]; $template->_name = [ 'meta', 'interval' ]; @@ -1747,7 +1739,7 @@ public static function get_meta_types() { $types->timezone = [ 'value' => 'timezone', 'text' => __( 'TimeZone', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function () use ( $default ) { $html[] = Field::wrapper( Field::type_number( $default->weight, null, 'string' ), $default->weight ); return implode( "\r\n", $html ); @@ -1757,7 +1749,7 @@ public static function get_meta_types() { $types->email = [ 'value' => 'email', 'text' => __( 'Email', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function () use ( $default ) { $html[] = Field::wrapper( Field::type_number( $default->weight, null, 'string' ), $default->weight ); return implode( "\r\n", $html ); @@ -1767,7 +1759,7 @@ public static function get_meta_types() { $types->domain = [ 'value' => 'domain', 'text' => __( 'Domain', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function () use ( $default ) { $html[] = Field::wrapper( Field::type_number( $default->weight, null, 'string' ), $default->weight ); return implode( "\r\n", $html ); @@ -1777,7 +1769,7 @@ public static function get_meta_types() { $types->ip = [ 'value' => 'ip', 'text' => __( 'IP', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function () use ( $default ) { $html[] = Field::wrapper( Field::type_number( $default->weight, null, 'string' ), $default->weight ); return implode( "\r\n", $html ); @@ -1787,7 +1779,7 @@ public static function get_meta_types() { $types->user_agent = [ 'value' => 'user_agent', 'text' => __( 'Browser User Agent', 'fakerpress' ), - 'template' => function ( $field, $type ) use ( $default ) { + 'template' => function () use ( $default ) { $html[] = Field::wrapper( Field::type_number( $default->weight, null, 'string' ), $default->weight ); return implode( "\r\n", $html ); @@ -1838,7 +1830,7 @@ public static function type_interval( $field, $container = null, $output = 'stri $content[] = '
'; $content[] = self::type_date( $max, null, 'string' ); - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; @@ -1863,7 +1855,7 @@ public static function type_raw( $field, $container = null, $output = 'string', $content = ''; } - if ( is_a( $container, __CLASS__ ) ) { + if ( $container instanceof self ) { $html[] = $container->build( $content ); } else { $html = $content; From ffe8041babe8f5316e098598bb6a70a88fca0cf8 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:10:11 +0000 Subject: [PATCH 07/12] Fix legacy implode()/join() argument order that is fatal on PHP 8 PHP 8 removed the join( $pieces, $glue ) order, so Text\Base::sentence(), paragraph() and text() and the set() helper's error path threw a TypeError. Swapping the arguments gives the output the code always intended. Also drops the space in $paragraphs []. --- src/FakerPress/Provider/Text/Base.php | 8 ++++---- src/functions/variables.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/FakerPress/Provider/Text/Base.php b/src/FakerPress/Provider/Text/Base.php index 9e26add4..7e2b8ddb 100644 --- a/src/FakerPress/Provider/Text/Base.php +++ b/src/FakerPress/Provider/Text/Base.php @@ -300,7 +300,7 @@ public static function sentence( $nbWords = 6, $variableNbWords = true ) { $words = static::words( $nbWords ); $words[0] = ucwords( $words[0] ); - return join( $words, ' ' ) . '.'; + return join( ' ', $words ) . '.'; } /** @@ -337,7 +337,7 @@ public static function paragraph( $nbSentences = 3, $variableNbSentences = true $nbSentences = self::randomize_nb_elements( $nbSentences ); } - return join( static::sentences( $nbSentences ), ' ' ); + return join( ' ', static::sentences( $nbSentences ) ); } /** @@ -351,7 +351,7 @@ public static function paragraph( $nbSentences = 3, $variableNbSentences = true public static function paragraphs( $nb = 3, $asText = false ) { $paragraphs = []; for ( $i = 0; $i < $nb; $i++ ) { - $paragraphs [] = static::paragraph(); + $paragraphs[] = static::paragraph(); } return $asText ? join( "\n\n", $paragraphs ) : $paragraphs; @@ -409,7 +409,7 @@ public static function text( $maxNbChars = 200 ) { } } - return join( $text, '' ); + return join( '', $text ); } protected static function randomize_nb_elements( $nbElements ) { diff --git a/src/functions/variables.php b/src/functions/variables.php index 4de6cbdd..4ceb67c9 100644 --- a/src/functions/variables.php +++ b/src/functions/variables.php @@ -33,7 +33,7 @@ function set( array $array, $key, $value ) { // phpcs:ignore Universal.NamingCon // would likely lead to unexpected problems for whatever first set it. $error = sprintf( 'Attempted to set $array[%1$s] but %2$s is already set and is not an array.', - implode( $key, '][' ), + implode( '][', $key ), $i ); From 1f617098f87f78ed4f565ee8ff5387bf9dc7eb86 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:12:53 +0000 Subject: [PATCH 08/12] PHPCS: Faker providers - get_terms() uses the single-array signature (the taxonomy-first form is deprecated since WordPress 4.5); the taxonomy still wins over any 'taxonomy' in $args, as before. - Empty catch blocks in the date formatters set $max = null so the existing 'now' fallback runs, with a comment. - Split the chained $els[] = $element assignment in HTML::html_elements(). - Text\Base: rename the protected randomize_nb_elements() parameter; the Faker-style camelCase public API ($wordList, $nbWords, $asText, ...) stays behind a scoped disable, and mt_rand() stays because Faker seeds it. - WP_Comment: $comment_post_ID mirrors the WordPress field, scoped disable. - Drop the commented-out WP_Term::slug() stub. - Targeted ignores: LoremPicsum class name, the HTML 'exclude' element list, the random list-length loop, suppress_filters on the post pool, meta_type_raw( $default ). --- src/FakerPress/Provider/HTML.php | 7 ++++--- src/FakerPress/Provider/Image/LoremPicsum.php | 2 ++ src/FakerPress/Provider/Text/Base.php | 10 +++++++--- src/FakerPress/Provider/WP_Comment.php | 6 +++++- src/FakerPress/Provider/WP_Meta.php | 4 +++- src/FakerPress/Provider/WP_Post.php | 7 ++++--- src/FakerPress/Provider/WP_Term.php | 11 ++--------- 7 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/FakerPress/Provider/HTML.php b/src/FakerPress/Provider/HTML.php index 4c327901..47e78f69 100644 --- a/src/FakerPress/Provider/HTML.php +++ b/src/FakerPress/Provider/HTML.php @@ -107,7 +107,7 @@ public function html_elements( $args = [] ) { 'qty' => [ 5, 25 ], 'elements' => array_merge( self::$sets['header'], self::$sets['list'], self::$sets['block'] ), 'attr' => [], - 'exclude' => [ 'div' ], + 'exclude' => [ 'div' ], // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- HTML element names to skip, not a query argument. 'allow_html_comments' => false, ]; @@ -138,7 +138,8 @@ public function html_elements( $args = [] ) { $elements = array_filter( $elements, [ $this, 'filter_html_comments' ] ); } - $els[] = $element = Base::randomElement( $elements ); + $element = Base::randomElement( $elements ); + $els[] = $element; $html[] = $this->element( $element, $args->attr, null, $args ); @@ -348,7 +349,7 @@ public function element( $name = 'div', $attr = [], $text = null, $args = null ) $text = Lorem::text( Base::numberBetween( 10, 60 ) ); $html[] = substr( $text, 0, strlen( $text ) - 1 ); } elseif ( in_array( $element->name, self::$sets['list'] ) ) { - for ( $i = 0; $i < Base::numberBetween( 1, 15 ); $i++ ) { + for ( $i = 0; $i < Base::numberBetween( 1, 15 ); $i++ ) { // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed -- Kept as is, hoisting the random bound would change the generated list-length distribution. $html[] = $this->element( 'li' ); } } elseif ( in_array( $element->name, self::$sets['header'] ) ) { diff --git a/src/FakerPress/Provider/Image/LoremPicsum.php b/src/FakerPress/Provider/Image/LoremPicsum.php index 782d6b49..45440112 100644 --- a/src/FakerPress/Provider/Image/LoremPicsum.php +++ b/src/FakerPress/Provider/Image/LoremPicsum.php @@ -3,11 +3,13 @@ use FakerPress\ThirdParty\Faker\Provider\Base; +// phpcs:disable StellarWP.Classes.ValidClassName.NotSnakeCase -- Public class name, renaming it breaks code that references the class. /** * @since 0.4.2 * @since 0.5.0 Unsplash.it turned into Lorem Picsum */ class LoremPicsum extends Base { + // phpcs:enable StellarWP.Classes.ValidClassName.NotSnakeCase const ID = 'lorempicsum'; /** diff --git a/src/FakerPress/Provider/Text/Base.php b/src/FakerPress/Provider/Text/Base.php index 7e2b8ddb..0f898372 100644 --- a/src/FakerPress/Provider/Text/Base.php +++ b/src/FakerPress/Provider/Text/Base.php @@ -4,7 +4,7 @@ use FakerPress\ThirdParty\Faker\Provider\Base as Faker_Base; class Base extends Faker_Base { - public static $wordList = [ + public static $wordList = [ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase -- Faker-compatible public property, subclasses and callers use this name. 'alias', 'consequatur', 'aut', @@ -256,6 +256,8 @@ class Base extends Faker_Base { 'repellat', ]; + // phpcs:disable WordPress.NamingConventions.ValidVariableName -- Faker-compatible public API: $wordList and the camelCase parameters mirror Faker's Lorem provider, renaming them breaks overrides and named arguments. + /** * @example 'Lorem' */ @@ -412,7 +414,9 @@ public static function text( $maxNbChars = 200 ) { return join( '', $text ); } - protected static function randomize_nb_elements( $nbElements ) { - return (int) ( $nbElements * mt_rand( 60, 140 ) / 100 ) + 1; + // phpcs:enable WordPress.NamingConventions.ValidVariableName + + protected static function randomize_nb_elements( $nb_elements ) { + return (int) ( $nb_elements * mt_rand( 60, 140 ) / 100 ) + 1; // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_mt_rand -- Faker seeds mt_rand(), wp_rand() would make seeded output unpredictable. } } diff --git a/src/FakerPress/Provider/WP_Comment.php b/src/FakerPress/Provider/WP_Comment.php index 3a10ad6a..3b4c0301 100644 --- a/src/FakerPress/Provider/WP_Comment.php +++ b/src/FakerPress/Provider/WP_Comment.php @@ -91,6 +91,8 @@ public function comment_approved( $comment_approved = 1 ) { return $comment_approved; } + // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- $comment_post_ID mirrors the WordPress comment field and is a public parameter name. + /** * Generates a Post ID for the Comment * @@ -110,7 +112,7 @@ public function comment_post_ID( $comment_post_ID = null, $args = [] ) { 'posts_per_page' => -1, 'post_type' => 'post', 'post_status' => 'publish', - 'suppress_filters' => true, + 'suppress_filters' => true, // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters -- Existing behaviour, the random post pool ignores third-party query filters. ]; // Apply the defaults @@ -131,6 +133,8 @@ public function comment_post_ID( $comment_post_ID = null, $args = [] ) { return $comment_post_ID; } + // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase + public function comment_author_email( $author_email = null ) { if ( is_null( $author_email ) ) { $author_email = $this->generator->safeEmail(); diff --git a/src/FakerPress/Provider/WP_Meta.php b/src/FakerPress/Provider/WP_Meta.php index 8c0d909e..4cf3ddba 100644 --- a/src/FakerPress/Provider/WP_Meta.php +++ b/src/FakerPress/Provider/WP_Meta.php @@ -404,6 +404,8 @@ public function meta_type_date( $interval, $format = 'Y-m-d H:i:s', $weight = 50 try { $max = new Chronos( $interval['max'] ); } catch ( \Exception $e ) { + // Invalid end date, fall back to "now" below. + $max = null; } } @@ -439,7 +441,7 @@ public function meta_type_user_agent( $weight = 50 ) { return $this->generator->optional( $weight / 100, null )->userAgent(); } - public function meta_type_raw( $weight = 100, $value = null, $default = null ) { + public function meta_type_raw( $weight = 100, $value = null, $default = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. if ( (int) $weight >= $this->generator->numberBetween( 0, 100 ) ) { return $value; } else { diff --git a/src/FakerPress/Provider/WP_Post.php b/src/FakerPress/Provider/WP_Post.php index 164cbdec..588a3e01 100644 --- a/src/FakerPress/Provider/WP_Post.php +++ b/src/FakerPress/Provider/WP_Post.php @@ -77,7 +77,8 @@ public function post_date( $interval = 'now' ) { try { $max = new Chronos( array_shift( $interval ) ); } catch ( \Exception $e ) { - + // Invalid end date, fall back to "now" below. + $max = null; } } @@ -228,11 +229,11 @@ public function tax_input( $config = null ) { foreach ( $settings->taxonomies as $taxonomy ) { if ( empty( $settings->terms ) ) { $terms = get_terms( - $taxonomy, [ + 'taxonomy' => $taxonomy, 'fields' => 'ids', 'hide_empty' => false, - ] + ] ); } else { $terms = $settings->terms; diff --git a/src/FakerPress/Provider/WP_Term.php b/src/FakerPress/Provider/WP_Term.php index 8d2f3694..428a3be3 100644 --- a/src/FakerPress/Provider/WP_Term.php +++ b/src/FakerPress/Provider/WP_Term.php @@ -51,18 +51,11 @@ public function parent_term( $terms = [], $taxonomies = [], $args = [] ) { $args['fields'] = 'ids'; // Merge the returned terms to the one provided - $terms = array_merge( (array) $terms, get_terms( $taxonomies, $args ) ); + $terms = array_merge( (array) $terms, get_terms( array_merge( $args, [ 'taxonomy' => $taxonomies ] ) ) ); } return $this->generator->randomElement( (array) $terms ); } - - // For now I think we should omit the slug, since it's auto-gen, but we need to figure a way to do it later - /* - public function slug(){ - - return $slug; - } - */ + // There is no slug() formatter on purpose: WordPress generates the slug from the name. } From aa272380e312f0998c83d8f24499f767c17f3536 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:12:53 +0000 Subject: [PATCH 09/12] PHPCS: verify the WP_Query AJAX nonce before reading $_POST query_posts() copied $_POST into $request and then checked $request->nonce. It now checks $_POST['nonce'] first (unslashed and sanitized; nonces are alphanumeric so the value is unchanged) and only then reads the rest of the request. Same accept/reject outcome. search_terms() uses get_terms() with a single array, and the term-search 'exclude' lines get targeted ignores. --- src/FakerPress/Ajax.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/FakerPress/Ajax.php b/src/FakerPress/Ajax.php index 3739731a..ed65e452 100644 --- a/src/FakerPress/Ajax.php +++ b/src/FakerPress/Ajax.php @@ -51,7 +51,7 @@ public function search_terms( $request = null ) { 'search' => get_request_var( 'search', '' ), 'post_type' => get_request_var( 'post_type' ), 'taxonomies' => get_request_var( 'taxonomies', [] ), - 'exclude' => get_request_var( 'exclude', [] ), + 'exclude' => get_request_var( 'exclude', [] ), // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Request field read into the search object, not a query argument. 'page' => absint( get_request_var( 'page', 0 ) ), 'page_limit' => absint( get_request_var( 'page_limit', 10 ) ), 'nonce' => get_request_var( 'nonce' ), @@ -92,12 +92,12 @@ public function search_terms( $request = null ) { } if ( ! empty( $request->exclude ) ) { - $args['exclude'] = $request->exclude; + $args['exclude'] = $request->exclude; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Paginated Select2 term search, the caller passes the term IDs to leave out. } $response->args = $args; - $terms = get_terms( (array) $request->taxonomies, $args ); + $terms = get_terms( array_merge( $args, [ 'taxonomy' => (array) $request->taxonomies ] ) ); // Setting up Select2 foreach ( $terms as $term ) { @@ -137,14 +137,15 @@ public function query_posts( $request = null ) { return ( is_ajax() ? wp_send_json( $response ) : $response ); } - $request = (object) $_POST; - - if ( empty( $request->nonce ) || ! wp_verify_nonce( $request->nonce, Plugin::$slug . '-select2-WP_Query' ) ) { + // Verify the nonce before reading anything else from the request. + if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), Plugin::$slug . '-select2-WP_Query' ) ) { $response->message = esc_attr__( 'Invalid nonce verification', 'fakerpress' ); return ( is_ajax() ? wp_send_json( $response ) : $response ); } + $request = (object) $_POST; + if ( ! current_user_can( 'publish_posts' ) ) { $response->message = esc_attr__( 'Your user needs the "publish_posts" permissions to use WP_Query.', 'fakerpress' ); From 4cb83e6655dd69fd7b295d2fa975739354769c3d Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:15:17 +0000 Subject: [PATCH 10/12] PHPCS: generation modules - Attachment: wp_delete_file() for the download_url() temp files (core's wrapper around unlink(), filterable via wp_delete_file), translators comments, and the protected get_random_dimension( $default ) parameter becomes $fallback. - Post, Term, Comment, User: class imports before function imports. - Targeted ignores: fetch() meta_query / nopaging (lists every generated item for bulk delete and image reuse), Meta's own $data['meta_value'] key (not a query), the WP_DEBUG-only error_log() calls and the 5 second attribution lookup timeout. --- src/FakerPress/Module/Attachment.php | 35 +++++++++++++++++----------- src/FakerPress/Module/Comment.php | 5 ++-- src/FakerPress/Module/Meta.php | 10 ++++---- src/FakerPress/Module/Post.php | 7 +++--- src/FakerPress/Module/Term.php | 5 ++-- src/FakerPress/Module/User.php | 9 +++---- 6 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/FakerPress/Module/Attachment.php b/src/FakerPress/Module/Attachment.php index 306fc04e..4374ba0a 100644 --- a/src/FakerPress/Module/Attachment.php +++ b/src/FakerPress/Module/Attachment.php @@ -53,10 +53,10 @@ public static function fetch( array $args = [] ): array { $defaults = [ 'post_type' => 'attachment', 'post_status' => 'any', - 'nopaging' => true, + 'nopaging' => true, // phpcs:ignore WordPressVIPMinimum.Performance.NoPaging.nopaging_nopaging -- Callers need every generated item, not one page (bulk delete, reuse of generated images). 'posts_per_page' => -1, 'fields' => 'ids', - 'meta_query' => [ + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Lists every item FakerPress generated, found by its flag meta (bulk delete, reuse of generated images). [ 'key' => static::get_flag(), 'value' => true, @@ -201,7 +201,7 @@ static function () use ( $url, $timeout ) { // If it's SVG, we need to handle it differently if ( $mime_type === 'image/svg+xml' || $mime_type === 'text/xml' ) { // Delete the SVG file as we don't want to process it - unlink( $temporary_file ); + wp_delete_file( $temporary_file ); return new WP_Error( 'svg-not-supported', __( 'SVG images are not supported. Please use a different image provider or format.', 'fakerpress' ) ); } } @@ -218,7 +218,14 @@ static function () use ( $url, $timeout ) { } if ( ! $extension ) { - return new WP_Error( 'invalid-image-mimetype', sprintf( __( 'Invalid image MimeType (%s)', 'fakerpress' ), $mime_type ) ); + return new WP_Error( + 'invalid-image-mimetype', + sprintf( + /* translators: %s: MIME type of the downloaded file. */ + __( 'Invalid image MimeType (%s)', 'fakerpress' ), + $mime_type + ) + ); } // Build file name with Extension. @@ -234,7 +241,7 @@ static function () use ( $url, $timeout ) { // download_url requires deleting the file if ( file_exists( $temporary_file ) ) { - unlink( $temporary_file ); + wp_delete_file( $temporary_file ); } /** @@ -244,7 +251,7 @@ static function () use ( $url, $timeout ) { */ if ( is_wp_error( $attachment_id ) ) { if ( file_exists( $temporary_file ) ) { - unlink( $temporary_file ); + wp_delete_file( $temporary_file ); } return $attachment_id; } @@ -387,7 +394,7 @@ public function parse_request( $qty, $request = [] ) { // Debug logging if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { - error_log( 'FakerPress Attachment: Generating ' . $quantity . ' attachments' ); + error_log( 'FakerPress Attachment: Generating ' . $quantity . ' attachments' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug trace, only runs when WP_DEBUG is on. } // Generate attachments. @@ -401,7 +408,7 @@ public function parse_request( $qty, $request = [] ) { if ( is_wp_error( $attachment_id ) ) { // Log the error for debugging if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { - error_log( 'FakerPress Attachment Error: ' . $attachment_id->get_error_message() . ' for URL: ' . $attachment_data['attachment_url'] ); + error_log( 'FakerPress Attachment Error: ' . $attachment_id->get_error_message() . ' for URL: ' . $attachment_data['attachment_url'] ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Logs skipped downloads, only when WP_DEBUG is on. } continue; } @@ -459,7 +466,7 @@ protected function generate_attachment_data( $request ) { // Fetch image metadata to get author info $metadata_url = sprintf( 'https://picsum.photos/id/%d/info', $image_id ); - $response = $this->safe_remote_get( $metadata_url, [ 'timeout' => 5 ] ); + $response = $this->safe_remote_get( $metadata_url, [ 'timeout' => 5 ] ); // phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout -- Existing 5 second bound on the admin-only attribution lookup. if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) { $body = wp_remote_retrieve_body( $response ); @@ -500,6 +507,7 @@ protected function generate_attachment_data( $request ) { // Always add attribution based on provider if ( ! empty( $image_author ) ) { // Lorem Picsum with known author + /* translators: %s: Name of the photographer. */ $attribution = sprintf( __( 'Photo by %s on Unsplash', 'fakerpress' ), $image_author ); } elseif ( $provider === 'lorempicsum' ) { // Lorem Picsum without author info (fallback) @@ -562,6 +570,7 @@ protected function update_attachment_fields( $attachment_id, $attachment_data, $ // If we have an image author from Lorem Picsum, include attribution if ( ! empty( $attachment_data['image_author'] ) ) { $alt_text = sprintf( + /* translators: 1: Generated alt text sentence, 2: Name of the photographer. */ __( '%1$s - Photo by %2$s on Unsplash', 'fakerpress' ), $faker->sentence( $faker->numberBetween( 3, 8 ) ), $attachment_data['image_author'] @@ -597,23 +606,23 @@ protected function update_attachment_fields( $attachment_id, $attachment_data, $ * @since TBD * * @param mixed $dimension Dimension value or range. - * @param int $default Default value. + * @param int $fallback Value used when no dimension was given. * * @return int */ - protected function get_random_dimension( $dimension, $default = 800 ) { + protected function get_random_dimension( $dimension, $fallback = 800 ) { if ( is_numeric( $dimension ) ) { return absint( $dimension ); } if ( is_array( $dimension ) || is_object( $dimension ) ) { $dimension = (array) $dimension; - $min = isset( $dimension['min'] ) ? absint( $dimension['min'] ) : $default; + $min = isset( $dimension['min'] ) ? absint( $dimension['min'] ) : $fallback; $max = isset( $dimension['max'] ) ? absint( $dimension['max'] ) : $min; return $this->get_faker()->numberBetween( $min, $max ); } - return $default; + return $fallback; } } diff --git a/src/FakerPress/Module/Comment.php b/src/FakerPress/Module/Comment.php index 77f781ca..ad9ef0a6 100644 --- a/src/FakerPress/Module/Comment.php +++ b/src/FakerPress/Module/Comment.php @@ -3,10 +3,11 @@ namespace FakerPress\Module; use FakerPress; +use WP_Error; + use function FakerPress\make; use function FakerPress\get; use function FakerPress\is_truthy; -use WP_Error; class Comment extends Abstract_Module { /** @@ -41,7 +42,7 @@ public function hook(): void { */ public static function fetch( array $args = [] ): array { $defaults = [ - 'meta_query' => [ + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Lists every item FakerPress generated, found by its flag meta (bulk delete, reuse of generated images). [ 'key' => static::get_flag(), 'value' => true, diff --git a/src/FakerPress/Module/Meta.php b/src/FakerPress/Module/Meta.php index c8ed926b..76608f58 100644 --- a/src/FakerPress/Module/Meta.php +++ b/src/FakerPress/Module/Meta.php @@ -98,7 +98,7 @@ public function object( $id = 0, $name = 'post' ): Interface_Module { public function with( string $type, string $name, $args ): Interface_Module { $this->data['meta_key'] = null; - $this->data['meta_value'] = null; + $this->data['meta_value'] = null; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Key in the module's own data array, not a query argument. if ( empty( $type ) ) { return $this; @@ -141,13 +141,13 @@ public function generate( bool $force = false ): Interface_Module { if ( is_callable( [ $faker, 'meta_type_' . $type ] ) ) { try { - $this->data['meta_value'] = call_user_func_array( [ $faker, 'meta_type_' . $type ], $args ); + $this->data['meta_value'] = call_user_func_array( [ $faker, 'meta_type_' . $type ], $args ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Key in the module's own data array, not a query argument. } catch ( \Throwable $e ) { // Not enough configuration to generate this meta value; skip it without halting generation. return $this; } } elseif ( count( $args ) === 1 ) { - $this->data['meta_value'] = reset( $args ); + $this->data['meta_value'] = reset( $args ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Key in the module's own data array, not a query argument. } /** @@ -160,7 +160,7 @@ public function generate( bool $force = false ): Interface_Module { * @param string $meta_type Which type of Meta we are dealing with * @param self $module An instance of the Meta Module */ - $this->data['meta_value'] = apply_filters( 'fakerpress.module.meta.value', $this->data['meta_value'], $this->data['meta_key'], $type, $this ); + $this->data['meta_value'] = apply_filters( 'fakerpress.module.meta.value', $this->data['meta_value'], $this->data['meta_key'], $type, $this ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Key in the module's own data array, not a query argument. /** * Allow filtering for the Value of a specific meta value based on it's key @@ -171,7 +171,7 @@ public function generate( bool $force = false ): Interface_Module { * @param string $meta_type Which type of Meta we are dealing with * @param self $module An instance of the Meta Module */ - $this->data['meta_value'] = apply_filters( "fakerpress.module.meta.{$this->data['meta_key']}.value", $this->data['meta_value'], $type, $this ); + $this->data['meta_value'] = apply_filters( "fakerpress.module.meta.{$this->data['meta_key']}.value", $this->data['meta_value'], $type, $this ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Key in the module's own data array, not a query argument. return $this; } diff --git a/src/FakerPress/Module/Post.php b/src/FakerPress/Module/Post.php index 0860e2f6..e2c1ea24 100644 --- a/src/FakerPress/Module/Post.php +++ b/src/FakerPress/Module/Post.php @@ -3,9 +3,10 @@ namespace FakerPress\Module; use FakerPress; +use WP_Error; + use function FakerPress\make; use function FakerPress\get; -use WP_Error; class Post extends Abstract_Module { /** @@ -42,10 +43,10 @@ public static function fetch( array $args = [] ): array { $defaults = [ 'post_type' => 'any', 'post_status' => 'any', - 'nopaging' => true, + 'nopaging' => true, // phpcs:ignore WordPressVIPMinimum.Performance.NoPaging.nopaging_nopaging -- Callers need every generated item, not one page (bulk delete, reuse of generated images). 'posts_per_page' => - 1, 'fields' => 'ids', - 'meta_query' => [ + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Lists every item FakerPress generated, found by its flag meta (bulk delete, reuse of generated images). [ 'key' => static::get_flag(), 'value' => true, diff --git a/src/FakerPress/Module/Term.php b/src/FakerPress/Module/Term.php index 7a5a8de5..e0d50d42 100644 --- a/src/FakerPress/Module/Term.php +++ b/src/FakerPress/Module/Term.php @@ -1,11 +1,12 @@ 'ID', - 'meta_query' => [ + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Lists every item FakerPress generated, found by its flag meta (bulk delete, reuse of generated images). [ 'key' => static::get_flag(), 'value' => true, From 140073b5ba89ca0b052f60b53ab443607572169c Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:15:17 +0000 Subject: [PATCH 11/12] PHPCS: annotate public Plugin and Fields API names Plugin::$_file, Plugin::$_ext_domain, Plugin::get( $default ) and the Field_Interface / Field_Abstract $default, $echo and $parent parameters are public API, so they keep their names with targeted ignores. --- src/FakerPress/Fields/Field_Abstract.php | 6 +++--- src/FakerPress/Fields/Field_Interface.php | 4 ++-- src/FakerPress/Plugin.php | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/FakerPress/Fields/Field_Abstract.php b/src/FakerPress/Fields/Field_Abstract.php index 34a52593..1f356382 100644 --- a/src/FakerPress/Fields/Field_Abstract.php +++ b/src/FakerPress/Fields/Field_Abstract.php @@ -128,7 +128,7 @@ public static function get_slug(): string { /** * {@inheritDoc} */ - public function get_setting( $index, $default = null ) { + public function get_setting( $index, $default = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. return get( $this->get_settings(), $index, $default ); } @@ -171,7 +171,7 @@ public function get_priority(): int { /** * {@inheritDoc} */ - public function get_html( $format = 'string', $echo = true ) { + public function get_html( $format = 'string', $echo = true ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.echoFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. // Globally set in the template vars this instance of field. $this->get_template()->set( 'field', $this, false ); @@ -320,7 +320,7 @@ public function get_parent() { /** * {@inheritDoc} */ - public function set_parent( Field_Interface $parent ) { + public function set_parent( Field_Interface $parent ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.parentFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. $this->parent = $parent; return $this; diff --git a/src/FakerPress/Fields/Field_Interface.php b/src/FakerPress/Fields/Field_Interface.php index 2afe7cbd..c16839fc 100644 --- a/src/FakerPress/Fields/Field_Interface.php +++ b/src/FakerPress/Fields/Field_Interface.php @@ -87,7 +87,7 @@ public function get_settings(); * * @return mixed Setting you are looking for. */ - public function get_setting( $index, $default = null ); + public function get_setting( $index, $default = null ); // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Interface signature, renaming the parameter breaks implementations and named-argument callers. /** * Configure this field and it's children. @@ -190,5 +190,5 @@ public function get_parent(); * * @return Field_Interface Returns an instance of itself be able to chain calls. */ - public function set_parent( Field_Interface $parent ); + public function set_parent( Field_Interface $parent ); // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.parentFound -- Interface signature, renaming the parameter breaks implementations and named-argument callers. } diff --git a/src/FakerPress/Plugin.php b/src/FakerPress/Plugin.php index c63c680b..0cb64eaf 100644 --- a/src/FakerPress/Plugin.php +++ b/src/FakerPress/Plugin.php @@ -76,7 +76,7 @@ class Plugin { * * @var string */ - public static $_file = __FP_FILE__; + public static $_file = __FP_FILE__; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore -- Public static property, renaming it breaks Plugin::$_file references. /** * The Plugin external website base domain @@ -85,7 +85,7 @@ class Plugin { * * @var string */ - public static $_ext_domain = 'https://fakerpress.com'; + public static $_ext_domain = 'https://fakerpress.com'; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore -- Public static property, renaming it breaks Plugin::$_ext_domain references. /** * Store if the plugin has been booted or not. @@ -313,7 +313,7 @@ public static function ext_site_url( string $path = '/' ): string { return esc_url_raw( static::$_ext_domain . ( ! empty( $path ) ? $path : '/' ), [ 'http', 'https' ] ); } - public static function get( $name, $default = false ) { + public static function get( $name, $default = false ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public API, renaming the parameter breaks callers that pass it as a named argument. $options = static::all(); return get( $options, $name, $default ); } From 109e5826d3d52b8ceb488caa758c2d8577552621 Mon Sep 17 00:00:00 2001 From: Gustavo Bordoni Date: Sat, 17 Oct 2026 16:29:55 +0000 Subject: [PATCH 12/12] docs: changelog for #239 --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index d40f2d3b..824e0b00 100644 --- a/readme.txt +++ b/readme.txt @@ -179,6 +179,7 @@ For help with or questions about FakerPress, visit the [WordPress Plugin Forums] * Tweak - Clear every JavaScript lint and TypeScript error: WordPress package types, the `@fp` import alias in ESLint, the zod v4 meta-rule schema, `…` in translated strings, and `let`/`const` in the legacy jQuery scripts. [[#236](https://github.com/bordoni/fakerpress/pull/236)] * Tweak - Clear every stylelint error in the admin styles with a Tailwind v4 aware config; the compiled CSS is unchanged apart from dropping obsolete `-moz-` gradients and empty rules. [[#237](https://github.com/bordoni/fakerpress/pull/237)] * Tweak - PHPCS skips the public hook names, the namespaced Faker formatter names and the generated readme data, each with a documented reason. [[#238](https://github.com/bordoni/fakerpress/pull/238)] +* Fix - The text provider's sentences, paragraphs and text no longer fatal on PHP 8 (`join()` argument order); the post search verifies its nonce before reading the request; template output is escaped, and batch success messages are translatable. [[#239](https://github.com/bordoni/fakerpress/pull/239)] = 0.9.2 — 20 of July 2026 =