feat(logger): add PSR-3 logger that captures wpseo_logger output#281
Open
feat(logger): add PSR-3 logger that captures wpseo_logger output#281
Conversation
Adds a text-input field helper alongside the existing checkbox/select helpers, so integrations can render text inputs in the same form style without hand-rolling HTML. Includes a small CSS rule for input[type=text] so the new field aligns with surrounding controls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces Yoast SEO's NullLogger via the wpseo_logger filter with a real PSR-3 implementation that persists captured entries to a configurable backend, plus an admin UI to enable/disable the logger, pick a level threshold, switch between backends, and view or clear the captured logs. Backends: - Database: a dedicated wp_yoast_test_helper_log table created lazily via dbDelta on first use, capped at 1000 rows (filterable through Yoast\WP\Test_Helper\logger_max_rows). Uses %i identifier placeholders so $wpdb->prepare() handles table-name escaping. - File: a JSONL file at a user-configurable absolute path, capped at 5MB with rotation by halving. Writes and rotation happen under the same flock so concurrent writers don't lose data. Path validation rejects anything inside wp-content/ or the uploads directory. Implementation extends \YoastSEO_Vendor\Psr\Log\AbstractLogger (the prefixed copy shipped by Yoast SEO) rather than pulling in psr/log, so the resulting object satisfies the same interface Yoast SEO's filter is typed against. Filter registration is gated by class_exists so the test helper doesn't fatal when Yoast SEO is inactive. The viewer renders inline as a compact summary with View / Delete link-buttons; clicking View opens a wide native HTML <dialog popover> with the most recent entries (cap 1000, with "1000+" overflow text when there's more behind the cap). Fixes #87 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR can be summarized in the following changelog entry:
NullLoggervia thewpseo_loggerfilter and persists captured entries to either a custom DB table or a JSONL file.Relevant technical choices
\YoastSEO_Vendor\Psr\Log\AbstractLogger(Yoast SEO's prefixed copy) so the resulting object satisfies the sameLoggerInterfaceYoast SEO's filter is typed against. Filter registration is gated byclass_exists('\YoastSEO_Vendor\Psr\Log\AbstractLogger')so the test helper does not fatal when Yoast SEO is inactive.{prefix}yoast_test_helper_logtable created lazily viadbDeltaon first use (capped at 1000 rows; cap is filterable throughYoast\WP\Test_Helper\logger_max_rows), or a JSONL file at a user-configurable absolute path (capped at 5MB with rotation by halving). The DB backend uses%iidentifier placeholders so$wpdb->prepare()handles table-name escaping.write(),clear(), and rotation all happen under a singleflock(LOCK_EX)per call, so concurrent writers don't lose data during rotation...-containing, non-writable, and paths insideWP_CONTENT_DIR/ the uploads directory — those are typically web-accessible. UI also shows an inline warning under the path field.{date}/{list}/{object}substitute meaningfully.<dialog popover>for the full table — no JavaScript required for open/close/ESC. Capped at 1000 entries; renders "1000+ logs captured" when there's more behind the cap. View / Delete are link-style buttons (Delete isbutton-link-delete, red), keeping Save as the only primary CTA.Milestone
Test instructions
Test instructions for the acceptance test before the PR gets merged
This PR can be acceptance tested by following these steps:
wp db query "SHOW TABLES LIKE '%yoast_test_helper_log'".wp eval 'apply_filters("wpseo_logger", new \YoastSEO_Vendor\Psr\Log\NullLogger())->warning("hello {who}", ["who" => "world"]);'./tmp/yoast-test-helper.log, save. Repeat thewp evalfrom step 4.tail /tmp/yoast-test-helper.logshows one JSON line containing"level":"warning"and"message":"hello world". Reload panel, confirm the viewer shows the entry. Click Delete — file truncates to 0 bytes.->warning(...)and a->critical(...). Only the critical entry persists./wp-content/uploads/anything.log. Confirm an error notification renders, the path doesn't save, and the logger doesn't switch on.composer check-cs-thresholds; should pass at the existing baseline (32 errors, 0 warnings).Test instructions for QA when the code is in the RC
Fixes #87