Hooks and Filters
All hooks are in the mediashield namespace and fire from the free plugin core. This page documents the actions and filters available in version 1.3.0. Pro adds its own on top; those are listed in the Pro reference.
Actions
Fires after the core plugin is fully initialized and all hooks are registered. Use this to initialize any code that depends on MediaShield being ready.
add_action( 'mediashield_loaded', function() {
// Safe to use MediaShield APIs here.
} );
Fires when a new watch session is created, for logged-in viewers and guests alike.
Parameters: $session_id (int), $video_id (int), $user_id (int - 0 for guests), $ip (string)
add_action( 'mediashield_session_started', function( $session_id, $video_id, $user_id, $ip ) {
// Log to external analytics, fire a webhook, etc.
}, 10, 4 );
Fires when a watch session is finalized.
Parameters: $session_id (int), $video_id (int), $user_id (int)
Fires when a user tries to start a stream beyond their allowed concurrent limit. Never fires for guests, who are not subject to the limit.
Parameters: $user_id (int), $video_id (int), $active_count (int), $max (int)
Fires when all sessions for a user are revoked (POST /session/revoke-user).
Parameters: $user_id (int), $count (int - number of sessions revoked)
Fires when any milestone percentage is reached for a user and video. Fires once per user per video per threshold.
Parameters: $user_id (int), $video_id (int), $pct (int), $session_id (int)
add_action( 'mediashield_milestone_reached', function( $user_id, $video_id, $pct, $session_id ) {
if ( 100 === $pct ) {
// Grant a certificate, update LMS progress, etc.
}
}, 10, 4 );
Fires for a specific milestone percentage. mediashield_milestone_25, _50, _75, and _100 always exist; a video with milestone tags enabled at other percentages (10% is offered in the admin) gets those too, and mediashield_milestone_thresholds can add any value.
Parameters: $user_id (int), $video_id (int)
add_action( 'mediashield_milestone_100', function( $user_id, $video_id ) {
learndash_process_mark_complete( $user_id, $video_id );
}, 10, 2 );
Since 1.0.1. Fires just before an upload driver runs.
Parameters: $driver (string), $file_path (string), $options (array)
Fires when an upload finishes successfully.
Parameters: $video_id (int), $driver (string), $result (array)
Since 1.0.1. Fires when an upload driver returns an error.
Parameters: $driver (string), $error (string), $options (array)
Since 1.1.0. Fires immediately before the player container HTML is emitted. Use to enqueue per-video assets or print HTML above the player.
Parameters: $video_id (int)
Since 1.1.0. Fires immediately after the player HTML is built and the mediashield_player_html filter has run.
Parameters: $video_id (int)
Fires while rendering a self-hosted or Bunny player, to flag that adaptive-streaming support may be needed. In free this is what causes the bundled HLS library to be enqueued. Despite the name, free does not load Shaka Player.
Parameters: none
Since 1.1.0. Fires when the devtools beacon receives a detection event from the browser. Rate limited to one event per user per hour per IP.
Parameters: $context (array with keys: user_id, ip, url, strategy, ua, screen, at)
strategy is size_delta or debugger_timing. at is a UTC MySQL timestamp.
Fires before MediaShield's GDPR eraser deletes or anonymizes rows for a given email. Use to roll your own removals into the GDPR receipt.
Parameters: $email (string), $user (WP_User or false), $page (int), $counters (stdClass, passed by reference)
Filters
The primary access control gate. Return the $result array unchanged to allow access. Return an array with allowed => false and a reason string to deny.
Note that free core's own checks - the login gate, the per-video role, and the domain whitelist - run before this filter, not through it. A denial from any of them short-circuits and the filter never runs.
Parameters: $result (array {allowed: bool, reason: string}), $video_id (int), $user_id (int)
// Restrict to active subscribers.
add_filter( 'mediashield_can_watch', function( $result, $video_id, $user_id ) {
if ( ! user_has_active_subscription( $user_id ) ) {
return array(
'allowed' => false,
'reason' => 'An active subscription is required.',
);
}
return $result;
}, 10, 3 );
Pro attaches its own gates at priority 20 (role re-check) and 25 (LMS enrollment). Pick a priority outside that range, or be ready for a decision one of them has already made.
Customize the watermark configuration handed to the browser when a session starts.
Parameters: $config (array with keys enabled, opacity, color, swap_interval, text, ip), $video_id (int), $user_id (int)
text is the display name (or "Guest"); ip is appended by the client on players 640 px wide or wider. Pro uses this filter to compose its 7-field text and adds font_size and show_badge.
Since 1.3.0. Filter the protection levels offered on the video edit screen.
Parameters: $levels (array, slug => label), $post (WP_Post), $selected (string)
Adding a level only makes it selectable and storable. Whatever it is meant to do still has to be implemented, typically through mediashield_player_type. Pro uses this to add drm.
Register custom upload driver classes. Each class must implement MediaShield\Upload\Drivers\DriverInterface.
Parameters: $drivers (array, driver name => class name)
add_filter( 'mediashield_upload_drivers', function( $drivers ) {
$drivers['s3'] = MyPlugin\Upload\S3Driver::class;
return $drivers;
} );
Since 1.3.0. Filter the on-disk filename for a self-hosted upload. Stored names carry a random token so a file path is impractical to guess; return the plain sanitised name to opt out.
Parameters: $obscured (string), $original_name (string)
Override the player type for a video. Free renders standard for every video; Pro uses drm for DRM playback.
Parameters: $type (string), $video_id (int)
Since 1.2.0. Supply or override the direct stream URL for a video, which is what lets MediaShield play it in a real <video> element instead of a provider iframe. Pro uses it to build Bunny HLS playlist URLs for videos imported before the URL was recorded.
Parameters: $stream_url (string), $video_id (int), $platform (string), $platform_video_id (string)
Customize which completion percentages trigger milestones. Percentages enabled in a video's Milestone Tags box are merged in on top of whatever this returns.
Parameters: $thresholds (array of ints, default [25, 50, 75, 100]), $video_id (int)
Filter the settings REST API GET response. Use to expose additional settings to the admin SPA.
Parameters: $settings (array)
Filter settings data before saving from the settings REST API PUT. Use to intercept and save your own settings keys.
Parameters: $data (array)
Configure which HTTP headers are checked for client IP detection when recording a session or a devtools event. Default: array( 'REMOTE_ADDR' ). Useful when behind a proxy or CDN.
Parameters: $headers (array of header name strings)
add_filter( 'mediashield_trusted_ip_headers', function( $headers ) {
array_unshift( $headers, 'HTTP_CF_CONNECTING_IP' );
return $headers;
} );
The watermark overlay reads REMOTE_ADDR directly and is not affected by this filter.
Control whether output buffering runs on the current request.
Parameters: $enabled (bool)
// Disable on WooCommerce checkout.
add_filter( 'mediashield_enable_output_buffer', function( $enabled ) {
if ( function_exists( 'is_checkout' ) && is_checkout() ) {
return false;
}
return $enabled;
} );
Filter the final rendered player HTML.
Parameters: $html (string), $video_id (int), $atts (array with keys platform, protection_level, player_type)
Since 1.2.0. Filter the plain player markup emitted when MediaShield is switched off site-wide.
Parameters: $html (string), $video_id (int), $platform (string)
Since 1.1.0. When the allowed-domain whitelist is active, controls whether requests with no Referer header are allowed. Default false (deny).
Parameters: $allow (bool)
Since 1.1.0. Filter the frontend localized config payload before it is emitted as window.mediashieldConfig.
Parameters: $config (array)
Since 1.1.0. Filter the CSS classes on the player container element.
Parameters: $classes (array, default ['ms-protected-player']), $video_id (int)
Since 1.1.0. Filter the protection JavaScript config before it is passed to protection.js.
Parameters: $config (array with keys block_right_click, block_keyboard, hide_source, detect_devtools, pause_on_devtools, devtools_title, devtools_message)
Since 1.1.0. Return a non-empty slug to emit as data-access-type on the player container, so the client can render an alternative gate UI instead of the login overlay. Applied on both render paths (shortcode/block and auto-wrapped embeds).
Parameters: $access_type (string), $video_id (int)
Since 1.1.0. Gates whether anonymous (logged-out) visitors may call POST /session/start for a given video.
Defaults to true when the ms_require_login setting is off (since 1.3.0), or when the video has a non-empty _ms_access_type meta value. Reaching the handler is not the same as being allowed to watch: AccessControl::can_watch() still runs.
Parameters: $allow (bool), $video_id (int), $access_type (string), $request (WP_REST_Request)
Since 1.1.0. Override the source URL resolved by the [mediashield] shortcode at render time.
Parameters: $source_url (string), $video_id (int), $atts (array)
Since 1.1.0. Return false to prevent the frontend player assets from registering.
Parameters: $register (bool)
Since 1.3.0. Filter a minted signed embed URL. See Extension Architecture for what embed links are.
Parameters: $url (string), $video_id (int), $user_id (int)
Supply the in-video ad break list for a video. Returning a non-empty array is what causes the ad engine to load. Free ships a bridge that fills this from WB Ad Manager video creatives; with no ad plugin the list is empty and nothing loads.
Parameters: $breaks (array), $video_id (int), $duration (int, seconds)
Filter the pool of ad creatives available to a video before breaks are planned. Return an empty array to suppress ads for that video. Each item keeps the shape { id, label, video_url, click_url, skip_after }.
Parameters: $ads (array), $video_id (int), $duration (int)
Filter the break plan. Default is a pre-roll plus the configured number of mid-rolls, no post-roll.
Parameters: $plan (array { pre: bool, mid_count: int, post: bool }), $video_id (int), $duration (int)
Since 1.3.0. Rows moved per batch by the one-off job that restores archived watch sessions to the live table. Default 2000, clamped to 100-20000.
Parameters: $batch (int)
Since 1.0.1. Filter the GDPR export result before WordPress processes it. Append your own items, or set done to false while you still have rows to hand back on a later page.
Parameters: $result (array {data: array, done: bool}), $email (string), $user (WP_User or false), $page (int)
Filter the final GDPR erasure result before WordPress processes it. Append messages or adjust counts.
Parameters: $result (array), $email (string), $user (WP_User or false), $page (int)
JavaScript Events
The frontend player dispatches DOM CustomEvents on window. Listen with window.addEventListener( name, handler ).
Dispatched once a watch session has started and the player is wired up. This is the event the watermark and tracker scripts key off, so it is the right place to hang your own per-player behaviour.
Detail: el (HTMLElement), videoId (number), token (string), resumePosition (number), watermarkConfig (object), video (object), adapter (object)
Since 1.1.0, this event is cancelable. Dispatched when POST /session/start returns 403 or a denial code. Call event.preventDefault() to suppress the default error overlay if you're rendering your own gate UI.
Detail: el (HTMLElement), videoId (number), reason (string - access_denied, login_required, etc.)
Dispatched when session start is refused because the viewer is at their concurrent stream limit.
Detail: el (HTMLElement), videoId (number), message (string)
Dispatched in the browser the moment developer tools are detected, before the beacon is sent to the server.
Detail: strategy (string - size_delta or debugger_timing)
Dispatched by the playlist player when the queue advances to another video.
Detail: el (HTMLElement - the main player), videoId (number)