Repository navigation
Sync main to develop after v2.3.1 release - #2163
Conversation
* Fix: Refresh What's New release post cache on every plugin update Delete the rtgodam_release_data transient on every version bump, patch releases included, so sites that cached an older release post fetch the current one the next time What's New opens. Patch updates still don't redirect to What's New. Refs rtCamp/godam-plugin-wp#46 * Release prep v2.3.1: version bump and changelog * Update POT reference for class-update.php line shift * fix(analytics): send the media's job id with layer events Both buffered layer-event flushes (the player bundle's in analytics.js and the image-page runtime's in layer-analytics-runtime.js) sent `jobId: ''` for any event keyed by the WordPress attachment id, which is every hotspot, CTA, form, poll and Woo layer event on a WordPress video or image. The page load event already sends the element's `data-job_id`. They now read it from the same element the flush already finds for `data-block-source`. The image frame had no job id to read, so render.php now puts the image's job id on `.godam-image__frame` as `data-job_id`, from rtgodam_get_job_id_by_attachment_id(). GoDAM for Woo's in-image add reads that attribute from the same frame for its Assisted touch and order stamp. Events stored without a job id are later rewritten by GoDAM Core's job-id backfill, and summaries keyed on job_id have to follow that rewrite (rtCamp/godam-analytics#344). Sending it up front leaves nothing to rewrite. An empty `data-job_id` still sends no job_id, as before. * fix(analytics): say revenue is after discounts, excluding tax, shipping and fees The Revenue card and the Top Products "Revenue" column tooltips said only "before refunds". The figure is the WooCommerce order line total (WC_Order_Item_Product::get_total(), "Line total (after discounts)"), so coupons are already taken off and tax, shipping and fees are not in it. A merchant comparing it with their order totals saw a lower number with no reason given. Both tooltips now say so, matching the Revenue Analytics docs page. The RevenueCard test that checked the "excluding N orders in other currencies" line was absent by asserting the card contains no "excluding" at all now matches that line's own wording, since the tooltip says "excluding tax". New tests pin the wording in both tooltips. POT regenerated. * fix(analytics): explain grouped and external products' empty figures in Top Products A grouped product is never added to the cart: WooCommerce adds the products it lists, and with rtCamp/godam-for-woo#223 those products get the credit. An external product is bought on another site. Either way its Add to Cart and Revenue stay empty, and the in-video hint said grouped and external products convert on the product page, which is true of neither. The proxy now sends each product's WooCommerce type. The table greys a grouped or external product's adds and revenue with a hint that says why, and the in-video hint gives each type its own reason. A product with adds but no times shown in the date range (bought from a grouped product's page, added after a Reel Pop, or clicked before the range) showed an add-to-cart rate of 0.0%, which reads as "shown, and nobody added it". It now shows "-" with a hint. * Use the site's own origin for analytics and engagement reads Analytics events are recorded under the visitor's window.location.origin. The analytics and engagement read routes now send this site's origin, built on the server from home_url() by the new rtgodam_get_site_origin(), instead of the site_url sent with the REST request. The now unused site_url argument is removed from those routes; clients that still send it are unaffected. Adds SiteOriginTest, covering the helper and every read that forwards a site URL. * Regenerate godam.pot for moved line references * Align analytics route permissions with the screens and with WooCommerce reports Dashboard routes now ask for edit_pages, the capability the Dashboard menu needs, instead of upload_files. dashboard-metrics, dashboard-history, top-videos, top-products, placement-funnels, revenue-summary and video-funnel move; fetch, history and layer-analytics stay on upload_files for the Analytics page and the Video Editor. Figures that come from orders (revenue, order counts, purchases, Video-to-Purchase, the funnels' Purchase step and per-hotspot revenue) now follow WooCommerce's report permission, view_woocommerce_reports, which WooCommerce grants to shop managers and administrators. The routes leave those fields out of their responses for everyone else, so they cannot be read through the route. Views, plays, clicks and add-to-carts are unchanged. The Dashboard and Analytics pages get a canViewRevenue flag and leave out the Revenue card, Video-to-Purchase, revenue tips, the funnels' Purchase step, the Top Products revenue column (and its CSV columns) and per-hotspot revenue. Without the Purchase step the Purchase Funnel card reads as a Cart Funnel. * Hide the GA4 widget's purchase count from users who cannot see order data The Dashboard's GA4 widget shows how many Purchase events were prepared, a count that comes from orders. It now follows the same rule as the other order figures: only users with WooCommerce's report permission see it. Everyone else still sees the Add to Cart count and the connection status. * Fix the POT header bug-report URL so it matches CI's build make-pot took the plugin slug from the worktree folder name, so the header read support/plugin/analytics-route-permissions instead of support/plugin/godam. Regenerated with the slug set; only that header line changes. * Editors see video data only: store data needs WooCommerce's report permission Everything that comes from the store (products, add-to-carts, Video-to-Cart, orders, purchases, revenue) now follows view_woocommerce_reports, which WooCommerce grants to shop managers and administrators. Editors and authors get no WooCommerce or Products menu, so they see video data only. Routes that are all store data (top-products, revenue-summary, placement-funnels, video-funnel) need edit_pages and view_woocommerce_reports and answer 403 otherwise. Routes that mix video and store data (dashboard-metrics, fetch, layer-analytics) strip the store fields for everyone else: revenue, orders, purchases, add-to-carts, Video-to-Cart, the funnel, the add-to-cart rows of the per-layer counters and per-hotspot revenue. Views, plays, watch time and hotspot clicks stay. The screens hide the whole store section instead of trimming it: the Top Products table (editors land on Top Videos), both funnels, the Revenue card, Video-to-Cart, Video-to-Purchase, the GA4 box, the layer funnel's Added to Cart bar and the layer panel's revenue. The localized flag is now canViewStoreData. This replaces the earlier column-by-column hiding, so the funnel, Top Products and GA4 widget components are back to their develop versions. * Add a filter for the site origin used by analytics reads home_url() and the address visitors load the site from can differ, for example behind a proxy that ends TLS without telling WordPress, or when a site answers on several domains. rtgodam_site_origin lets those sites return the origin their visitors' browsers report. Values that are not a bare scheme://host[:port] are ignored. The docblock states the assumption. * fix(analytics): name variable products explicitly in the in-video hint The hint fell through to the variable-product sentence for any restricted product type other than grouped or external. It now checks for 'variable' and gives any other product the proxy marks as not addable in a video, or a row from before the proxy sent product_type, a neutral sentence that says only what the flag proves. * fix(analytics): send the store's UTC offset with the funnel reads The analytics service counts the funnel, Video-to-Cart, Video-to-Purchase and the placement funnels on the UTC day, while the Revenue card puts an order on the store's day. The proxy now adds the store's current offset in minutes (from the WordPress timezone setting) to the four routes that serve those figures, so the service counts plays, adds and orders on the store's own day. The per-video read, the dashboard metrics, the placement funnels and the video funnel each add it with one line; the other routes are unchanged. A service that does not know the parameter ignores it. * Keep commenter details out of the public engagement response The engagement activities route returns each comment's author email so the player can decide whether to show Delete and Edit. The site now works out whether a comment belongs to the viewer from the WordPress session and returns an `is_own` flag instead; the display name and avatar are unchanged. Editing or deleting a comment now checks, against a fresh copy from GoDAM Central, that the signed-in user wrote it, whatever id or email the browser sends. The player reads `is_own` for its controls and shows the server's message if a delete is refused. Tests cover the route response for a logged-out visitor, the owner, another user and a guest, the cache, and refused edits and deletes, plus the comment controls in the player. * chore(i18n): update godam.pot line references for class-analytics.php The new offset helper shifts the source lines of the strings below it. No string changed. * fix(analytics): keep the "never added to the cart" hint to rows with no adds The in-video hint depended only on the not-addable-in-video flag, so a grouped or external row that does have adds (older data, or a product whose type changed after it sold) said it was never added to the cart beside a non-zero count. The grouped and external sentences now show only when the row has no adds; otherwise it gets the neutral in-video sentence. * Look through all of a video's comments when checking who wrote one The check that runs before a comment is edited or deleted asked Central for its default window, the newest 20 comments, so a comment that had moved out of that window since the page loaded was refused. It now reads the thread in pages of 100 until it finds the comment or reaches the end. The public list still uses Central's default window. The test stand-in for wp_timezone() now reads the zone a test sets, so it can share a run with another test file's stand-in for the same function. * Answer with an allow-list of video fields for users without store access The three routes that mix video and store data (dashboard-metrics, fetch and layer-analytics) removed a list of store fields from their responses. That fails open: a store field the analytics service adds later would reach Editors until someone added it to the list. They now keep only the fields listed as video data, so a new field stays hidden from Editors and Authors until it is classified. The per-layer counter rows are kept only for video actions (viewed, clicked, hovered, skipped, submitted, voted), which also drops a row for an action added later. Shop managers and administrators still get the whole response. Tests: a field added to each route's response is hidden from Editors and Authors and reaches a Shop manager, a counter row for an unclassified action is dropped, and no allow-list may name a store field. * Keep the site origin exact, and refuse analytics reads without one - Origins from the rtgodam_site_origin filter are lowercased and rejected when they carry userinfo, so they match what browsers report. - The ten analytics reads behind upload_files take the request's site_url only when it is on the same host and port as home_url() and the scheme is the only difference (a proxy that ends TLS). Anything else, and the public views route, keeps the site's own origin. - When the site has no origin the reads return a site_origin_unavailable error before calling the service, which reads an empty site_url as "all sites on the account". - The is_user_logged_in test stub answers from $GLOBALS['rtgodam_stub']['user'] and reports a logged-out visitor by default, so it does not shadow other stubs that need a logged-in user. * Pin the conversion counters as visible to Editors and Authors The total_conversion figure on top-videos and the layer counters conversion_rate, converting_sessions, unique_converting_sessions and layer_converting_sessions stay visible on purpose. They count sessions that acted on a video and carry no products, amounts or orders, and they are how an Editor sees how the form and call-to-action layers they build perform. A total that counts an add-to-cart once can include some. That is accepted. This test-only change makes the decision explicit: a later edit to the video allow-lists can no longer hide these fields by accident. * Document what can_view_store_data() means when WooCommerce is off The capability lives on the roles, not in WooCommerce's code. Where WooCommerce was never active, or removed its data on uninstall, nobody holds it, so even an Administrator gets video data only from the mixed routes and a 403 from the store routes. Deactivating WooCommerce leaves the capability on the roles. The same docblock still said the mixed routes strip the store fields; they answer with the VIDEO_DATA_* allow-lists since the previous round, so the wording now says that. Documentation only; the POT changes only in source line numbers. * Answer the ownership check from the cached comments, and handle a refused edit The check that runs before a comment is edited or deleted now looks in the comments the site already holds first. Who wrote a comment never changes, so a comment found there is answered with no call to Central. Only a comment the cache does not hold is looked for on Central, and that lookup stops after five pages of 100, so an unknown comment ID costs at most the list read and five pages. The player only shows the newest 20 comments, so a comment someone is acting on has moved down by a few places, not by hundreds. Saving an edit now handles a refusal the way deleting already does: the form leaves the sending state, the server's message goes to the store's error action, and nothing is left unhandled. * Validate origins strictly and convert internationalised hosts The origin check accepted http://:80, http://ex..com and http://host:abc, and passed unicode hosts through. It now requires a hostname made of valid labels, an IPv4 address or a bracketed IPv6 address, and a port from 1 to 65535. Like a browser's window.location.origin, the result is lowercase, has an internationalised host as punycode (idn_to_ascii, when intl is available) and has no default port. The origin built from home_url() goes through the same check as the filter result. * Make the test stand-ins for home_url() and the API base agree with the other stub file tests/stubs/engagement-functions.php and tests/stubs/site-functions.php both define home_url() and RTGODAM_API_BASE behind function_exists/defined guards, so whichever file loads first wins. The home_url() here ignored the value a test sets. It now reads the same key and default as the other file, and the API base constant has the same value in both, so the load order no longer changes any result. EngagementCommentPrivacyTest sets its own home_url instead of relying on the default. * Match counter rows on the action column only The per-layer counter rows for an Editor or Author were kept when any column held a video action, so a layer named "viewed" kept its added_to_cart row. Check only the action column (index 1 of layer_type_stats rows, index 3 of layer_details rows) and drop a row that is too short to have one. Also say in the docblock that the conversion counters include add-to-cart sessions on WooCommerce layers and stay visible on purpose. * Add the 2.3.1 changelog entries for the combined release One line each for the user-visible changes in #2147 to #2153, next to the What's New fix, and the release date is now September 30, 2026. * Ask for GoDAM for Woo 2.2.1 or newer GoDAM 2.3.1 shows the "update the add-on" notice for GoDAM for Woo older than 2.2.1 (the minimum was 2.0.0). It is a notice only and switches nothing off. * chore(i18n): regenerate godam.pot for qa/plugin-followups Built from a clean assets/build (npm ci, npm run build:prod), then both make-pot passes with --slug=godam so the header matches develop's (only Project-Id-Version differs, 2.3.1 from #2146). * Set the 2.3.1 release date to October 5, 2026 and replace @SInCE n.e.x.t with 2.3.1 - CHANGELOG.md and readme.txt: v2.3.1 is dated October 5, 2026. readme.txt keeps the newest three entries (2.3.1, 2.3.0, 2.2.4). - inc/helpers/custom-functions.php: the four @SInCE n.e.x.t placeholders are now @SInCE 2.3.1. None are left in the tree. * Clear the Plugin Check warnings: ship composer.json, mark the gallery block's local variable Plugin Check flagged the vendor folder shipping without composer.json, and $inner_block_video_ids in the gallery-v2 render.php as a non-prefixed global. render.php runs inside WP_Block::render(), so the variable is local, and the shared gallery template reads it by this name. * Gravity Forms recorder: stop counting one recording as two files (#2158) * Gravity Forms recorder: stop counting one recording as two files Gravity Forms 2.9.18+ treats the GoDAM Record field as a file upload: it saves the recording to its temp folder on a page change or a failed submit and counts that saved copy together with any file sent again. The recorder restores the recording after every page load and put it back into the file input, so the next submit failed with "Number of files (2) exceeds limit (1)", one more per page on longer forms. - Recorder: when Gravity Forms already saved the recording, show the restored preview but do not send the file again; removing the recording also drops the saved copy, so a new recording replaces it. - Field: a recording sent in the current request replaces any saved copy, so the field always counts one file. * Gravity Forms recorder: guard the submission-files override on Gravity Forms before 2.9.18 The override makes get_submission_files() exist on the GoDAM Record field even where Gravity Forms has no such method, so a plugin that checks method_exists() before calling it would hit the missing parent method. Return empty lists there. Checks the parent class by name, since get_parent_class() without an argument is deprecated in PHP 8.3. * Set the 2.3.1 release date to October 6, 2026, add the Gravity Forms recorder fix to the changelog Replaces the @SInCE n.e.x.t that #2158 brought in with 2.3.1 and regenerates godam.pot for the line references #2158 moved. --------- Co-authored-by: Vishal Kumar <vishnshiv3@gmail.com>
There was a problem hiding this comment.
Copilot wasn't able to review any files in this pull request. Check if the Files changed in this pull request are included in default exclusions.
🔍 WordPress Plugin Check Report
📊 Report
|
| 📍 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/06/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/06/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
elifvish
left a comment
There was a problem hiding this comment.
Back-sync looks clean. No file changes (0 files in the diff), and the branch is a single merge commit (6ea4089) bringing the #2161 release merge onto develop. #2161 is merged into main as the PR says.
Security: nothing to flag, since no code changes.
Correctness: the tree is identical to develop; only the merge ancestry changes. develop is currently 1 commit ahead of this branch, so GitHub may need a refresh, but the PR is MERGEABLE.
Other: as the description says, please merge with a merge commit, not squash, or main will stay diverged from develop.
Consumers: none affected.
Verification
Back-sync after the v2.3.1 release (rtCamp/godam-plugin-wp#46): brings the develop → main release merge (#2161) back onto
develop.Clean alignment: 1 merge commit, no file changes. Merge with a merge commit, not squash.