Feature/v2 refactor and renamer#20
Conversation
Replace legacy .gitignore patterns with generated-artifact entries. Remove blanket-silenced PHPCS rules in favour of targeted inline ignores. Add composer.json with PSR-4 autoloading, dev dependencies (PHPUnit 11, WPCS 3), scripts (lint, test, package, make-pot), and lock file pinning saltus/framework plus PHPUnit and PHPCS packages. Add phpunit.xml.dist and bin/package.php CLI for distributable ZIPs. Remove obsolete package-lock.json as Node/Grunt is no longer used.
Move plugin header constants to defined() guards for safety. Add PHP version check and Composer dependency check with admin notices. Replace deprecated Loader stub with direct framework registration. Convert Core properties from public to private typed fields with getters. Add return type declarations to all methods across core classes. Remove unused property storage after construction.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the Saltus Framework Demo plugin by upgrading the PHP requirement to 8.3, replacing Grunt build tasks with Composer scripts, and introducing a new plugin generator UI to download renamed copies of the plugin as a ZIP file. Feedback on these changes highlights a regex bug in the package name generator that mangles uppercase author names, a risk of corrupting third-party assets by globally replacing the version string '2.0.0', an unused $framework parameter in the Core constructor, and the necessity of clearing active output buffers before streaming the ZIP file to prevent archive corruption.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
The Core class no longer needs the Saltus Framework reference. The framework is still instantiated and registered at the plugin level, but is no longer passed into Core. The unused unset() call in the constructor is removed.
Clear all output buffers before sending ZIP headers to prevent "headers already sent" errors.
The regex now allows uppercase letters to pass through before strtolower() runs. Previously, uppercase letters in author names were replaced with dashes, producing incorrect package name segments.
Verify that the renamer correctly replaces the PLUGIN_VERSION value in the main plugin file when a custom version is provided.
Verify the renamer correctly rewrites the composer.json package name from saltus/framework-demo to the target author/slug combination. The test uses a mixed-case author name (Acme Inc) to verify the updated regex preserves uppercase letters before strtolower conversion.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the Saltus Framework Demo plugin by upgrading the PHP requirement to 8.3, replacing the Grunt build system with Composer scripts, and introducing a new admin UI to generate and download renamed copies of the plugin as a ZIP file. It also updates array syntax to match WordPress standards and adds PHPUnit tests. The review feedback highlights three key improvement opportunities: correcting the return value check for wp_tempnam() and ensuring temporary files are cleaned up via a shutdown function, removing a redundant submenu page registration, and simplifying the unslashing of $_POST data using wp_unslash() directly.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the WordPress demo plugin by upgrading the PHP requirement to 8.3, replacing Grunt with Composer scripts, and refactoring the codebase to adhere to WordPress coding standards. It also introduces a new plugin renamer feature that allows users to generate and download a renamed copy of the plugin as a ZIP file, complete with PHPUnit tests. The review feedback highlights several critical improvements for the renamer feature: validating URLs before they are sanitized by esc_url_raw() to prevent validation bypasses, making validation error messages translatable, checking the return values of ZipArchive operations to handle failures gracefully, and ensuring the error query parameter is a string before sanitizing it to avoid PHP warnings.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Check that $_GET['framework_demo_error'] is a string before passing it to sanitize_text_field(), which expects a string. A malicious array parameter would otherwise trigger PHP warnings.
Run validation before esc_url_raw() to catch invalid URLs before they are silently converted to empty strings. Wrap validation error messages in __() for i18n support.
ZipArchive::close() and addFromString() return false on failure without throwing exceptions. Check their return values and throw RuntimeException on failure to prevent silently generating incomplete or corrupted ZIP files.
Restore WordPress function stubs removed in prior cleanup. Make esc_url_raw return empty string for invalid URLs to match real WordPress behavior.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the WordPress plugin by upgrading the minimum PHP requirement to 8.3, replacing Grunt with Composer scripts, and introducing a new "Rename Plugin" feature that generates customized, renamed ZIP packages of the plugin. It also adds PHPUnit tests, updates coding standards, and refactors core classes to use typed properties and return types. The review feedback suggests improving security and usability on the renamer admin page by storing redirect error messages in WordPress Transients instead of passing them as raw URL query parameters.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the plugin by replacing the Grunt-based build system with a Composer-based workflow, updating the PHP requirement to 8.3+, and introducing a generator UI to download a renamed copy of the plugin. Feedback on the changes highlights a critical bug in the renamer page that causes a blank screen on normal access due to an incorrect early return on the nonce check. Additionally, it is recommended to restrict admin asset enqueuing to the plugin's specific pages to avoid global conflicts, and to update the PHPCompatibility testVersion in phpcs.xml to 8.3- to prevent false positives.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Move the nonce verification out of the top-level page render block so the page renders normally on first visit. Only verify the error redirect nonce when an error token is present.
Replace unset of the hook_suffix with an early return guard that only loads styles when the suffix contains 'framework-demo'. This avoids styling conflicts on other admin pages.
The plugin uses PHP 8.0+ features such as mixed return types. The previous testVersion of 7.4- caused false positive errors from PHPCompatibility.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the Saltus Framework Demo plugin by upgrading the minimum PHP requirement to 8.3, replacing the Grunt-based build system with Composer scripts, and introducing a new admin feature to generate renamed copies of the plugin as ZIP files. The review feedback highlights several opportunities for improvement, including failing fast in stream_zip() by checking headers early, defensively verifying request inputs to avoid array-to-string casting warnings, trimming vendor names to prevent malformed Composer package names, utilizing PHP 8's str_contains() in Assets.php, and ensuring the global $post object is a valid WP_Post instance before accessing its properties.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Check headers_sent() before disk I/O in stream_zip() so the application fails fast when streaming is impossible. Trim leading and trailing dashes from the generated vendor name in package_name() to prevent malformed Composer package names such as 'acme-inc-/my-plugin'. Existing tests for package_name verification are extended to cover the dash-trimming edge case.
Defensively verify that request values are not arrays before casting to string in from_request(), preventing PHP 8.x warnings when a malformed or malicious request submits an array for a text field.
Since this plugin requires PHP 8.3 or newer, use the more modern and readable str_contains() function instead of strpos().
Defensively verify that the global $post object is a valid WP_Post instance before accessing its properties, preventing potential PHP warnings or errors if the global is null or uninitialized.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the Saltus Framework Demo plugin by upgrading requirements to PHP 8.3 and PHPUnit 11, replacing Grunt tasks with Composer scripts, and introducing a new admin UI and backend logic to generate renamed plugin ZIP files. The review feedback highlights several opportunities to improve robustness and correctness: using substr instead of str_replace to safely strip root and source directories, adding a safety check to prevent an infinite loop in ob_end_clean(), providing a fallback vendor name for non-ASCII author names in PluginRenamer, removing a redundant validation call in PluginIdentity, and correcting typos in post-type-all.php (specifically the 'post_schedulled' key and the word 'permanetly').
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Replace str_replace with substr for removing root/source directory prefixes from file paths. str_replace can produce incorrect results when the directory name appears elsewhere in the path. Using substr with the length of the directory path is safer and more robust.
When the author name contains only non-ASCII characters (Cyrillic, Chinese, Japanese, emoji), the sanitized vendor name becomes empty, resulting in an invalid package name like '/plugin-slug'. Fall back to 'local' to ensure composer.json remains valid.
If an active output buffer was started with flags preventing it from being cleaned or removed, ob_end_clean() returns false and the buffer level does not decrease. This could cause an infinite loop. Breaking when ob_end_clean() fails prevents this.
self::validate() was called twice in from_request(): once before and once after esc_url_raw(). Since esc_url_raw() only sanitizes URLs and does not make a valid URL invalid, the first call is unnecessary. Fix the test bootstrap's esc_url_raw mock to match WordPress behavior (strip bad characters rather than return empty for non-URLs).
Fix the typo 'post_schedulled' -> 'post_scheduled'. The standard WordPress post updated message key is 'post_scheduled' (one 'l').
Fix the spelling 'permanetly' -> 'permanently' in the bulk delete message for the book post type.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request modernizes the Saltus Framework Demo plugin by upgrading the minimum PHP requirement to 8.3, replacing the Grunt build system with Composer scripts, and refactoring the core codebase to use strict typing and modern PHP features. It also introduces a new admin generator UI to let users download a renamed copy of the demo plugin as a ZIP file, backed by PHPUnit tests. The review feedback identifies two critical issues: a text domain mismatch bug in the renamer utility that breaks translations when the custom text domain differs from the plugin slug, and an invalid absolute path passed to load_plugin_textdomain which prevents local translation files from loading.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| private function rewrite_contents( string $contents, PluginIdentity $identity ): string { | ||
| $replacements = array( | ||
| self::ORIGINAL_NAMESPACE_SEGMENT => $identity->namespace_segment, | ||
| self::ORIGINAL_PACKAGE => $this->package_name( $identity ), | ||
| self::ORIGINAL_MAIN_FILE => $identity->main_file, | ||
| self::ORIGINAL_PREFIX_UPPER => strtoupper( $identity->prefix ), | ||
| self::ORIGINAL_PREFIX => $identity->prefix, | ||
| 'Plugin Name: ' . self::ORIGINAL_NAME => 'Plugin Name: ' . $identity->plugin_name, | ||
| 'Description: ' . self::ORIGINAL_DESCRIPTION => 'Description: ' . $identity->description, | ||
| 'Plugin URI: ' . self::ORIGINAL_PLUGIN_URI => 'Plugin URI: ' . $identity->plugin_uri, | ||
| 'Author URI: ' . self::ORIGINAL_AUTHOR_URI => 'Author URI: ' . $identity->author_uri, | ||
| 'Author: ' . self::ORIGINAL_AUTHOR => 'Author: ' . $identity->author, | ||
| self::ORIGINAL_SLUG => $identity->plugin_slug, | ||
| "PLUGIN_VERSION', '" . self::ORIGINAL_VERSION . "'" => "PLUGIN_VERSION', '" . $identity->version . "'", | ||
| self::ORIGINAL_VERSION => $identity->version, | ||
| ); | ||
|
|
||
| return strtr( $contents, $replacements ); |
There was a problem hiding this comment.
⚠️ Text Domain Mismatch Bug
There is a discrepancy between how the plugin_slug and text_domain fields are handled during the renaming process:
- In
target_path(), the.pottranslation file is renamed using$identity->text_domain(e.g.,my-custom-domain.pot). - In
rewrite_contents(), the text domain header and all translation calls (e.g.,__( 'Books', 'framework-demo' )) are rewritten using$identity->plugin_slug(because'framework-demo'is mapped to$identity->plugin_slug).
If a user enters a text_domain that is different from the plugin_slug, the generated plugin's PHP files will use the slug as the text domain (e.g., my-plugin), while the translation files in the languages/ directory will be named after the custom text domain (e.g., my-custom-domain-en_US.mo). As a result, WordPress will fail to load any translations due to this domain mismatch.
Recommended Solutions:
- Option A (Simplest & Standard): Remove the
text_domainfield from the generator UI entirely and always use theplugin_slugas the text domain. In the WordPress ecosystem, it is standard practice for the plugin slug and text domain to be identical. - Option B: If you must support different values, you need to update
rewrite_contents()to specifically target and replace the text domain header and translation calls with$identity->text_domaininstead of$identity->plugin_slug.
| $i18n = new Plugin\I18n( $this->name ); | ||
| private function set_locale(): void { | ||
| $i18n = new I18n( $this->name ); | ||
| $i18n->load_plugin_textdomain( dirname( $this->file_path ) ); |
There was a problem hiding this comment.
🐛 Absolute Path Passed to load_plugin_textdomain
In WordPress, the third argument of load_plugin_textdomain() must be a relative path to WP_PLUGIN_DIR, not an absolute path.
Passing an absolute path (returned by dirname( $this->file_path )) causes WordPress to concatenate WP_PLUGIN_DIR with the absolute path, resulting in an invalid path like /wp-content/plugins/var/www/.../languages/. This prevents local translation files (.mo) from being loaded.
To fix this, use plugin_basename() to get the relative path.
$i18n->load_plugin_textdomain( dirname( plugin_basename( $this->file_path ) ) );
No description provided.