Summary
Full review of develop @ b744727 against a clean WP 7.0.3 / PHP 8.3 / BuddyPress 14.5.2 install (DDEV).
Correction (see also findings 12 and 13 below). An earlier revision of this issue opened with "PHPCS is clean (13 violations across 129 files)". That was wrong twice over. The run had testVersion overridden to 7.4-, contradicting the 5.3- in phpcs.xml; as actually configured the repo reports 15 errors, not 13. And "clean" only describes one of the three rulesets this repo defines — bin/pre-commit gates on --standard=WordPress, which reports 24,879 violations. The linting posture is covered properly in finding 13.
Two PHP warnings fire on every page load of a default install. One of the CSS files we ship had silently drifted from its SCSS source. Security findings from the same review are being reported separately per SECURITY.md.
1. PHP warnings on a default install
1a. Every front-end page load
app/main/RTMediaUploadTerms.php:100
$general_upload_terms_error_message = apply_filters(
'rtmedia_upload_terms_check_terms_message',
$rtmedia->options['general_upload_terms_error_message']
);
Unguarded array access. general_upload_terms_error_message is not seeded by init_site_options(), so it only exists once an admin saves the Upload Terms settings. Every neighbouring line in the same method uses isset() / ! empty().
Reproduced on /, /members/, /activity/:
PHP Warning: Undefined array key "general_upload_terms_error_message"
1b. Every admin page load
app/importers/RTMediaMigration.php:229 — PHP Warning: Undefined variable $count
$count is first assigned at :171, inside if ( ! empty( $_SESSION['migration_user_album'] ) ). On an install with no legacy bp-media data none of the four accumulator branches run, so return $count; warns and returns null. Reached from add_migration_notice() on admin_init.
2. $_SESSION is used without session_start()
RTMediaMigration.php has 20+ $_SESSION reads/writes and the plugin calls session_start() nowhere. Values do not survive the request, so the migration's cross-request progress tracking cannot work — migrate_to_new_db() (:678) reads $_SESSION['migration_media'] expecting a previous request to have set it. This is also the root cause of 1b.
Worth noting readme.txt advertises WordPress.com VIP compatibility, and VIP prohibits PHP sessions.
3. grunt build does not build the non-minified CSS — and it had drifted
Gruntfile.js registers:
grunt.registerTask( 'build', [ 'sass:minify', 'shell:postcss', 'terser' ] );
sass:dist (which produces the expanded admin.css / rtmedia.css) never runs. Running it revealed the committed app/assets/css/rtmedia.css was missing an entire block of button reset and :focus-visible styles that exist in _rtm.scss — a 115-line diff.
Those expanded files ship whenever rtm_get_script_style_suffix() returns '' (RTMedia.php:1316-1319, RTMediaAdmin.php:858), so anyone running SCRIPT_DEBUG has been served stale, less accessible CSS.
Fix: [ 'sass', 'shell:postcss', 'terser' ].
4. Two SCSS sources are never compiled by any task
app/assets/admin/css/sass/widget.scss and sass/rtm-upload-terms.scss exist, and their .css outputs are enqueued (RTMediaAdmin.php:862, RTMediaUploadTerms.php:103) — but neither appears in the Gruntfile sass config. Editing either SCSS file currently has no effect on the shipped CSS.
Related: shell:postcss globs app/assets/**/css/*.css --replace, sweeping in already-minified and already-prefixed files. That is why widget.min.css and rtm-upload-terms.min.css show as modified after a build that never compiled them.
5. rtmedia_bp is not localized under SCRIPT_DEBUG
app/main/RTMedia.php:1341-1358 — wp_localize_script( 'rtmedia-main', 'rtmedia_bp', … ) sits only in the else (minified) branch. rtMedia.js:7 copies every rtmedia_bp key onto window, so with SCRIPT_DEBUG on, bp_template_pack is never set and template-pack-conditional JS diverges from production. Move the call outside the branch.
6. BuddyPress-derived settings are frozen at first activation
RTMedia.php:275 calls init_site_options() only when rtmedia-options is absent; that calls init_buddypress_options() (:744), which derives buddypress_enableOnActivity / enableOnGroup from bp_is_active().
Hit live during this review: activating rtMedia before BuddyPress had run its installer left both permanently false. Activity uploads are silently disabled with no indication why, and re-activating rtMedia does not recover — rtmedia-options already exists.
Suggest re-deriving these on bp_init when no explicit user preference is stored, or surfacing an admin notice when BP components are active but the rtMedia toggles are off.
7. GoDAM integration
Cross-checked against the GoDAM 2.1.1 release from wp.org (downloads.wordpress.org/plugin/godam.zip). GoDAM is also an rtCamp plugin, so these are coordinatable rather than third-party risks.
7a. Dead enqueue — godam-player-frontend-style does not exist
templates/media/godam-integration.php:27
wp_enqueue_style( 'godam-player-frontend-style' );
That handle appears nowhere in GoDAM 2.1.1. The three siblings around it are all real, registered in inc/classes/shortcodes/class-godam-player.php:137-190:
| rtMedia enqueues |
Registered by GoDAM |
godam-player-frontend-script |
yes (:137) |
godam-player-analytics-script |
yes (:148, guarded by file_exists) |
godam-player-frontend-style |
no — handle does not exist |
godam-player-style |
yes (:157) |
godam-player-{minimal,pills,bubble,classic}-skin |
yes (:164-190) |
wp_enqueue_style() on an unregistered handle is a silent no-op, so this has never surfaced as an error. Either drop the line or correct it to whatever style was intended.
7b. The "multisite safe" comment is wrong — but the code is right
:33 is annotated "Skin detection — multisite safe (uses site option)" and the file header repeats the claim, while the call is get_option( 'rtgodam-settings', array() ).
The code is correct and must not be changed. GoDAM reads and writes this option with get_option() / update_option() throughout — inc/classes/rest-api/class-settings.php:348 is the writer, and all 12 read sites use get_option. Switching rtMedia to get_site_option() would read a key GoDAM never writes and silently break skin detection on every install.
Fix is to delete the two misleading comments, not to touch the call.
7c. Function naming
| Line |
Function |
Status |
| 23 |
godam_enqueue_player_assets() |
no collision in GoDAM 2.1.1, but see below |
| 202 |
handle_get_single_activity_comment_html() |
entirely unprefixed, very generic, registered as wp_ajax_get_single_activity_comment_html |
| 258 |
rtmedia_user_can_view_activity() |
fine |
| 352 |
enqueue_rtmedia_magnific_popup_script() |
prefix buried mid-name |
GoDAM's primary prefix is rtgodam_ (RTGODAM_URL, rtgodam_cache_delete(), …), so godam_enqueue_player_assets() does not collide today. It is not a free namespace though — GoDAM declares seven bare godam_ globals of its own (godam_embed_page_content(), godam_preview_page_content(), godam_is_audio_file(), godam_get_transcript_path(), godam_is_supported_document(), godam_is_audio_file_by_name(), godam_should_load_auth_detector_script()), none of them function_exists-guarded, and neither is rtMedia's. Two rtCamp plugins growing the same unguarded global namespace is a fatal-redeclare waiting to happen.
handle_get_single_activity_comment_html() is the one worth fixing regardless of GoDAM — it is a completely generic global name owned by no prefix at all. The handler itself is correctly secured (nonce + login + permission check); this is purely a naming risk.
7d. Verified correct, no action needed
is_plugin_active( 'godam/godam.php' ) in index.php:74 matches GoDAM's actual folder/file layout.
Enqueue ordering is sound: GoDAM registers on wp_enqueue_scripts at priority 10 (class-godam-player.php:27), rtMedia enqueues at 20.
The skin mapping matches GoDAM's own vocabulary exactly — Default, Minimal, Pills, Bubble, Classic — and correctly no-ops on Default.
godam-ajax-nonce is rtMedia's own nonce action, not a GoDAM one.
7e. Open question — should video-preview be excluded too?
:52 skips loading the integration script on GoDAM's embed page:
if ( 'video-embed' !== get_query_var( 'godam_page' ) ) {
GoDAM serves two bare-player contexts off that query var: video-embed (inc/classes/class-video-embed.php:54) and video-preview (inc/classes/class-video-preview.php:52). Only the first is excluded. Worth confirming with whoever wrote 9aa1f82 whether video-preview was deliberately left in.
7f. Unrelated to GoDAM: $activities_template stub
:231-233 replaces the global $activities_template with a bare stdClass carrying only ->activity, then renders bp_get_template_part( 'activity/entry' ) against it. The restore at :239 only puts ->activity back, and only when the original was truthy. Contained because the request ends in wp_send_json_success(), but fragile against BP template changes.
Note for scheduling: GoDAM already ships first-class rtMedia support in the other direction (admin/godam-transcoder-actions.php:240 hooks rtmedia_after_update_media, and calls rtmedia_type() / rtmedia_media_id()), so 7a/7b/7c are worth coordinating with the GoDAM team rather than fixing unilaterally.
8. Text domain inconsistency
RTMediaUploadTerms::load_translation() (:88) loads domain 'rtmedia'. All 1,016 translatable strings use 'buddypress-media' (5 use 'rtmedia'), so that load_plugin_textdomain() call is a no-op.
Separately, the template file is misnamed: languages/buddpress-media.pot (missing the "u").
9. Admin includes loaded on every front-end request
index.php:66-75 pulls in wp-admin/includes/plugin.php and calls is_plugin_active( 'godam/godam.php' ) at plugin-load time to define RTMEDIA_GODAM_ACTIVE. That loads an admin-only file on every public page view.
Correction to an earlier revision of this issue: it previously claimed is_plugin_active() ignores network activation, and proposed replacing it with a bare in_array( …, get_option( 'active_plugins' ) ). That was wrong on both counts. WP core (wp-admin/includes/plugin.php:539-541) is:
function is_plugin_active( $plugin ) {
return in_array( $plugin, (array) get_option( 'active_plugins', array() ), true ) || is_plugin_active_for_network( $plugin );
}
The network check is already there, and the proposed one-liner would have dropped multisite support for RTMEDIA_GODAM_ACTIVE. Do not apply it.
What remains is narrower: an admin-only file is loaded on every front-end request, and the constant is resolved at plugin-load time rather than lazily. If this is worth changing at all, the options are to defer the definition to plugins_loaded, or to inline both halves of core's check (active_plugins plus active_sitewide_plugins) — not to drop one of them. Low priority; correctness is fine as-is.
10. No automated test coverage
tests/ contains only bootstrap.php and rt-wp-test-case.php — zero test-*.php files, so phpunit.xml matches nothing.
.github/workflows/playwright.yml is gated on if: false and points at ./tests/wp-e2e-playwright, which no longer exists in the tree (removed in f9c4841). .github/ci/main.sh still references it too.
There is currently no automated verification of this plugin.
11. Stale version metadata and toolchain drift
No Requires PHP header in index.php or readme.txt.
phpcs.xml sets testVersion 5.3-; the plugin runs on PHP 8.3+ in practice.
Requires at least: 4.1, Tested up to: 6.9 (current WP is 7.0.x).
.nvmrc pins v20.18.1; CI sets NODE_VERSION: 22.
grunt-checktextdomain and grunt-wp-i18n are devDependencies with no Gruntfile config.
.bowerrc and app/assets/css/sass/.bowerrc are Bower leftovers.
No composer.json, so PHPCS cannot be run locally without a manual WPCS install.
Sass darken() deprecations are already tracked in #2119 and not repeated here.
12. JavaScript is never linted — 1,283 JSHint errors
bin/.jshintrc exists (symlinked to .jshintrc at the repo root) and bin/pre-commit runs JSHint against staged .js files. But jshint is not a devDependency, no npm script invokes it, and no CI job runs it. It has evidently never been run.
Running it against the six JS sources with the repo's own config:
jshint --config bin/.jshintrc \
app/assets/js/rtMedia.js app/assets/js/godam-integration.js \
app/assets/js/godam-ajax-refresh.js app/assets/admin/js/scripts.js \
app/assets/admin/js/settings.js app/assets/admin/js/rtmedia-admin.js
→ 1283 errors
Not all cosmetic. A sample from app/assets/admin/js/rtmedia-admin.js:
line 83, col 21, 'ajaxurl' is not defined.
line 95, col 21, 'ajaxurl' is not defined.
line 105, col 16, 'ajaxurl' is not defined.
line 12, col 13, 'console' is not defined.
ajaxurl is a legitimate WP admin global and console is a browser global; both are simply missing from the globals block in bin/.jshintrc, which currently declares only jQuery and wp. So part of the count is config debt rather than code defects — but nobody can tell which part until someone triages it, and that is the point.
Decide whether JS linting is a gate or not. If yes, add the tooling and burn down the list. If no, delete bin/.jshintrc and the JSHint block in bin/pre-commit so it stops implying a check that does not happen.
13. Three PHPCS rulesets that disagree, and one that cannot pass
The repo defines three different PHPCS configurations, and no two agree:
| Gate |
Standard |
Full-repo result |
phpcs.xml |
WordPress-Core (−Files.FileName, −PreparedSQL.*) + Extra + Docs + PHPCompatibility 5.3- |
15 errors |
bin/pre-commit |
--standard=WordPress (plain) |
24,879 violations |
.github/workflows/phpcs_on_pull_request.yml |
WordPress,WordPress-Core,WordPress-Docs, excludes WordPress.Files.FileName, skips tests,.github,lib,node_modules,vendor |
diff-only, n/a |
bin/pre-commit cannot pass in its current state, so it is dead in practice — consistent with there being no composer.json to install phpcs from (finding 11).
Two real violations of the repo's own phpcs.xml, missed until the config was honoured rather than overridden:
templates/media/godam-integration.php:31 null coalescing operator (??) is not present in PHP version 5.6
templates/media/godam-integration.php:228 null coalescing operator (??) is not present in PHP version 5.6
Either testVersion is stale and should be raised to match a real support floor, or ?? should not be in the codebase. Both cannot be true. This is the same question as the missing Requires PHP header in finding 11 — resolve them together.
13a. The clean security-sniff result is self-declared, not tool-verified
phpcs.xml globally disables WordPress.DB.PreparedSQL.InterpolatedNotPrepared and WordPress.DB.PreparedSQL.NotPrepared. Re-enabling them via --standard=WordPress produces zero Security, PreparedSQL, EscapeOutput or NonceVerification hits — but only because the source carries 409 inline suppressions of precisely those sniffs:
358 WordPress.DB.* (96 DirectQuery, 92 NoCaching, 85 InterpolatedNotPrepared,
81 NotPrepared, 3 SchemaChange, 1 UnfinishedPrepare)
45 WordPress.Security.NonceVerification.*
6 WordPress.Security.EscapeOutput.OutputNotEscaped
Every one of those is an unreviewed assertion by whoever added it. No automated check currently backs the claim that this codebase is free of SQL injection or missing-nonce problems; the only thing supporting it is manual reading, which is exactly the weaker form of evidence this issue has already been burned by twice.
Suggested: audit the 409 suppressions in batches, and drop the two global PreparedSQL excludes from phpcs.xml so future code has to justify itself inline rather than inheriting a blanket exemption.
14. Dependency vulnerabilities in the dev toolchain
npm audit reports 6 vulnerabilities (5 high, 1 moderate), all with fixes available via npm audit fix:
| Package |
Severity |
Route |
js-yaml |
high |
transitive via grunt |
nanoid |
high |
transitive |
postcss |
moderate |
direct dependency in package.json |
Dev-only, so not a runtime risk to sites, but postcss is declared directly and is trivially bumpable. Related to #2346 and #2240, which track the Dependabot alerts.
Proposed order of work
Grouped by what unblocks them, not by size. The split below is deliberate: items marked observed were reproduced on a running install, items marked inferred were read out of the code and have a worse track record in this issue (see the two corrections above, both of which were confident one-liners that would have broken something).
Observed — safe to fix directly (PR #2359, open)
Inferred — validate before designing the fix
Blocked on a decision, not on testing
How to test
Durable steps for verifying the items above. Environment used throughout: WP 7.0.3, PHP 8.3.30, BuddyPress 14.5.2, MariaDB 11.8, DDEV v1.25.2.
1a / 1b — the two page-load warnings
# On develop, both counters climb; on the fix branch they stay flat.
ddev logs | grep -cE 'general_upload_terms_error_message|Undefined variable \$count'
curl -sk -o /dev/null https://<ddev-host>/
curl -sk -o /dev/null https://<ddev-host>/members/
ddev logs | grep -cE 'general_upload_terms_error_message|Undefined variable \$count'
1b needs an authenticated admin request (it fires from add_migration_notice() on admin_init). Requires WP_DEBUG on and a fresh install with no legacy bp-media-key postmeta.
7a — the dead GoDAM handle
curl -sL -o godam.zip https://downloads.wordpress.org/plugin/godam.zip && unzip -q godam.zip
grep -rn 'godam-player-frontend-style' godam/ # no output — handle does not exist
grep -rn "'godam-player-style'" godam/ # registered, class-godam-player.php:157
7b — do not "fix" the get_option call
grep -rn "rtgodam-settings" godam/ | grep -c get_site_option # 0
grep -rn "update_option( 'rtgodam-settings'" godam/ # class-settings.php:348
6 — activation-order bug
On a clean DB: activate rtMedia before BuddyPress has run its installer, then check wp option get rtmedia-options --format=json. buddypress_enableOnActivity will be false permanently, and re-activating rtMedia does not recover it because rtmedia-options already exists.
PHPCS
No composer.json ships with the plugin, so install the standards out-of-tree:
composer config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
composer require --dev wp-coding-standards/wpcs:^3.1 phpcompatibility/phpcompatibility-wp:^2.1 dealerdirect/phpcodesniffer-composer-installer
Run each gate as it is actually configured — do not override testVersion, which is what hid the two ?? errors in finding 13:
# phpcs.xml as configured → 15 errors on develop @ b7447272
vendor/bin/phpcs --standard=phpcs.xml .
# bin/pre-commit gate → 24,879 violations
vendor/bin/phpcs --standard=WordPress --ignore='*/tests/*,*/lib/*,*/node_modules/*,*/vendor/*,*/bin/*' .
# CI ruleset, per changed file → what phpcs_on_pull_request.yml reviews
vendor/bin/phpcs --standard=WordPress,WordPress-Core,WordPress-Docs --exclude=WordPress.Files.FileName <file>
templates/media/godam-integration.php accounts for 6 of the 15 and is expected to stay dirty until 7c and 13 land.
Other gates
jshint --config bin/.jshintrc app/assets/js/*.js app/assets/admin/js/*.js # 1283 errors (finding 12)
for f in $(find app templates index.php -name '*.php'); do php -l "$f"; done # all pass
npm audit # 6 vulns (finding 14)
PHPUnit has nothing to run — phpunit.xml matches tests/test-*.php and no such file exists (finding 10).
Environment
WordPress 7.0.3, PHP 8.3.30, MariaDB 11.8, BuddyPress 14.5.2, DDEV v1.25.2
rtMedia 4.7.11, develop @ b744727
PHPCS run with WPCS 3.4.1 + PHPCompatibility, using each gate's own configuration (no testVersion override). JSHint 2.x, Node 22, npm 11.
Summary
Full review of
develop@ b744727 against a clean WP 7.0.3 / PHP 8.3 / BuddyPress 14.5.2 install (DDEV).Two PHP warnings fire on every page load of a default install. One of the CSS files we ship had silently drifted from its SCSS source. Security findings from the same review are being reported separately per
SECURITY.md.1. PHP warnings on a default install
1a. Every front-end page load
app/main/RTMediaUploadTerms.php:100Unguarded array access.
general_upload_terms_error_messageis not seeded byinit_site_options(), so it only exists once an admin saves the Upload Terms settings. Every neighbouring line in the same method usesisset()/! empty().Reproduced on
/,/members/,/activity/:PHP Warning: Undefined array key "general_upload_terms_error_message"1b. Every admin page load
app/importers/RTMediaMigration.php:229—PHP Warning: Undefined variable $count$countis first assigned at:171, insideif ( ! empty( $_SESSION['migration_user_album'] ) ). On an install with no legacy bp-media data none of the four accumulator branches run, soreturn $count;warns and returnsnull. Reached fromadd_migration_notice()onadmin_init.2.
$_SESSIONis used withoutsession_start()RTMediaMigration.phphas 20+$_SESSIONreads/writes and the plugin callssession_start()nowhere. Values do not survive the request, so the migration's cross-request progress tracking cannot work —migrate_to_new_db()(:678) reads$_SESSION['migration_media']expecting a previous request to have set it. This is also the root cause of 1b.Worth noting
readme.txtadvertises WordPress.com VIP compatibility, and VIP prohibits PHP sessions.3.
grunt builddoes not build the non-minified CSS — and it had driftedGruntfile.jsregisters:sass:dist(which produces the expandedadmin.css/rtmedia.css) never runs. Running it revealed the committedapp/assets/css/rtmedia.csswas missing an entire block of button reset and:focus-visiblestyles that exist in_rtm.scss— a 115-line diff.Those expanded files ship whenever
rtm_get_script_style_suffix()returns''(RTMedia.php:1316-1319,RTMediaAdmin.php:858), so anyone runningSCRIPT_DEBUGhas been served stale, less accessible CSS.Fix:
[ 'sass', 'shell:postcss', 'terser' ].4. Two SCSS sources are never compiled by any task
app/assets/admin/css/sass/widget.scssandsass/rtm-upload-terms.scssexist, and their.cssoutputs are enqueued (RTMediaAdmin.php:862,RTMediaUploadTerms.php:103) — but neither appears in the Gruntfilesassconfig. Editing either SCSS file currently has no effect on the shipped CSS.Related:
shell:postcssglobsapp/assets/**/css/*.css --replace, sweeping in already-minified and already-prefixed files. That is whywidget.min.cssandrtm-upload-terms.min.cssshow as modified after a build that never compiled them.5.
rtmedia_bpis not localized underSCRIPT_DEBUGapp/main/RTMedia.php:1341-1358—wp_localize_script( 'rtmedia-main', 'rtmedia_bp', … )sits only in theelse(minified) branch.rtMedia.js:7copies everyrtmedia_bpkey ontowindow, so withSCRIPT_DEBUGon,bp_template_packis never set and template-pack-conditional JS diverges from production. Move the call outside the branch.6. BuddyPress-derived settings are frozen at first activation
RTMedia.php:275callsinit_site_options()only whenrtmedia-optionsis absent; that callsinit_buddypress_options()(:744), which derivesbuddypress_enableOnActivity/enableOnGroupfrombp_is_active().Hit live during this review: activating rtMedia before BuddyPress had run its installer left both permanently
false. Activity uploads are silently disabled with no indication why, and re-activating rtMedia does not recover —rtmedia-optionsalready exists.Suggest re-deriving these on
bp_initwhen no explicit user preference is stored, or surfacing an admin notice when BP components are active but the rtMedia toggles are off.7. GoDAM integration
Cross-checked against the GoDAM 2.1.1 release from wp.org (
downloads.wordpress.org/plugin/godam.zip). GoDAM is also an rtCamp plugin, so these are coordinatable rather than third-party risks.7a. Dead enqueue —
godam-player-frontend-styledoes not existtemplates/media/godam-integration.php:27That handle appears nowhere in GoDAM 2.1.1. The three siblings around it are all real, registered in
inc/classes/shortcodes/class-godam-player.php:137-190:godam-player-frontend-script:137)godam-player-analytics-script:148, guarded byfile_exists)godam-player-frontend-stylegodam-player-style:157)godam-player-{minimal,pills,bubble,classic}-skin:164-190)wp_enqueue_style()on an unregistered handle is a silent no-op, so this has never surfaced as an error. Either drop the line or correct it to whatever style was intended.7b. The "multisite safe" comment is wrong — but the code is right
:33is annotated "Skin detection — multisite safe (uses site option)" and the file header repeats the claim, while the call isget_option( 'rtgodam-settings', array() ).The code is correct and must not be changed. GoDAM reads and writes this option with
get_option()/update_option()throughout —inc/classes/rest-api/class-settings.php:348is the writer, and all 12 read sites useget_option. Switching rtMedia toget_site_option()would read a key GoDAM never writes and silently break skin detection on every install.Fix is to delete the two misleading comments, not to touch the call.
7c. Function naming
godam_enqueue_player_assets()handle_get_single_activity_comment_html()wp_ajax_get_single_activity_comment_htmlrtmedia_user_can_view_activity()enqueue_rtmedia_magnific_popup_script()GoDAM's primary prefix is
rtgodam_(RTGODAM_URL,rtgodam_cache_delete(), …), sogodam_enqueue_player_assets()does not collide today. It is not a free namespace though — GoDAM declares seven baregodam_globals of its own (godam_embed_page_content(),godam_preview_page_content(),godam_is_audio_file(),godam_get_transcript_path(),godam_is_supported_document(),godam_is_audio_file_by_name(),godam_should_load_auth_detector_script()), none of themfunction_exists-guarded, and neither is rtMedia's. Two rtCamp plugins growing the same unguarded global namespace is a fatal-redeclare waiting to happen.handle_get_single_activity_comment_html()is the one worth fixing regardless of GoDAM — it is a completely generic global name owned by no prefix at all. The handler itself is correctly secured (nonce + login + permission check); this is purely a naming risk.7d. Verified correct, no action needed
is_plugin_active( 'godam/godam.php' )inindex.php:74matches GoDAM's actual folder/file layout.Enqueue ordering is sound: GoDAM registers on
wp_enqueue_scriptsat priority 10 (class-godam-player.php:27), rtMedia enqueues at 20.The skin mapping matches GoDAM's own vocabulary exactly —
Default,Minimal,Pills,Bubble,Classic— and correctly no-ops onDefault.godam-ajax-nonceis rtMedia's own nonce action, not a GoDAM one.7e. Open question — should
video-previewbe excluded too?:52skips loading the integration script on GoDAM's embed page:GoDAM serves two bare-player contexts off that query var:
video-embed(inc/classes/class-video-embed.php:54) andvideo-preview(inc/classes/class-video-preview.php:52). Only the first is excluded. Worth confirming with whoever wrote 9aa1f82 whethervideo-previewwas deliberately left in.7f. Unrelated to GoDAM:
$activities_templatestub:231-233replaces the global$activities_templatewith a barestdClasscarrying only->activity, then rendersbp_get_template_part( 'activity/entry' )against it. The restore at:239only puts->activityback, and only when the original was truthy. Contained because the request ends inwp_send_json_success(), but fragile against BP template changes.Note for scheduling: GoDAM already ships first-class rtMedia support in the other direction (
admin/godam-transcoder-actions.php:240hooksrtmedia_after_update_media, and callsrtmedia_type()/rtmedia_media_id()), so 7a/7b/7c are worth coordinating with the GoDAM team rather than fixing unilaterally.8. Text domain inconsistency
RTMediaUploadTerms::load_translation()(:88) loads domain'rtmedia'. All 1,016 translatable strings use'buddypress-media'(5 use'rtmedia'), so thatload_plugin_textdomain()call is a no-op.Separately, the template file is misnamed:
languages/buddpress-media.pot(missing the "u").9. Admin includes loaded on every front-end request
index.php:66-75pulls inwp-admin/includes/plugin.phpand callsis_plugin_active( 'godam/godam.php' )at plugin-load time to defineRTMEDIA_GODAM_ACTIVE. That loads an admin-only file on every public page view.Correction to an earlier revision of this issue: it previously claimed
is_plugin_active()ignores network activation, and proposed replacing it with a barein_array( …, get_option( 'active_plugins' ) ). That was wrong on both counts. WP core (wp-admin/includes/plugin.php:539-541) is:The network check is already there, and the proposed one-liner would have dropped multisite support for
RTMEDIA_GODAM_ACTIVE. Do not apply it.What remains is narrower: an admin-only file is loaded on every front-end request, and the constant is resolved at plugin-load time rather than lazily. If this is worth changing at all, the options are to defer the definition to
plugins_loaded, or to inline both halves of core's check (active_pluginsplusactive_sitewide_plugins) — not to drop one of them. Low priority; correctness is fine as-is.10. No automated test coverage
tests/contains onlybootstrap.phpandrt-wp-test-case.php— zerotest-*.phpfiles, sophpunit.xmlmatches nothing..github/workflows/playwright.ymlis gated onif: falseand points at./tests/wp-e2e-playwright, which no longer exists in the tree (removed in f9c4841)..github/ci/main.shstill references it too.There is currently no automated verification of this plugin.
11. Stale version metadata and toolchain drift
No
Requires PHPheader inindex.phporreadme.txt.phpcs.xmlsetstestVersion 5.3-; the plugin runs on PHP 8.3+ in practice.Requires at least: 4.1,Tested up to: 6.9(current WP is 7.0.x)..nvmrcpinsv20.18.1; CI setsNODE_VERSION: 22.grunt-checktextdomainandgrunt-wp-i18nare devDependencies with no Gruntfile config..bowerrcandapp/assets/css/sass/.bowerrcare Bower leftovers.No
composer.json, so PHPCS cannot be run locally without a manual WPCS install.Sass
darken()deprecations are already tracked in #2119 and not repeated here.12. JavaScript is never linted — 1,283 JSHint errors
bin/.jshintrcexists (symlinked to.jshintrcat the repo root) andbin/pre-commitruns JSHint against staged.jsfiles. Butjshintis not a devDependency, no npm script invokes it, and no CI job runs it. It has evidently never been run.Running it against the six JS sources with the repo's own config:
Not all cosmetic. A sample from
app/assets/admin/js/rtmedia-admin.js:ajaxurlis a legitimate WP admin global andconsoleis a browser global; both are simply missing from theglobalsblock inbin/.jshintrc, which currently declares onlyjQueryandwp. So part of the count is config debt rather than code defects — but nobody can tell which part until someone triages it, and that is the point.Decide whether JS linting is a gate or not. If yes, add the tooling and burn down the list. If no, delete
bin/.jshintrcand the JSHint block inbin/pre-commitso it stops implying a check that does not happen.13. Three PHPCS rulesets that disagree, and one that cannot pass
The repo defines three different PHPCS configurations, and no two agree:
phpcs.xmlFiles.FileName, −PreparedSQL.*) + Extra + Docs + PHPCompatibility5.3-bin/pre-commit--standard=WordPress(plain).github/workflows/phpcs_on_pull_request.ymlWordPress,WordPress-Core,WordPress-Docs, excludesWordPress.Files.FileName, skipstests,.github,lib,node_modules,vendorbin/pre-commitcannot pass in its current state, so it is dead in practice — consistent with there being nocomposer.jsonto install phpcs from (finding 11).Two real violations of the repo's own
phpcs.xml, missed until the config was honoured rather than overridden:Either
testVersionis stale and should be raised to match a real support floor, or??should not be in the codebase. Both cannot be true. This is the same question as the missingRequires PHPheader in finding 11 — resolve them together.13a. The clean security-sniff result is self-declared, not tool-verified
phpcs.xmlglobally disablesWordPress.DB.PreparedSQL.InterpolatedNotPreparedandWordPress.DB.PreparedSQL.NotPrepared. Re-enabling them via--standard=WordPressproduces zero Security, PreparedSQL, EscapeOutput or NonceVerification hits — but only because the source carries 409 inline suppressions of precisely those sniffs:Every one of those is an unreviewed assertion by whoever added it. No automated check currently backs the claim that this codebase is free of SQL injection or missing-nonce problems; the only thing supporting it is manual reading, which is exactly the weaker form of evidence this issue has already been burned by twice.
Suggested: audit the 409 suppressions in batches, and drop the two global
PreparedSQLexcludes fromphpcs.xmlso future code has to justify itself inline rather than inheriting a blanket exemption.14. Dependency vulnerabilities in the dev toolchain
npm auditreports 6 vulnerabilities (5 high, 1 moderate), all with fixes available vianpm audit fix:js-yamlgruntnanoidpostcsspackage.jsonDev-only, so not a runtime risk to sites, but
postcssis declared directly and is trivially bumpable. Related to #2346 and #2240, which track the Dependabot alerts.Proposed order of work
Grouped by what unblocks them, not by size. The split below is deliberate: items marked observed were reproduced on a running install, items marked inferred were read out of the code and have a worse track record in this issue (see the two corrections above, both of which were confident one-liners that would have broken something).
Observed — safe to fix directly (PR #2359, open)
godam-player-frontend-styleenqueue, delete the incorrect "multisite safe" comments (leaveget_optionalone)load_plugin_textdomain( 'rtmedia' )→'buddypress-media'Inferred — validate before designing the fix
rtmedia_bplocalize underSCRIPT_DEBUG; may be benignrgb()); sequence against Prepare for Dart Sass 3.0.0 – Resolve Deprecations #2119widget.css/rtm-upload-terms.cssbefore adding them to the sass config, in case they were hand-edited while uncompiledvideo-previewshould be excluded alongsidevideo-embed$activities_templatestub break anything in BP Nouveau today?Blocked on a decision, not on testing
$_SESSIONon transients/user meta. Nobody can act without this answerbp_initwould flip settings on sites that deliberately disabled activity uploads. Needs an ownerTested up to: 7.0cannot honestly be written until someone tests on WP 7.0; same question astestVersion 5.3-vs the??usage and the missingRequires PHPheader. Resolve as onebin/.jshintrcand the JSHint block inbin/pre-commitbin/pre-commitcannot currently passPreparedSQLexcludes fromphpcs.xml.pot) — renamehandle_get_single_activity_comment_html(), agree afunction_existsconvention with the GoDAM team, renamebuddpress-media.potnpm audit fixfor the 6 dev-toolchain vulnerabilitiesHow to test
Durable steps for verifying the items above. Environment used throughout: WP 7.0.3, PHP 8.3.30, BuddyPress 14.5.2, MariaDB 11.8, DDEV v1.25.2.
1a / 1b — the two page-load warnings
1b needs an authenticated admin request (it fires from
add_migration_notice()onadmin_init). RequiresWP_DEBUGon and a fresh install with no legacybp-media-keypostmeta.7a — the dead GoDAM handle
7b — do not "fix" the
get_optioncall6 — activation-order bug
On a clean DB: activate rtMedia before BuddyPress has run its installer, then check
wp option get rtmedia-options --format=json.buddypress_enableOnActivitywill befalsepermanently, and re-activating rtMedia does not recover it becausertmedia-optionsalready exists.PHPCS
No
composer.jsonships with the plugin, so install the standards out-of-tree:composer config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true composer require --dev wp-coding-standards/wpcs:^3.1 phpcompatibility/phpcompatibility-wp:^2.1 dealerdirect/phpcodesniffer-composer-installerRun each gate as it is actually configured — do not override
testVersion, which is what hid the two??errors in finding 13:templates/media/godam-integration.phpaccounts for 6 of the 15 and is expected to stay dirty until 7c and 13 land.Other gates
PHPUnit has nothing to run —
phpunit.xmlmatchestests/test-*.phpand no such file exists (finding 10).Environment
WordPress 7.0.3, PHP 8.3.30, MariaDB 11.8, BuddyPress 14.5.2, DDEV v1.25.2
rtMedia 4.7.11,
develop@ b744727PHPCS run with WPCS 3.4.1 + PHPCompatibility, using each gate's own configuration (no
testVersionoverride). JSHint 2.x, Node 22, npm 11.