{"id":180088,"date":"2024-02-26T10:05:37","date_gmt":"2024-02-26T10:05:37","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/blue-billywig\/"},"modified":"2026-04-24T09:15:46","modified_gmt":"2026-04-24T09:15:46","slug":"blue-billywig","status":"publish","type":"plugin","link":"https:\/\/es-pr.wordpress.org\/plugins\/blue-billywig\/","author":21052357,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"2.0.2","stable_tag":"2.0.2","tested":"6.9.4","requires":"4.7","requires_php":"8.1.0","requires_plugins":null,"header_name":"Blue Billywig","header_author":"Blue Billywig","header_description":"A plugin for managing video content","assets_banners_color":"ccc6bc","last_updated":"2026-04-24 09:15:46","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/www.bluebillywig.com\/","rating":0,"author_block_rating":0,"active_installs":10,"downloads":3123,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"bluebillywigplugin","date":"2024-02-26 10:09:45"},"1.0.1":{"tag":"1.0.1","author":"bluebillywigplugin","date":"2024-04-18 11:15:40"},"1.0.10":{"tag":"1.0.10","author":"bluebillywigplugin","date":"2024-09-24 08:18:09"},"1.0.11":{"tag":"1.0.11","author":"bluebillywigplugin","date":"2024-11-11 15:52:25"},"1.0.12":{"tag":"1.0.12","author":"bluebillywigplugin","date":"2024-11-25 13:34:19"},"1.0.13":{"tag":"1.0.13","author":"bluebillywigplugin","date":"2024-12-30 09:16:10"},"1.0.14":{"tag":"1.0.14","author":"bluebillywigplugin","date":"2025-07-14 09:52:23"},"1.0.15":{"tag":"1.0.15","author":"bluebillywigplugin","date":"2025-07-14 09:55:59"},"1.0.2":{"tag":"1.0.2","author":"bluebillywigplugin","date":"2024-12-30 09:12:01"},"1.0.3":{"tag":"1.0.3","author":"bluebillywigplugin","date":"2024-05-02 08:58:07"},"1.0.4":{"tag":"1.0.4","author":"bluebillywigplugin","date":"2024-07-11 08:31:40"},"1.0.5":{"tag":"1.0.5","author":"bluebillywigplugin","date":"2024-07-22 07:57:56"},"1.0.6":{"tag":"1.0.6","author":"bluebillywigplugin","date":"2024-07-25 08:49:28"},"1.0.7":{"tag":"1.0.7","author":"bluebillywigplugin","date":"2024-08-05 07:19:09"},"1.0.8":{"tag":"1.0.8","author":"bluebillywigplugin","date":"2024-09-06 07:35:28"},"1.0.9":{"tag":"1.0.9","author":"bluebillywigplugin","date":"2024-09-12 08:21:52"},"2.0.1":{"tag":"2.0.1","author":"bluebillywigplugin","date":"2026-04-22 11:40:41"},"2.0.2":{"tag":"2.0.2","author":"bluebillywigplugin","date":"2026-04-24 09:15:46"}},"upgrade_notice":{"2.0.2":"<p>Fixes the dashboard video analytics widget: it read SAPI responses at the wrong path and quietly rendered the &quot;no data&quot; empty state even on publications with real traffic. After upgrading, the widget now shows Views \/ Player Loads \/ Play Rate, Top 5 Videos, and the device breakdown. Also adds a one-click admin notice when the plugin is installed but has no API credentials yet, and a red error panel inside the widget when a SAPI call fails (instead of the misleading empty state).<\/p>","2.0.1":"<p>This is the first 2.x release shipped via wordpress.org (2.0.0 was distributed via GitHub only). Upgrading from 1.x is a MAJOR update with breaking changes: requires PHP 8.1+, replaces the upload flow with direct browser-to-storage uploads, removes the blue_billywig_progress_list filter, and REST endpoints now require authentication. Read the 2.0 migration guide in USER-GUIDE.md before updating in production. 2.0.1 itself adds a fail-closed fix to the content-gate recursion cap, observability for gate-error and JWT-pepper persistence failures, a Solr-fq validation parity fix on a library AJAX endpoint, and regression tests.<\/p>","2.0.0":"<p>Major update with breaking changes. Direct browser-to-storage uploads via Uppy (no more PHP upload limits), Gutenberg blocks with SEO, oEmbed support, content protection, video analytics dashboard, folder browsing, and more. Requires PHP 8.1+. The blue_billywig_progress_list filter has been removed \u2014 see release notes if you used it in custom code.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3041421,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3041423,"resolution":"256x256","location":"assets","locale":""},"icon.svg":{"filename":"icon.svg","revision":3041424,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3041420,"resolution":"1544x500","location":"assets","locale":""},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3041418,"resolution":"772x250","location":"assets","locale":""}},"assets_blueprints":{},"all_blocks":{"bluebillywig\/embed":{"name":"bluebillywig\/embed","title":"Blue Billywig Clip"},"bluebillywig\/channel":{"name":"bluebillywig\/channel","title":"Blue Billywig Channel"},"bluebillywig\/shorts":{"name":"bluebillywig\/shorts","title":"Blue Billywig Shorts"}},"tagged_versions":["1.0.0","1.0.1","1.0.10","1.0.11","1.0.12","1.0.13","1.0.14","1.0.15","1.0.2","1.0.3","1.0.4","1.0.5","1.0.6","1.0.7","1.0.8","1.0.9","2.0.1","2.0.2"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3041425,"resolution":"1","location":"assets","locale":""}},"screenshots":[],"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[224718,224717,224716,222],"plugin_category":[50],"plugin_contributors":[224719],"plugin_business_model":[],"class_list":["post-180088","plugin","type-plugin","status-publish","hentry","plugin_tags-billywig","plugin_tags-blue-billywig","plugin_tags-bluebillywig","plugin_tags-video","plugin_category-media","plugin_contributors-bluebillywig","plugin_committers-bluebillywigplugin"],"banners":{"banner":"https:\/\/ps.w.org\/blue-billywig\/assets\/banner-772x250.png?rev=3041418","banner_2x":"https:\/\/ps.w.org\/blue-billywig\/assets\/banner-1544x500.png?rev=3041420","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/blue-billywig\/assets\/icon.svg?rev=3041424","icon":"https:\/\/ps.w.org\/blue-billywig\/assets\/icon.svg?rev=3041424","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/blue-billywig\/assets\/screenshot-1.png?rev=3041425","caption":""}],"raw_content":"<!--section=description-->\n<p>The Blue Billywig plugin enhances Blue Billywig's capabilities by integrating with WordPress. This plugin allows users to seamlessly upload media directly to their Blue Billywig publication.<\/p>\n\n<p><strong>Documentation:<\/strong> See USER-GUIDE.md in the plugin directory for a complete walkthrough of all features.<\/p>\n\n<h3>Third-Party Service Integration<\/h3>\n\n<p>This plugin relies on the Blue Billywig Online Video Platform to provide video uploading capabilities. By using this plugin, you acknowledge and agree to the following:<\/p>\n\n<ul>\n<li>The plugin sends data to <a href=\"https:\/\/bbvms.com\/\">bbvms.com<\/a> and <a href=\"https:\/\/www.bluebillywig.com\/\">bluebillywig.com<\/a> for video management tasks.<\/li>\n<li>Your usage of Blue Billywig is subject to their <a href=\"https:\/\/www.bluebillywig.com\/privacy-statement\/\">Privacy Policy<\/a>.<\/li>\n<\/ul>\n\n<h3>Privacy &amp; GDPR<\/h3>\n\n<p><strong>What data is transmitted to Blue Billywig from site visitors?<\/strong><\/p>\n\n<p>Every page that embeds a Blue Billywig video loads the player from <code>{publication}.bbvms.com<\/code>. When the script runs, the visitor's IP address, User-Agent, Referer and page URL are transmitted to Blue Billywig so the player can fetch the clip, apply geo\/language rules, and record analytics.<\/p>\n\n<p><strong>Consent integration (GDPR \/ ePrivacy \/ TTDSG).<\/strong><\/p>\n\n<p>The plugin exposes a WordPress filter <code>bluebillywig_consent_granted<\/code> so consent-management plugins (Complianz, Cookiebot, Iubenda, Osano, \u2026) can defer loading the player until the visitor opts in:<\/p>\n\n<pre><code>add_filter( 'bluebillywig_consent_granted', function() { return your_cmp_has_video_consent(); } );\n<\/code><\/pre>\n\n<p>When this filter returns <code>false<\/code>, BB embed blocks, channel blocks, Shorts blocks, shortcodes, and oEmbed all render a neutral placeholder explaining that loading will transmit data to bbvms.com. No IP\/UA is shipped to Blue Billywig until consent is granted (or until the visitor reloads after accepting).<\/p>\n\n<p><strong>Cookies and local storage.<\/strong><\/p>\n\n<ul>\n<li>The plugin itself does not set any cookies or write to local storage from admin pages.<\/li>\n<li>On the frontend, the CTA email-capture overlay (when enabled by the editor) writes <code>bbtl_{clipId}<\/code> to the visitor's <code>localStorage<\/code> after a successful submit, so the form does not re-ask an engaged visitor. This key only carries the submitted email and a timestamp.<\/li>\n<li>The Blue Billywig player itself may set first-party cookies on the <code>.bbvms.com<\/code> domain for playback\/analytics. See Blue Billywig's privacy statement for details.<\/li>\n<\/ul>\n\n<p><strong>CTA email capture \u2014 consent.<\/strong><\/p>\n\n<p>The CTA editor can optionally include an email-capture form. The plugin requires an explicit consent checkbox on the form and rejects non-<code>https<\/code> submit endpoints. Captured emails are sent to the customer-configured endpoint (if any); Blue Billywig's own backend does not receive or store these emails.<\/p>\n\n<p><strong>Content protection JWT.<\/strong><\/p>\n\n<p>When you enable JWT-based content protection and a logged-in WordPress user requests a protected clip, a short-lived token (\u2264 7200s, clamped) is minted. The user-ID claim in the token is an HMAC of the WordPress user ID (never the raw ID) using <code>wp_salt('auth')<\/code>. Pages carrying a JWT emit <code>Cache-Control: private, no-store<\/code> to keep shared caches from serving one user's token to another.<\/p>\n\n<p><strong>Admin-side third-party code.<\/strong><\/p>\n\n<p>On plugin admin pages, the Uppy uploader library is bundled locally (<code>admin\/assets\/vendor\/uppy\/<\/code>) \u2014 no request to <code>releases.transloadit.com<\/code> on every admin page load.<\/p>\n\n<p><strong>Uninstall.<\/strong><\/p>\n\n<p>Uninstalling the plugin deletes every <code>blue-billywig-*<\/code> option (including stored API keys and the content-protection shared secret) and every <code>bb_*<\/code> transient. A reinstall starts from a clean slate.<\/p>\n\n<h3>Translators<\/h3>\n\n<p>The plugin ships with starter translations for German, French, Swedish, Danish, Norwegian Bokm\u00e5l, Finnish, and Dutch (in <code>\/languages\/<\/code>). They were generated automatically and cover every string, but they have not been reviewed by native speakers.<\/p>\n\n<p><strong>Please help us improve them.<\/strong> Once the plugin is listed on wordpress.org, any translation you contribute at <a href=\"https:\/\/translate.wordpress.org\/projects\/wp-plugins\/blue-billywig\/\">translate.wordpress.org\/projects\/wp-plugins\/blue-billywig<\/a> automatically rolls out to every site running that locale \u2014 no plugin release required. If you already translate other WordPress plugins, the process is the same; if you don't, it takes about five minutes to sign up and suggest a correction.<\/p>\n\n<p><strong>Adding a new language.<\/strong><\/p>\n\n<p>Once the plugin is listed on translate.wordpress.org, that is the preferred home for every language \u2014 translators suggest a locale and the site creates the project on first approval. If you want to kick-start a language ahead of that: copy <code>languages\/blue-billywig.pot<\/code> to <code>languages\/blue-billywig-&lt;locale&gt;.po<\/code> (e.g. <code>blue-billywig-it_IT.po<\/code> for Italian), translate the <code>msgstr<\/code> values, run <code>msgfmt blue-billywig-&lt;locale&gt;.po -o blue-billywig-&lt;locale&gt;.mo<\/code>, and send the files to <a href=\"https:\/\/support.bluebillywig.com\/\">support.bluebillywig.com<\/a>. We'll bundle them in the next release so translate.wordpress.org starts with a baseline.<\/p>\n\n<!--section=changelog-->\n<h4>2.0.2<\/h4>\n\n<ul>\n<li>Fix: Dashboard video analytics widget was reading SAPI responses at the wrong path (<code>['count']<\/code> \/ <code>['facets']<\/code> instead of <code>['body']['total']<\/code> \/ <code>['body']['facets']<\/code>, and facet entries use <code>'value'<\/code>, not <code>'val'<\/code>). <code>$total_views<\/code> and <code>$total_inits<\/code> always stayed 0, so the widget always rendered its \"No video views recorded\" empty state \u2014 even on publications with plenty of traffic. After upgrade the widget shows real data.<\/li>\n<li>UX: New <code>admin_notices<\/code> banner warns administrators when the plugin is installed but has no API credentials yet, with a one-click link to the settings page. Gated on <code>manage_options<\/code>, suppressed on the settings page itself, auto-clears as soon as credentials are saved.<\/li>\n<li>UX: When a SAPI analytics call fails the widget now renders a red error panel naming the failed sections and writes a structured <code>error_log<\/code> entry, instead of silently falling back to the empty-state copy. Makes \"API outage\" visually distinct from \"publication has no traffic\".<\/li>\n<li>Observability: On cache skip (at least one of the four analytics calls errored) the plugin now writes a single summary <code>error_log<\/code> line listing which section(s) failed, so transient SAPI outages surface in <code>debug.log<\/code> without waiting for a dashboard render.<\/li>\n<li>Performance: Dashboard widget transient TTL reduced from 15 to 5 minutes for slightly fresher stats; cache still busts immediately on credential changes via <code>SapiClient::clearCache()<\/code>, and errored responses are still never cached.<\/li>\n<li>Tests: +34 assertions in <code>AnalyzeWidgetDataTest<\/code> locking the SAPI envelope contract against the exact response-shape drift that caused the 2.0.1 regression.<\/li>\n<\/ul>\n\n<h4>2.0.1<\/h4>\n\n<ul>\n<li>Security: ContentGate::injectJwt now fails closed at the depth cap (previously returned un-gated content, so a crafted nested-base64 payload could bypass the gate).<\/li>\n<li>Security: Library AJAX endpoint now validates <code>bb_folder<\/code> and <code>bb-sourcetype<\/code> against the same regex the REST <code>\/search_media_clips<\/code> route uses (closes a Solr-fq injection surface the REST path had already closed).<\/li>\n<li>Hardening: <code>bulk_action<\/code> now verifies the CSRF nonce before the capability check (defence in depth).<\/li>\n<li>Observability: Content gate logs each distinct failure reason (SAPI disconnected \/ SAPI error \/ 404 \/ missing shared secret) and records a rolling one-hour tally. A new admin-notices banner surfaces the tally so operators can tell \"outage\" from \"misconfig\" instead of all paths rendering the same viewer message.<\/li>\n<li>Observability: JWT pepper persistence failure now triggers a persistent <code>notice-error<\/code> admin banner (<code>manage_options<\/code>-gated); previously every gated video silently failed verification with no signal.<\/li>\n<li>UX: Library AJAX endpoints (<code>load_library_videos<\/code>, <code>load_library_playlists<\/code>) surface the SAPI <code>Error<\/code> message via <code>wp_send_json_error<\/code> 502 instead of the prior generic 200 + \"No data\". Auth failures are now distinguishable from legitimately-empty libraries.<\/li>\n<li>Compat: Replaced <code>array_filter(..., 'strlen')<\/code> in <code>CtaTranslator<\/code> with a closure (PHP 8.1 deprecation, removed in 9).<\/li>\n<li>Docs: Corrected inaccurate comments in <code>CtaTranslator<\/code> (widget types) and subtitle upload (single-POST behaviour).<\/li>\n<li>Tests: +10 assertions via <code>ContentGateFailsClosedTest<\/code>, <code>UninstallAllowlistTest<\/code>, <code>SapiClientInvalidateClipCppCacheTest<\/code>; updated <code>ContentGateInjectJwtTest::test_depth_cap_fails_closed<\/code> to lock the fail-closed invariant.<\/li>\n<\/ul>\n\n<h4>2.0.0<\/h4>\n\n<ul>\n<li>New: Direct browser-to-storage upload via Uppy (no PHP upload limits)<\/li>\n<li>New: Gutenberg blocks with server-side rendering and JSON-LD SEO<\/li>\n<li>New: Channel embed Gutenberg block with channel selector<\/li>\n<li>New: oEmbed \u2014 paste BB video URLs directly to embed<\/li>\n<li>New: Video XML sitemap integration<\/li>\n<li>New: AI transcript display below videos (SEO-indexed)<\/li>\n<li>New: Video chapters with clickable timestamps (opt-in)<\/li>\n<li>New: Interactive video overlay support<\/li>\n<li>New: Folder tree browsing in library and media picker<\/li>\n<li>New: Video analytics dashboard widget<\/li>\n<li>New: Inline metadata editing in Media Library<\/li>\n<li>New: JWT-based content protection via WordPress roles<\/li>\n<li>New: Test Connection button on settings page<\/li>\n<li>Security: All AJAX handlers verify capabilities + nonces<\/li>\n<li>Security: Output escaping throughout, query injection fixes<\/li>\n<li>Performance: SAPI client singleton with response caching<\/li>\n<li>Compat: Requires PHP 8.1+, tested up to WordPress 6.9<\/li>\n<li>Breaking: blue_billywig_progress_list filter removed; use SapiClient class<\/li>\n<\/ul>\n\n<h4>1.0.15<\/h4>\n\n<ul>\n<li>Previous release.<\/li>\n<\/ul>","raw_excerpt":"The Blue Billywig plugin enhances Blue Billywig&#039;s capabilities by integrating with WordPress. This plugin allows users to seamlessly upload media &hellip;","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/180088","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=180088"}],"author":[{"embeddable":true,"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/bluebillywigplugin"}],"wp:attachment":[{"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=180088"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=180088"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=180088"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=180088"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=180088"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/es-pr.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=180088"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}