Skip to content

Show media on GoDAM's public routes only where WordPress would show it - #2245

Open
subodhr258 wants to merge 3 commits into
mainfrom
fix/public-media-visibility
Open

subodhr258 wants to merge 3 commits into
mainfrom
fix/public-media-visibility

Conversation

@subodhr258

@subodhr258 subodhr258 commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

What changes

GoDAM's public pages and routes now show a media item only where WordPress itself would, instead of answering for any media ID.

The rule (rtgodam_can_view_attachment() in inc/helpers/custom-functions.php):

  • Shown: unattached media, and media whose parent post is published (or another public status), with or without a password. This is the same answer WordPress's media API gives.
  • Refused, exactly like a missing ID: media of draft, pending, private, scheduled and trashed posts.
  • Signed-in users: anyone who can edit the media always sees it; users who can read a private or draft parent see its media.
  • Kept working: media used on any publicly viewable post counts as public, whichever post it was uploaded to (read from the media usage index, _godam_usage_post_ids). A video uploaded while drafting one post and placed on a published page keeps working in that page's player, gallery, lightbox and embed, and in embeds on other sites.
  • New filter rtgodam_can_view_attachment( $can_view, $attachment ) to tighten or relax the answer.

Where it applies

Entry point Change
Gallery block, shortcode and godam/v1/gallery-shortcode route same rule in SQL (rtgodam_public_media_query_clauses()), so paging and counts stay right; the listing is the same for every viewer
godam/v1/video-shortcode route refused media answers 404, like a missing ID
Preview page and embed page refused media shows the usual "not found" page
adTagURL/{id} route refused media gets an empty answer, like a missing ID
godam/v1/transcoding/transcoding-status route leaves out refused, missing and junk IDs; at most 100 IDs per request (maxItems, 400 above that); a read no longer writes anything (see below)
rtgodam_meta REST field on attachments stored settings only for users who can write posts (editor previews) or edit the media; null for visitors and Subscribers
Video SEO schema (wp_head and the footer path) printed only for posts whose content is public: not drafts, private, scheduled or password-protected posts

Transcoding status read. A transcoded video with no thumbnail yet used to be reported at 95% for three reads, counted by writing rtgodam_thumbnail_retry_count on every read. It is now reported at 95% for 15 seconds after the last status update, which the status callback stores (rtgodam_transcoding_status_updated). The media library's list-view poller (transcoding-checker.js) now sends IDs in batches of 100, because longer lists get a 400.

The video sitemap needed no change: it already lists only published posts without a password.

Testing

Throwaway WordPress (Playground, PHP 7.4, WordPress latest) with the 2.5.0 release plus these PHP files. A video attached to a page in each state, an unattached video, an exception video (uploaded to a draft, used on a published page), an Editor and an Author. Logged out / Editor:

Entry point published unattached used on a published page password draft private scheduled trashed
video-shortcode route ok / ok ok / ok ok / ok ok / ok no / ok no / ok no / ok no / ok
preview page ok / ok ok / ok ok / ok ok / ok no / ok no / ok no / ok no / ok
embed page ok / ok ok / ok ok / ok ok / ok no / ok no / ok no / ok no / ok
gallery route ok / ok ok / ok ok / ok ok / ok no / no no / no no / no no / no
transcoding status ok / ok ok / ok ok / ok ok / ok no / ok no / ok no / ok no / ok
adTagURL (ad breaks) ok / ok ok / ok ok / ok ok / ok* no / ok no / ok no / ok no / ok
  • Password column: after the change to match WordPress (commit cabb90ce6, 23 Oct), the shortcode route, preview, embed, gallery and transcoding status were re-checked logged out on a second throwaway site: all show the video, and WordPress's media API shows it too. *The ad route uses the same check but was not re-run.
  • A published page with the GoDAM video block renders the player, and its adTagURL returns the ad breaks (also for the exception page).
  • Transcoding: 100 IDs returns 200 and 101 returns 400. Five reads in a row write nothing, and the status flips to transcoded after 15 seconds.
  • Video schema: printed on public pages only.
  • The new transcoding-checker.js was run in Node against the patched route with 131 IDs: two requests (100 + 31), all statuses delivered. Jest covers 250 IDs in 3 requests.
  • PHPUnit: 125 new tests in tests/php/MediaVisibilityTest.php and tests/php/MediaVisibilityShortcodeRouteTest.php; full suite OK (738 tests). phpcs, ESLint and bin/hook-check balance and coverage checks pass.

Effect on godam.io

Checked on a copy of godam.io's database (24 Sep 2026), read directly, without loading the site:

  • 227 videos: 85 unattached and 122 on published posts (unchanged by this PR), and 20 on draft posts (14 handbook entries, 6 pages).
  • 13 of those 20 are used on a published post. They keep working through the "used on a published post" rule. The usage index and the post content agree on all 13.
  • The other 7 are used on no published post, so the public routes and pages now treat them as missing, as WordPress does.

Worth knowing

  • The exception relies on the media usage index. On a site whose usage backfill (Tools > Media usage sync) hasn't finished, an exception video may be refused until it completes or the page is re-saved.
  • A video uploaded to a draft and used only in a block widget isn't covered by the exception. The widget's own player still plays, because it doesn't go through these routes. The filter can allow such videos.
  • Editors don't see draft-parent videos in the gallery listing; the listing matches what visitors see.
  • Videos transcoded before this change have no update time, so they skip the 95% wait.
  • Transcoding status requests with more than 100 IDs, or with ids that aren't an array, now get a 400.

QA:

  1. A video on a published post plays in the player, gallery, lightbox, embed page and preview, as before.
  2. Logged out, a video attached to a draft or private post is "not found" on the embed and preview pages and missing from the gallery.
  3. As an Editor, preview and embed your own unpublished media: works.
  4. A video uploaded while drafting post A and placed on published page B plays on B and appears in B's gallery.
  5. In the Media Library list view with more than 100 items per page, transcoding statuses keep updating.
  6. View the source of a password-protected post with a video: no VideoObject data.

Issue: rtCamp/godam-plugin-wp#67

@subodhr258 subodhr258 self-assigned this Oct 23, 2026
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

🔍 WordPress Plugin Check Report

⚠️ Status: Passed with warnings

📊 Report

🎯 Total Issues ❌ Errors ⚠️ Warnings
13 0 13

⚠️ Warnings (13)

📁 readme.txt (2 warnings)
📍 Line 🔖 Check 💬 Message
0 mismatched_plugin_name Plugin name "GoDAM - Organize WordPress Media Library & File Manager with Unlimited Folders for Images, Videos & more" is different from the name declared in plugin header "GoDAM".
0 trademarked_term The plugin name includes a restricted term. Your chosen plugin name - "GoDAM - Organize WordPress Media Library & File Manager with Unlimited Folders for Images, Videos & more" - contains the restricted term "wordpress" which cannot be used at all in your plugin name.
📁 assets/build/css/main.css (1 warning)
📍 Line 🔖 Check 💬 Message
0 EnqueuedStylesScope This style is being loaded in all contexts.
📁 assets/src/libs/analytics.min.js (5 warnings)
📍 Line 🔖 Check 💬 Message
0 EnqueuedScriptsScope This script is being loaded in all frontend contexts.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880 (with handle analytics-library) is loaded in the footer. Consider a defer or async script loading strategy instead.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880/2026/10/23/hello-world/ (with handle analytics-library) is loaded in the footer. Consider a defer or async script loading strategy instead.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880/sample-page/ (with handle analytics-library) is loaded in the footer. Consider a defer or async script loading strategy instead.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880/demo-attachment-post/ (with handle analytics-library) is loaded in the footer. Consider a defer or async script loading strategy instead.
📁 assets/build/js/main.min.js (5 warnings)
📍 Line 🔖 Check 💬 Message
0 EnqueuedScriptsScope This script is being loaded in all frontend contexts.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880 (with handle rtgodam-script) is loaded in the footer. Consider a defer or async script loading strategy instead.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880/2026/10/23/hello-world/ (with handle rtgodam-script) is loaded in the footer. Consider a defer or async script loading strategy instead.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880/sample-page/ (with handle rtgodam-script) is loaded in the footer. Consider a defer or async script loading strategy instead.
0 NonBlockingScripts.NoStrategy This script on http://localhost:8880/demo-attachment-post/ (with handle rtgodam-script) is loaded in the footer. Consider a defer or async script loading strategy instead.

🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check

The preview and embed pages, the video shortcode, ad tag and transcoding
status routes, and the video gallery listing now follow WordPress's own
media visibility instead of answering for any media ID.

Media is shown when it is unattached, or when the post it was uploaded to
is published (or has another public status) and has no password the
visitor has not entered. Users who can edit the media always see it, and
users who can read a private or draft parent, or edit a password-protected
one, see its media. Media used on a publicly viewable post counts as
public whichever post it was uploaded to, using the media usage index, so
a video uploaded while drafting one post keeps working in the player,
gallery, lightbox and embed of the published page that uses it. Media a
visitor may not see is treated like a missing ID. The result can be
adjusted with the new rtgodam_can_view_attachment filter.

- rtgodam_can_view_attachment() answers for one attachment; the gallery
  listing applies the same rule in SQL (rtgodam_public_media_query_clauses)
  so paging and counts stay correct.
- The transcoding status route takes at most 100 IDs per request and leaves
  out IDs the user may not see. Reading the status no longer writes: the
  short wait for a thumbnail after transcoding is based on the time of the
  last status update, stored when the status is set, instead of a counter
  incremented on every read. The media library requests statuses in batches
  of 100.
- The rtgodam_meta REST field on attachments returns the stored settings
  only to users who can write posts (for editor previews) or edit the
  attachment.
- Video schema is printed only for posts whose content is public: not
  drafts, private, scheduled or password-protected posts.
- Add unit tests for each of these.
@subodhr258
subodhr258 changed the base branch from develop to main October 23, 2026 06:21
@subodhr258
subodhr258 force-pushed the fix/public-media-visibility branch from 158f694 to 4c08086 Compare October 23, 2026 06:21
@subodhr258

Copy link
Copy Markdown
Collaborator Author

Tested together with the other five 2.5.1 PRs on a hosted test site connected to production GoDAM Central. Full table and all recordings: https://github.com/rtCamp/godam-plugin-wp/issues/68 (recordings are in the rtCamp Test media library; sign in to watch).

Tested commit 158f69464; the current head 95f518502 changes tests only.

  • Before, on 2.5.0: B1
  • Draft post (transcodes; hidden until published; hidden again when switched back to draft): T1
  • Private post: T2
  • Published post, control: T3
  • Unattached, then used in a private post, then attached to it: T4
  • Uploaded to a draft, used on a published page, then removed: T5
  • Central's site checks, including the transcoding-status route: T7

All passed. Transcoding is not affected: each video transcoded in 70 to 104 seconds, and Central's site checks pass 6 of 6.

GoDAM's public routes and pages now follow WordPress's media API for
media attached to a password-protected post: it is shown, the same as
media of any published post. The rest is unchanged: media of draft,
pending, private, scheduled and trashed posts stays hidden from visitors,
and media used on a public post still counts as public.

The video schema is still left out of a password-protected post, since
the post's own content is hidden until the password is entered.

@elifvish elifvish left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No issues found.

Verification

  • Head tested: cabb90ce63. PHPUnit on this PR's head: 737/737 OK.
  • All seven 2.5.1 PRs merged onto main (no conflicts): PHPUnit 915/915, Jest 690/690, build:prod OK.
  • Playwright API checks against that build on a local WordPress 7.1.3 site: 30/30 for this PR.
  • Not covered: Video SEO schema on a password-protected post with a real video block: fixtures had no rendered block; covered by code reading and unit tests; adTagURL route with ad breaks configured.

Screenshots and a recording of the local run are available on request.

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.

2 participants