Skip to content

Media/Admin: migrate raw inline scripts to wp_print_inline_script_tag() - #13319

Open
tinhien11 wants to merge 4 commits into
WordPress:trunkfrom
tinhien11:csp-slice-media-v2
Open

Media/Admin: migrate raw inline scripts to wp_print_inline_script_tag()#13319
tinhien11 wants to merge 4 commits into
WordPress:trunkfrom
tinhien11:csp-slice-media-v2

Conversation

@tinhien11

@tinhien11 tinhien11 commented Aug 30, 2026

Copy link
Copy Markdown

Description

Follows up on the Trac ticket discussion (comment 19): migrates the raw inline
<script> blocks in wp-admin/admin-header.php and wp-admin/includes/media.php to
wp_print_inline_script_tag(), matching the patterns established in r60909 / r60913.

This is a prerequisite slice for the Content Security Policy rollout discussed in Trac #59446: once all admin inline scripts route through the script tag API, the
wp_inline_script_attributes filter becomes the single point where a per-request nonce can be attached.

Changes

  • wp-admin/admin-header.php: the global admin JS (addLoadEvent, ajaxurl, pagenow, typenow,
    adminpage, locale separators, isRtl) and the no-js -> js body-class replacement are now printed via wp_print_inline_script_tag().
  • wp-admin/includes/media.php: 10 of the 11 inline script blocks (send-to-editor handoff, plupload init, preloaded media item lists, wpOnload() trigger, post_id echo) migrated. The disable_captions conditional and the dynamic admin image URLs keep their existing behavior.
  • Deferred: the addExtImage raw block (the only remaining <script> in media.php) needs the same treatment but ships separately to keep this slice reviewable.

Verification

  • php -l on both files.
  • The emitted JS is byte-identical to the previous output (same esc_js() values, same
    statement order; only the surrounding <script> wrapper newlines differ).
  • Rendered-markup diff on a live admin page will be attached from the PR test run.

Next steps

With this in place, the script-loader can attach a per-request nonce via the
wp_inline_script_attributes filter, enabling the report-only CSP discussed in Trac #59446.

Trac ticket: https://core.trac.wordpress.org/ticket/59446 (see comment 19).

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @tinhien11.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

Core Committers: Use this line as a base for the props when committing in SVN:

Props sergeybiryukov, westonruter.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

- admin-header.php: global admin JS (ajaxurl, pagenow, adminpage...) and
  the no-js replacement now print through wp_print_inline_script_tag().
- includes/media.php: all 11 inline script blocks (send-to-editor, plupload
  init, addExtImage, preloaded item lists) migrated to
  wp_print_inline_script_tag() with the same JS output; the disable_captions
  conditional and dynamic admin image URLs are preserved.
- Prerequisite for the CSP rollout (#59446): the
  wp_inline_script_attributes filter can now attach a per-request nonce to
  these scripts.
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/admin-header.php Outdated
</script>
<?php
wp_print_inline_script_tag(
"document.body.className = document.body.className.replace('no-js','js');"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a nowdoc here too. The benefit here is IDEs will do syntax highlighting and syntax checking.

Before:

Image

After:

Image
Suggested change
"document.body.className = document.body.className.replace('no-js','js');"
<<<'JS'
document.body.className = document.body.className.replace( 'no-js', 'js' );
JS

Comment thread src/wp-admin/admin-header.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php
- Use nowdoc for addLoadEvent in admin-header.php
- Use Object.assign + wp_json_encode for globals instead of esc_js()
- Clean up indentation and code style

Addresses feedback from westonruter on WordPress#13319 (see PR review comments).
… refactor

- Use nowdoc for the migrated inline scripts (admin-header.php no-js
  replacement, the three preloaded-item handlers in media.php, the popup
  addLoadEvent) so IDEs syntax-check the JS.
- Refactor the media-upload-popup globals block the same way as
  admin-header.php: unminified, strict-mode compatible addLoadEvent, and
  Object.assign( window, wp_json_encode( ... ) ) instead of esc_js()
  string building, per the suggestion.
- media_send_to_editor() prints via the suggested sprintf() + wp_json_encode().
- Remove the PHP close/reopen pairs introduced by the migration in
  media_send_to_editor(), wp_iframe(), media_upload_form_handler(),
  media_upload_gallery_form() and admin-header.php.
- Keep isRtl as (int) to preserve the previous JS value type.

See #59446.
@tinhien11

Copy link
Copy Markdown
Author

Thanks for the detailed review @westonruter — all points addressed in cfaa362:

  • Nowdoc everywhere: the admin-header no-js replacement script, the three preloaded handlers in media.php, and the popup addLoadEvent.
  • media-upload-popup globals block now mirrors admin-header: unminified, strict-mode-compatible addLoadEvent, and Object.assign( window, wp_json_encode( ... ) ) with JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS. The popup keeps its original variable subset (ajaxurl, pagenow, adminpage, isRtl).
  • media_send_to_editor() uses the suggested sprintf() + wp_json_encode() form.
  • PHP close/reopen pairs removed: the wp_print_inline_script_tag() calls now sit directly in the surrounding PHP blocks in media_send_to_editor(), wp_iframe() (×2), media_upload_form_handler(), media_upload_gallery_form(), and both spots in admin-header.php.
  • isRtl stays (int) as in your suggestion, preserving the previous JS value type.

Coding standards (PHP/JS) and PHP compatibility pass on the new head; the rest of the matrix is running.

Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/admin-header.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
Comment thread src/wp-admin/includes/media.php Outdated
- Use nowdoc heredocs for static inline scripts in wp_iframe() and gallery handling.
- Use wp_json_encode() with full JSON flag set for Object.assign() data payloads.
- Scope post_id to var instead of implicit global in media_upload_header().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants