Developer Documentation

Complete reference for all hooks, filters, and APIs available in Polanger VideoHub. Build powerful integrations and custom addons.

API Stability Public
Version 1.8.1
Hooks 170+
Backward Compatibility

All public hooks are guaranteed to remain stable within the same major version.

Version 1.8.1 Developer Notes

VideoHub 1.8.1 focuses on safer addon distribution, cleaner comment state handling, and more predictable search interactions. The public hook surface remains stable within the 1.x line.

Recommended addon distribution

Paid and optional addons should be packaged as normal WordPress plugins with VideoHub addon headers. VideoHub Core still presents them in VideoHub -> Addons, but WordPress owns installation, activation, updates, backups, and deletion.

Area Developer Impact
Core addon manager Standalone VideoHub-compatible plugins are discovered through plugin headers and can be represented in the VideoHub Addons screen without living inside the core plugin directory.
Official addon packages Official paid addon ZIPs should install into wp-content/plugins/{addon-slug}, protecting them from WordPress.org core updates.
PVH Comments Frontend comment loading now ignores stale AJAX responses when the active video, short, or comment section has changed. Empty lists also keep load-more controls hidden until more approved comments exist.
PVH Search Primary type selections are treated as selected filters until the user submits the search action, which makes custom filter integrations easier to reason about.

Addon Structure

VideoHub addons follow a consistent structure for easy development and maintenance.

Directory Structure
my-addon/
|-- my-addon.php          # Main addon file
|-- admin/
|   `-- views/            # Admin templates
|-- public/
|   |-- css/              # Frontend styles
|   |-- js/               # Frontend scripts
|   `-- views/            # Frontend templates
`-- includes/             # PHP classes

Main Addon File Header

PHP
<?php
/**
 * Addon Name: My Custom Addon
 * Addon URI: https://example.com/my-addon
 * Description: Description of what this addon does.
 * Version: 1.0.0
 * Author: Your Name
 * Author URI: https://example.com
 * Slug: my-addon
 * Requires: 1.0.0
 * Depends: premium-content
 */

Uploadable Addon Packages

VideoHub's Addons screen can install official addon ZIP packages as standard WordPress plugins while still presenting them as VideoHub addons. Use this contract when building official VideoHub addons that customers download from Polanger and upload from VideoHub -> Addons.

Strict package contract

The ZIP must contain exactly one top-level plugin folder. The folder name, addon slug, and final main PHP file name must match, for example pvh-ads/pvh-ads.php.

Required ZIP Layout

ZIP
pvh-example-addon.zip
`-- pvh-example-addon/
    |-- pvh-example-addon.php
    |-- pvh-addon.json          # Optional, but recommended
    |-- includes/
    |-- admin/
    `-- public/
Rule Requirement
File type Only .zip packages are accepted.
Root folder The extracted ZIP must contain exactly one addon plugin folder. Hidden folders and __MACOSX are ignored.
Slug match The folder name must match the addon slug from the PHP header or manifest.
Main file The installed addon plugin must include {addon-slug}.php at the root of the addon folder.
Catalog lock The slug must be in the official VideoHub addon catalog, unless extended with pvh_addon_installer_allowed_slugs.
Safety checks Absolute paths, Windows drive paths, and .. traversal entries are blocked before extraction.
Size limit The default ZIP size limit is 50 * MB_IN_BYTES and can be changed with pvh_addon_installer_max_zip_size.

Optional Manifest

The installer can work from headers only, but a manifest makes package intent explicit and gives the installer a safe main-file hint before final validation.

JSON
{
  "type": "polanger-videohub-addon",
  "slug": "pvh-example-addon",
  "main": "pvh-example-addon.php",
  "requires_core": "1.8.1"
}

Main File Template

PHP
<?php
/**
 * Addon Name: PVH Example Addon
 * Addon URI: https://polanger.com/
 * Description: Adds a custom VideoHub feature.
 * Version: 1.0.0
 * Author: Polanger
 * Author URI: https://polanger.com/
 * Slug: pvh-example-addon
 * Requires: 1.8.1
 * Depends: pvh-auth
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

add_action( 'polanger_videohub_addons_loaded', function( $addon_manager ) {
    // Register hooks, shortcodes, assets, or service classes here.
} );

Official Installable Slugs

The built-in installer currently accepts these optional official addon slugs by default. Core bundled addons such as PVH Comments, PVH Reactions, and PVH Search remain part of VideoHub Core.

Text
pvh-shorts, pvh-auth, pvh-channels, pvh-uploads, pvh-ads,
premium-content, marketplace,
live-streaming, pvh-media-optimizer, pvh-live-chat,
pvh-navigation-panel, pvh-pwa

External Plugin Addons

Third-party and community addons can follow the same standalone WordPress plugin pattern. Include the VideoHub headers below so VideoHub can identify the plugin as compatible and display it in addon management screens.

PHP
/**
 * Plugin Name: My External VideoHub Addon
 * PVH Addon: true
 * PVH Addon Slug: my-external-addon
 * Requires PVH: 1.8.1
 * PVH Depends: premium-content
 */

Video Lifecycle Hooks

These hooks fire at key moments in a video's lifecycle, enabling integrations with LMS, APIs, caching systems, and analytics.

pvh_video_uploaded
Action

Fires when a video file is uploaded via the frontend upload form.

PHP
do_action( 'pvh_video_uploaded', int $video_id, string $file_path );
Parameter Type Description
$video_id int The created video post ID
$file_path string Full path to the uploaded video file

Example

PHP
add_action( 'pvh_video_uploaded', function( $video_id, $file_path ) {
    // Send notification to admin
    wp_mail( 'admin@example.com', 'New Video Uploaded', 'Video ID: ' . $video_id );
}, 10, 2 );
pvh_video_imported
Action

Fires when a video is imported from an external source (YouTube, Vimeo, etc.).

PHP
do_action( 'pvh_video_imported', int $post_id, string $provider_id, array $video_data );
Parameter Type Description
$post_id int The created video post ID
$provider_id string Provider identifier (e.g., 'youtube', 'vimeo')
$video_data array Video metadata from the provider

Example

PHP
add_action( 'pvh_video_imported', function( $post_id, $provider_id, $video_data ) {
    // Log imported video
    error_log( "Video imported from {$provider_id}: {$post_id}" );
}, 10, 3 );
pvh_video_updated
Action

Fires after a video's metadata is saved/updated.

PHP
do_action( 'pvh_video_updated', int $post_id, WP_Post $post );
Parameter Type Description
$post_id int The video post ID
$post WP_Post The video post object

Example

PHP
add_action( 'pvh_video_updated', function( $post_id, $post ) {
    // Clear video cache
    wp_cache_delete( 'video_' . $post_id, 'pvh_videos' );
}, 10, 2 );
pvh_video_deleted
Action

Fires before a video is permanently deleted.

PHP
do_action( 'pvh_video_deleted', int $post_id, WP_Post $post );
Parameter Type Description
$post_id int The video post ID
$post WP_Post The video post object

Example

PHP
add_action( 'pvh_video_deleted', function( $post_id, $post ) {
    // Remove from external search index
    my_search_index_remove( $post_id );
    
    // Clean up related data
    delete_post_meta( $post_id, '_custom_meta' );
}, 10, 2 );
pvh_video_status_changed
Action

Fires when a video's status changes (pending → published, etc.).

PHP
do_action( 'pvh_video_status_changed', int $post_id, string $old_status, string $new_status );
Parameter Type Description
$post_id int The video post ID
$old_status string Previous post status
$new_status string New post status

Example

PHP
add_action( 'pvh_video_status_changed', function( $post_id, $old_status, $new_status ) {
    if ( $new_status === 'publish' && $old_status !== 'publish' ) {
        // Video just published - notify subscribers
        my_notify_subscribers( $post_id );
    }
    
    if ( $new_status === 'trash' ) {
        // Video moved to trash - update analytics
        my_analytics_track( 'video_trashed', $post_id );
    }
}, 10, 3 );
pvh_video_optimized
Action

Fires after a video has been optimized by the Media Optimizer addon.

PHP
do_action( 'pvh_video_optimized', int $video_id, string $output_file, string $output_url, array $stats );
Parameter Type Description
$video_id int The video post ID
$output_file string Path to the optimized video file
$output_url string URL of the optimized video
$stats array Optimization statistics (original_size, optimized_size, compression_ratio)

Example

PHP
add_action( 'pvh_video_optimized', function( $video_id, $output_file, $output_url, $stats ) {
    // Log optimization results
    error_log( sprintf(
        'Video %d optimized: %s reduction',
        $video_id,
        $stats['compression_ratio'] . '%'
    ) );
}, 10, 4 );
pvh_after_ajax_upload
Action New in 1.7.0

Fires after a video is uploaded via AJAX (frontend upload form). Use this for post-upload processing like AI analysis, thumbnail generation, or notifications.

PHP
do_action( 'pvh_after_ajax_upload', int $video_id, int $attachment_id );
Parameter Type Description
$video_id int The created video post ID
$attachment_id int The uploaded video attachment ID

Example: AI Processing Queue

PHP
// Queue video for AI transcription after upload
add_action( 'pvh_after_ajax_upload', function( $video_id, $attachment_id ) {
    // Mark video for AI processing
    update_post_meta( $video_id, '_pvh_ai_status', 'pending' );
    
    // Add to processing queue
    wp_schedule_single_event( time() + 60, 'pvh_process_ai_transcription', array( $video_id ) );
}, 10, 2 );
Related Hooks

Use pvh_video_uploaded for file-based uploads and pvh_after_ajax_upload for AJAX uploads. Both can be used together for comprehensive coverage.

AI-Ready Meta Fields

VideoHub 1.7.0+ automatically creates placeholder meta fields for future AI addon integration. These fields are created when a video is saved.

Future-Ready

These meta fields are placeholders for the upcoming VideoHub AI Addon (v1.8.x+). They are currently empty but provide a foundation for AI features like auto-transcription, auto-tagging, and content moderation.

Available Meta Fields

Meta Key Type Description
_pvh_ai_status string AI processing status: pending, processing, completed, failed
_pvh_ai_last_run int Unix timestamp of last AI processing
_pvh_ai_provider string AI provider used: openai, whisper, anthropic, etc.
_pvh_transcript_path string Path to transcript file (e.g., /wp-content/uploads/pvh-transcripts/123.txt)
_pvh_ai_data string (JSON) AI-generated data: chapters, tags, summary, keywords

Example: Custom AI Integration

PHP
// Process video with custom AI service
add_action( 'pvh_video_uploaded', function( $video_id, $file_path ) {
    // Mark as processing
    update_post_meta( $video_id, '_pvh_ai_status', 'processing' );
    update_post_meta( $video_id, '_pvh_ai_provider', 'my_custom_ai' );
    
    // Call your AI service
    $result = my_ai_service_analyze( $file_path );
    
    if ( $result ) {
        // Store AI data
        update_post_meta( $video_id, '_pvh_ai_data', wp_json_encode( array(
            'chapters'  => $result['chapters'],
            'tags'      => $result['tags'],
            'summary'   => $result['summary'],
            'keywords'  => $result['keywords'],
        ) ) );
        
        // Save transcript
        $transcript_path = wp_upload_dir()['basedir'] . '/pvh-transcripts/' . $video_id . '.txt';
        file_put_contents( $transcript_path, $result['transcript'] );
        update_post_meta( $video_id, '_pvh_transcript_path', $transcript_path );
        
        // Mark as completed
        update_post_meta( $video_id, '_pvh_ai_status', 'completed' );
        update_post_meta( $video_id, '_pvh_ai_last_run', time() );
    } else {
        update_post_meta( $video_id, '_pvh_ai_status', 'failed' );
    }
}, 10, 2 );

// Display AI-generated chapters on video page
add_action( 'polanger_videohub_after_video_details', function( $video_id ) {
    $ai_data = get_post_meta( $video_id, '_pvh_ai_data', true );
    if ( $ai_data ) {
        $data = json_decode( $ai_data, true );
        if ( ! empty( $data['chapters'] ) ) {
            echo '<div class="pvh-ai-chapters">';
            echo '<h4>Chapters</h4>';
            foreach ( $data['chapters'] as $chapter ) {
                printf( '<a href="#" data-time="%d">%s - %s</a>', 
                    $chapter['time'], 
                    gmdate( 'i:s', $chapter['time'] ), 
                    esc_html( $chapter['title'] ) 
                );
            }
            echo '</div>';
        }
    }
} );

Planned AI Features (v1.8.x+)

  • Auto-transcription - Whisper API integration
  • Auto-tagging - GPT-4 powered tag suggestions
  • Auto-chapters - Automatic chapter detection
  • Content moderation - Toxicity and copyright checks
  • Smart thumbnails - AI-selected best frames
  • Video summarization - Auto-generated descriptions

Single Video Page Hooks

Template hooks for customizing the single video page layout.

Hook Location Description
pvh_before_single_video Before video content Add content before the video player
polanger_videohub_video_actions Below video title Add action buttons (like, share, etc.)
polanger_videohub_after_video_details After video description Add content after video details
polanger_videohub_after_video_content After main content Add comments, related content, etc.
pvh_video_sidebar_top Top of sidebar Add content to sidebar (used by Live Chat)
pvh_before_single_video
Action

Fires before the video player on single video pages.

PHP
add_action( 'pvh_before_single_video', function( $video_id ) {
    echo '<div class="custom-banner">Featured Video</div>';
} );
polanger_videohub_video_actions
Action

Fires below the video title. Use this to add custom action buttons.

PHP
add_action( 'polanger_videohub_video_actions', function( $video_id ) {
    echo '<button class="download-btn">Download</button>';
} );
polanger_videohub_after_video_details
Action

Fires after video description. Add custom sections here.

PHP
add_action( 'polanger_videohub_after_video_details', function( $video_id ) {
    echo '<div class="my-custom-section">';
    echo '<h3>Related Products</h3>';
    // Display related products
    echo '</div>';
} );
polanger_videohub_after_video_content
Action

Fires after main video content. Perfect for comments or related videos.

pvh_video_sidebar_top
Action

Fires at the top of the video sidebar. Used by Live Chat addon.

Player Filters

Filters for customizing the video player behavior and appearance.

pvh_video_player_args
Filter

Filter the video player configuration arguments.

PHP
add_filter( 'pvh_video_player_args', function( $args, $video_id ) {
    // Enable autoplay for featured videos
    if ( get_post_meta( $video_id, '_featured', true ) ) {
        $args['autoplay'] = true;
    }
    
    // Custom poster image
    $args['poster'] = get_the_post_thumbnail_url( $video_id, 'full' );
    
    return $args;
}, 10, 2 );

Available Arguments

Key Type Default Description
autoplay bool false Auto-start video playback
muted bool false Start muted
loop bool false Loop video
controls bool true Show player controls
poster string '' Poster image URL
pvh_video_player_source
Filter

Filter the video source URL before rendering.

PHP
add_filter( 'pvh_video_player_source', function( $source, $video_id ) {
    // Use CDN URL in production
    if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
        $source = str_replace( 
            home_url(), 
            'https://cdn.example.com', 
            $source 
        );
    }
    return $source;
}, 10, 2 );
pvh_settings_tabs
Filter

Add custom tabs to the VideoHub settings page.

PHP
add_filter( 'pvh_settings_tabs', function( $tabs ) {
    $tabs['my_addon'] = array(
        'title'    => __( 'My Addon', 'my-addon' ),
        'icon'     => 'dashicons-admin-generic',
        'callback' => 'my_addon_settings_callback',
        'priority' => 50
    );
    return $tabs;
} );
pvh_profile_tabs
Filter

Add custom tabs to user profile pages.

PHP
add_filter( 'pvh_profile_tabs', function( $tabs, $user_id ) {
    $tabs['analytics'] = array(
        'title'    => __( 'Analytics', 'my-addon' ),
        'icon'     => 'chart-bar',
        'callback' => 'render_analytics_tab',
        'count'    => get_user_video_count( $user_id )
    );
    return $tabs;
}, 10, 2 );

JavaScript Player Events

Subscribe to player events for analytics, custom UI, or integrations.

Global Object

All player instances are accessible via window.PVHPlayer object.

JavaScript
document.addEventListener('pvh:player:ready', function(e) {
    const player = e.detail.player;
    const videoId = e.detail.videoId;
    
    console.log('Player ready for video:', videoId);
});

document.addEventListener('pvh:player:play', function(e) {
    // Track play event
    gtag('event', 'video_play', {
        video_id: e.detail.videoId
    });
});

document.addEventListener('pvh:player:ended', function(e) {
    // Show related videos
    showRelatedVideos(e.detail.videoId);
});

document.addEventListener('pvh:player:timeupdate', function(e) {
    const progress = (e.detail.currentTime / e.detail.duration) * 100;
    updateProgressBar(progress);
});

Available Events

Event Detail Properties Description
pvh:player:ready player, videoId Player initialized and ready
pvh:player:play videoId, currentTime Playback started
pvh:player:pause videoId, currentTime Playback paused
pvh:player:ended videoId, duration Video finished playing
pvh:player:timeupdate videoId, currentTime, duration Playback position changed
pvh:player:volumechange videoId, volume, muted Volume or mute state changed
pvh:player:fullscreen videoId, isFullscreen Fullscreen mode toggled
pvh:player:qualitychange videoId, quality Video quality changed

Player Methods

Control the player programmatically.

JavaScript
// Get player instance
const player = window.PVHPlayer.getInstance(videoId);

// Playback control
player.play();
player.pause();
player.stop();

// Seeking
player.seek(30);           // Seek to 30 seconds
player.seekPercent(50);    // Seek to 50%

// Volume
player.setVolume(0.8);     // 0-1
player.mute();
player.unmute();

// Quality
player.setQuality('720p');
player.getAvailableQualities(); // ['360p', '720p', '1080p']

// Fullscreen
player.enterFullscreen();
player.exitFullscreen();

// Get state
player.getCurrentTime();   // Current position in seconds
player.getDuration();      // Total duration
player.isPaused();         // Boolean
player.isEnded();          // Boolean

Cue Points

Add interactive markers and chapters to videos.

JavaScript
const player = window.PVHPlayer.getInstance(videoId);

// Add a cue point
player.addCuePoint({
    time: 30,
    label: 'Introduction ends',
    callback: function() {
        console.log('Reached introduction end');
    }
});

// Add chapter markers
player.setChapters([
    { time: 0, title: 'Introduction' },
    { time: 60, title: 'Main Content' },
    { time: 300, title: 'Conclusion' }
]);

// Listen for cue point events
document.addEventListener('pvh:player:cuepoint', function(e) {
    console.log('Cue point reached:', e.detail.label);
});

Example: Analytics Addon

Complete example of building a video analytics addon.

PHP
<?php
/**
 * Addon Name: Video Analytics
 * Description: Track video engagement and watch time.
 * Version: 1.0.0
 * Slug: video-analytics
 * Requires: 1.0.0
 */

class PVH_Video_Analytics {
    
    public function __construct() {
        // Track video views
        add_action( 'pvh_video_view_counted', array( $this, 'track_view' ), 10, 2 );
        
        // Add analytics tab to profile
        add_filter( 'pvh_profile_tabs', array( $this, 'add_analytics_tab' ), 10, 2 );
        
        // Enqueue tracking script
        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
        
        // AJAX handler for watch time
        add_action( 'wp_ajax_pvh_track_watch_time', array( $this, 'track_watch_time' ) );
        add_action( 'wp_ajax_nopriv_pvh_track_watch_time', array( $this, 'track_watch_time' ) );
    }
    
    public function track_view( $video_id, $user_id ) {
        global $wpdb;
        
        $wpdb->insert(
            $wpdb->prefix . 'pvh_analytics',
            array(
                'video_id'   => $video_id,
                'user_id'    => $user_id,
                'event_type' => 'view',
                'created_at' => current_time( 'mysql' )
            )
        );
    }
    
    public function add_analytics_tab( $tabs, $user_id ) {
        $tabs['analytics'] = array(
            'title'    => __( 'Analytics', 'video-analytics' ),
            'icon'     => 'chart-bar',
            'callback' => array( $this, 'render_analytics_tab' )
        );
        return $tabs;
    }
    
    public function render_analytics_tab( $user_id ) {
        $stats = $this->get_user_stats( $user_id );
        include plugin_dir_path( __FILE__ ) . 'views/analytics-tab.php';
    }
}

new PVH_Video_Analytics();

Example: Custom Settings Tab

Add a custom tab to VideoHub admin settings.

PHP
// Register settings tab
add_filter( 'pvh_settings_tabs', function( $tabs ) {
    $tabs['watermark'] = array(
        'title'    => __( 'Watermark', 'my-addon' ),
        'icon'     => 'dashicons-format-image',
        'callback' => 'render_watermark_settings',
        'priority' => 60
    );
    return $tabs;
} );

// Render tab content
function render_watermark_settings() {
    $options = get_option( 'pvh_watermark_settings', array() );
    ?>
    <div class="pvh-settings-section">
        <h3><?php _e( 'Watermark Settings', 'my-addon' ); ?></h3>
        
        <table class="form-table">
            <tr>
                <th><?php _e( 'Enable Watermark', 'my-addon' ); ?></th>
                <td>
                    <input type="checkbox" 
                           name="pvh_watermark_settings[enabled]" 
                           value="1" 
                           <?php checked( $options['enabled'] ?? false ); ?>>
                </td>
            </tr>
            <tr>
                <th><?php _e( 'Position', 'my-addon' ); ?></th>
                <td>
                    <select name="pvh_watermark_settings[position]">
                        <option value="top-left">Top Left</option>
                        <option value="top-right">Top Right</option>
                        <option value="bottom-left">Bottom Left</option>
                        <option value="bottom-right">Bottom Right</option>
                    </select>
                </td>
            </tr>
        </table>
    </div>
    <?php
}

// Save settings
add_action( 'pvh_save_settings', function() {
    if ( isset( $_POST['pvh_watermark_settings'] ) ) {
        update_option( 'pvh_watermark_settings', $_POST['pvh_watermark_settings'] );
    }
} );

Archive Page Hooks

Template hooks for video archive and category pages.

Hook Location Description
pvh_before_archive_content Before video grid Add content before video listings
pvh_before_archive_grid Before archive grid Add content directly before the grid
pvh_archive_grid_after_item After each grid item Inject content after specific video (for ads)
pvh_after_archive_grid After archive grid Add content directly after the grid
pvh_before_category_content Before category page Add content before category videos
pvh_category_grid_after_item After each category item Inject content after video in category
pvh_home_grid_after_item After each home item Inject content after video in homepage

Grid Item Hooks (for Ads)

These hooks fire after each video item in grids, perfect for injecting ads.

pvh_category_grid_after_item
Action

Fires after each video in category grids.

PHP
do_action( 'pvh_category_grid_after_item', int $grid_index, int $video_id, WP_Term $term );

// Example: Inject ad every 5 videos
add_action( 'pvh_category_grid_after_item', function( $index, $video_id, $term ) {
    if ( $index % 5 === 0 ) {
        echo '<div class="my-ad-unit">';
        // Your ad code here
        echo '</div>';
    }
}, 10, 3 );
Parameter Type Description
$grid_index int Current position in grid (1-indexed)
$video_id int Current video post ID
$term WP_Term Current category term
pvh_home_grid_after_item
Action

Fires after each video in homepage grids.

PHP
do_action( 'pvh_home_grid_after_item', int $grid_index, int $video_id, string $section_type );

$section_type can be 'latest', 'trending', etc.

pvh_archive_grid_after_item
Action

Fires after each video in archive grids.

PHP
do_action( 'pvh_archive_grid_after_item', int $grid_index, int $video_id );

Profile & Author Hooks

Hooks for customizing user profile and channel pages.

Hook Location Description
pvh_before_author_profile Before author profile Add content before profile
pvh_author_header_actions Author header Add action buttons to author header
pvh_after_author_profile After author profile Add content after profile
pvh_profile_header_actions Profile header Add buttons to user's own profile
pvh_channel_header_actions Channel header Add buttons to channel header
pvh_profile_tabs
Filter

Add custom tabs to user profile pages.

PHP
$tabs = apply_filters( 'pvh_profile_tabs', array $tabs, WP_User $user, bool $is_own_profile );

add_filter( 'pvh_profile_tabs', function( $tabs, $user, $is_own_profile ) {
    $tabs['analytics'] = array(
        'label' => 'Analytics',
        'icon'  => '<svg>...</svg>',
    );
    return $tabs;
}, 10, 3 );

// Add tab content
add_action( 'pvh_profile_tab_content_analytics', function( $user, $is_own_profile ) {
    if ( $is_own_profile ) {
        // Show analytics dashboard
    }
}, 10, 2 );
pvh_author_header_actions
Action

Add action buttons to author header.

pvh_profile_header_actions
Action

Add buttons to user's own profile header.

Shorts Addon Hooks

Hooks specific to the Shorts (vertical video) addon.

Addon Required

These hooks require the PVH Shorts addon to be active.

Hook Type Description
pvh_before_shorts_archive Action Before shorts archive content
pvh_before_shorts_feed Action Before shorts feed container
pvh_shorts_feed_after_item Action After each short in feed (for ads)
pvh_after_shorts_feed Action After shorts feed container
pvh_shorts_feed_after_item
Action

Fires after each short item in the feed, perfect for injecting ads between shorts.

PHP
do_action( 'pvh_shorts_feed_after_item', int $shorts_index, int $short_id );

// Example: Inject ad every 5 shorts
add_action( 'pvh_shorts_feed_after_item', function( $index, $short_id ) {
    if ( $index % 5 === 0 ) {
        echo '<div class="my-shorts-ad">';
        // Your ad code here
        echo '</div>';
    }
}, 10, 2 );
Parameter Type Description
$shorts_index int Current position in feed (1-indexed)
$short_id int Current short post ID

Search Addon Hooks

Hooks for customizing the advanced search functionality.

Settings & Configuration

Hook Type Description
pvh_search_init Action Fires when search addon initializes
pvh_search_settings Filter Filter search settings array
pvh_search_filter_enabled Filter Check if specific filter is enabled
pvh_search_settings_fields Action Add custom fields to search settings
pvh_search_settings_save Filter Filter settings before saving

Search Bar Rendering

Hook Type Description
pvh_before_search_bar_render Action Before search bar HTML is rendered
pvh_after_search_bar Action After search bar
pvh_search_before_type_chips Action Before type filter chips
pvh_search_after_filter_groups Action After filter groups (add custom filters)
pvh_search_filter_categories Filter Filter categories shown in search
pvh_search_filter_enabled
Filter

Disable specific filters programmatically.

PHP
add_filter( 'pvh_search_filter_enabled', function( $enabled, $filter ) {
    // Disable duration filter for non-logged-in users
    if ( $filter === 'duration' && ! is_user_logged_in() ) {
        return false;
    }
    return $enabled;
}, 10, 2 );
pvh_search_after_filter_groups
Action

Add custom filter groups to the search panel.

PHP
add_action( 'pvh_search_after_filter_groups', function( $settings ) {
    ?>
    <div class="pvh-filter-group">
        <div class="pvh-filter-group-header">
            <span><?php esc_html_e( 'Quality', 'my-addon' ); ?></span>
        </div>
        <div class="pvh-filter-options" data-filter="quality">
            <button type="button" class="pvh-filter-btn" data-value="hd">HD</button>
            <button type="button" class="pvh-filter-btn" data-value="4k">4K</button>
        </div>
    </div>
    <?php
} );

Marketplace Addon Hooks

Hooks for the video marketplace and premium content features.

Hook Type Description
pvh_marketplace_earning_created Action After an earning record is created
pvh_marketplace_earning_status_changed Action After earning status changes
pvh_marketplace_withdrawal_created Action After withdrawal request created
pvh_marketplace_withdrawal_paid Action After withdrawal marked as paid
pvh_marketplace_withdrawal_rejected Action After withdrawal rejected
pvh_marketplace_earnings_released Action After pending earnings released by cron
pvh_marketplace_vendor_profile_saved Action After vendor payout profile saved
pvh_marketplace_earning_created
Action

Fires after an earning record is created from a video sale.

PHP
// Notify vendor when earning is created
add_action( 'pvh_marketplace_earning_created', function( $earning_id, $data ) {
    $vendor_id = $data['vendor_id'];
    $amount = $data['net_amount'];
    
    // Send notification
    wp_mail( 
        get_userdata( $vendor_id )->user_email, 
        'New Sale!', 
        "You earned $amount from a video sale."
    );
}, 10, 2 );
pvh_marketplace_withdrawal_paid
Action

Fires after a withdrawal is marked as paid.

PHP
// Track withdrawals
add_action( 'pvh_marketplace_withdrawal_paid', function( $withdrawal_id, $withdrawal ) {
    // Log to external accounting system
    my_accounting_log( 'payout', $withdrawal->amount, $withdrawal->vendor_id );
}, 10, 2 );

Ads Addon Hooks

Hooks for video advertising integration, tracking, and advanced customization.

New in 1.6.0

Advanced developer hooks added for ad control, slot rendering, event tracking, and playback milestones.

Ad Placement Hooks

The Ads addon uses these existing hooks for ad placement:

Hook Ad Position
pvh_before_single_video Above video player
polanger_videohub_after_video_details Below video player
polanger_videohub_after_video_content Below comments
pvh_category_grid_after_item In-feed ads in category grids
pvh_archive_grid_after_item In-feed ads in archive grids
pvh_home_grid_after_item In-feed ads in homepage grids
pvh_shorts_feed_after_item Ads between shorts

Ad Control Hooks

Control ad display and content programmatically.

pvh_ads_should_show
Filter

Filter whether ads should be shown for a specific context. Use for geo-targeting, user role checks, or video-specific rules.

Parameter Type Description
$show bool Whether to show ads
$video_id int Current video ID (0 if not on video page)
$user_id int Current user ID (0 if not logged in)
$slot string Ad slot identifier
PHP
// Disable ads for kids content
add_filter( 'pvh_ads_should_show', function( $show, $video_id, $user_id, $slot ) {
    if ( $video_id && has_term( 'kids', 'pvh_category', $video_id ) ) {
        return false;
    }
    return $show;
}, 10, 4 );

// Disable ads for premium subscribers
add_filter( 'pvh_ads_should_show', function( $show, $video_id, $user_id, $slot ) {
    if ( $user_id && user_can( $user_id, 'premium_member' ) ) {
        return false;
    }
    return $show;
}, 10, 4 );
pvh_ad_slot_before_render
Filter

Filter ad content before rendering. Modify ad code, image, or URL based on slot type, video category, or other conditions.

Parameter Type Description
$ad_data array Ad data with keys: type, code, image, url
$slot string Ad slot identifier
$video_id int Current video ID
PHP
// Use different ad for gaming category
add_filter( 'pvh_ad_slot_before_render', function( $ad_data, $slot, $video_id ) {
    if ( $video_id && has_term( 'gaming', 'pvh_category', $video_id ) ) {
        $ad_data['code'] = '<div class="gaming-sponsor">Gaming Ad</div>';
    }
    return $ad_data;
}, 10, 3 );

Ad Event Hooks

Track and respond to ad events.

pvh_ad_event_tracked
Action

Fires when any ad event (impression or click) is tracked. Use for external analytics integration.

Parameter Type Description
$slot string Ad slot identifier
$event string 'impression' or 'click'
$video_id int Video ID
$user_id int User ID
PHP
// Send to external analytics
add_action( 'pvh_ad_event_tracked', function( $slot, $event, $video_id, $user_id ) {
    // Send to Google Analytics, Mixpanel, etc.
    do_action( 'my_analytics_track', 'ad_' . $event, array(
        'slot' => $slot,
        'video_id' => $video_id,
    ) );
}, 10, 4 );
pvh_ad_completed
Action

Fires when an ad interaction is completed (clicked). Use for rewarding users or tracking conversions.

PHP
// Award points for ad interaction
add_action( 'pvh_ad_completed', function( $slot, $video_id, $user_id ) {
    if ( $user_id ) {
        $points = intval( get_user_meta( $user_id, 'ad_points', true ) );
        update_user_meta( $user_id, 'ad_points', $points + 5 );
    }
}, 10, 3 );

Playback Milestone Hook

pvh_video_playback_milestone
Action

Fires when a video playback milestone is reached. Useful for analytics, mid-roll ad triggering, or engagement tracking.

Parameter Type Description
$video_id int Video post ID
$milestone int Milestone percentage (25, 50, 75, or 100)
$user_id int User ID (0 if not logged in)
PHP
// Track video completion
add_action( 'pvh_video_playback_milestone', function( $video_id, $milestone, $user_id ) {
    if ( $milestone === 100 && $user_id ) {
        // Video completed - update watch history
        $history = get_user_meta( $user_id, 'completed_videos', true ) ?: array();
        $history[] = $video_id;
        update_user_meta( $user_id, 'completed_videos', array_unique( $history ) );
    }
}, 10, 3 );

JavaScript API

The Ads addon exposes a global PVH_Ads object for custom integrations:

JavaScript
// Track custom ad event
PVH_Ads.trackEvent('custom-slot', 'impression');
PVH_Ads.trackEvent('custom-slot', 'click');

// Track ad completion with watch duration
PVH_Ads.trackAdCompletion('preroll', 15); // 15 seconds watched

// Track custom milestone
PVH_Ads.trackMilestone(50); // 50% milestone

// Check if ads should show
if (PVH_Ads.shouldShowAds) {
    // Show custom ad
}

// Listen to milestone events
$(document).on('pvh:milestone', function(e, data) {
    console.log('Milestone:', data.milestone, 'Video:', data.videoId);
});

// Listen to ad completion events
$(document).on('pvh:ad:completed', function(e, data) {
    console.log('Ad completed:', data.slot);
});

Ad Statistics Table

The addon creates a wp_pvh_ad_stats table:

Column Type Description
id bigint Primary key
ad_slot varchar(50) Ad slot identifier
event_type enum 'impression' or 'click'
video_id bigint Associated video ID
user_id bigint User ID (if logged in)
created_at datetime Event timestamp

Complete Hook Inventory

This compact inventory was generated from static do_action() and apply_filters() calls in the VideoHub core and bundled addons. Dynamic hook families are shown with placeholder names such as {$tab_slug}. The source column is a representative call site; some hooks are fired from more than one template.

Generated hook inventory
| Hook | Type | Representative source |
|------|------|-----------------------|
| `polanger_videohub_addon_activated` | action | `includes/class-polanger-videohub-addon-manager.php:569` |
| `polanger_videohub_addon_deactivated` | action | `includes/class-polanger-videohub-addon-manager.php:596` |
| `polanger_videohub_addon_loaded` | action | `includes/class-polanger-videohub-addon-manager.php:481` |
| `polanger_videohub_addon_paths` | filter | `includes/class-polanger-videohub-addon-manager.php:181` |
| `polanger_videohub_addons_loaded` | action | `includes/class-polanger-videohub-addon-manager.php:145` |
| `polanger_videohub_after_video_content` | action | `addons/live-streaming/templates/single-pvh_live_stream.php:272` |
| `polanger_videohub_after_video_details` | action | `addons/live-streaming/templates/single-pvh_live_stream.php:263` |
| `polanger_videohub_allowed_player_html` | filter | `public/class-polanger-videohub-public.php:1202` |
| `polanger_videohub_create_core_addon_tables` | action | `includes/class-polanger-videohub-activator.php:196` |
| `polanger_videohub_database_upgrade` | action | `includes/class-polanger-videohub.php:198` |
| `polanger_videohub_homepage_option_defaults` | filter | `admin/views/settings-homepage-tab.php:43` |
| `polanger_videohub_sanitize_homepage_options` | filter | `admin/class-polanger-videohub-admin.php:623` |
| `polanger_videohub_save_video_meta` | action | `admin/class-polanger-videohub-admin.php:1329` |
| `polanger_videohub_video_actions` | action | `addons/live-streaming/templates/single-pvh_live_stream.php:211` |
| `polanger_videohub_video_details_meta_box` | action | `admin/views/meta-box-video-details.php:110` |
| `polanger_videohub_video_player` | filter | `public/class-polanger-videohub-public.php:1147` |
| `polanger_videohub_video_stats_meta_box` | action | `admin/views/meta-box-video-stats.php:24` |
| `pvh_ad_completed` | action | `addons/pvh-ads/pvh-ads.php:889` |
| `pvh_ad_event_tracked` | action | `addons/pvh-ads/pvh-ads.php:876` |
| `pvh_ad_slot_before_render` | filter | `addons/pvh-ads/pvh-ads.php:512` |
| `pvh_ad_unit_html` | filter | `addons/pvh-ads/pvh-ads.php:550` |
| `pvh_addon_can_activate_{$addon_slug}` | filter | `admin/class-polanger-videohub-admin.php:789` |
| `pvh_addon_installer_allowed_slugs` | filter | `includes/class-polanger-videohub-addon-installer.php:121` |
| `pvh_addon_installer_max_zip_size` | filter | `includes/class-polanger-videohub-addon-installer.php:151` |
| `pvh_admin_dashboard_after` | action | `admin/views/dashboard-page.php:1624` |
| `pvh_ads_should_show` | filter | `addons/pvh-ads/pvh-ads.php:287` |
| `pvh_after_ajax_upload` | action | `addons/pvh-uploads/pvh-uploads.php:1454` |
| `pvh_after_archive_grid` | action | `templates/archive-pvh_video.php:207` |
| `pvh_after_author_profile` | action | `public/views/shortcode-author-profile.php:293` |
| `pvh_after_category_content` | action | `templates/taxonomy-pvh_category.php:250` |
| `pvh_after_category_grid` | action | `templates/taxonomy-pvh_category.php:132` |
| `pvh_after_search_bar` | action | `addons/pvh-search/templates/search-bar.php:60` |
| `pvh_after_search_bar_render` | action | `addons/pvh-search/templates/search-bar.php:338` |
| `pvh_after_shorts_archive` | action | `addons/pvh-shorts/public/views/archive-shorts.php:256` |
| `pvh_after_shorts_feed` | action | `addons/pvh-shorts/public/views/shorts-feed.php:41` |
| `pvh_after_single_playlist` | action | `templates/single-pvh_playlist.php:79` |
| `pvh_after_tag_content` | action | `templates/taxonomy-pvh_tag.php:100` |
| `pvh_archive_grid_after_item` | action | `templates/archive-pvh_video.php:198` |
| `pvh_author_destination_url` | filter | `public/class-polanger-videohub-public.php:1281` |
| `pvh_author_header_actions` | action | `public/views/shortcode-author-profile.php:67` |
| `pvh_author_profile_url` | filter | `public/class-polanger-videohub-public.php:1319` |
| `pvh_before_ajax_upload` | action | `addons/pvh-uploads/pvh-uploads.php:1408` |
| `pvh_before_archive_content` | action | `addons/live-streaming/templates/archive-pvh_live_stream.php:69` |
| `pvh_before_archive_grid` | action | `templates/archive-pvh_video.php:181` |
| `pvh_before_author_profile` | action | `public/views/shortcode-author-profile.php:34` |
| `pvh_before_category_content` | action | `templates/taxonomy-pvh_category.php:78` |
| `pvh_before_category_grid` | action | `templates/taxonomy-pvh_category.php:108` |
| `pvh_before_home_content` | action | `public/views/shortcode-home.php:69` |
| `pvh_before_search_bar_render` | action | `addons/pvh-search/templates/search-bar.php:30` |
| `pvh_before_search_results` | action | `addons/pvh-search/templates/search-results.php:37` |
| `pvh_before_shorts_archive` | action | `addons/pvh-shorts/public/views/archive-shorts.php:146` |
| `pvh_before_shorts_feed` | action | `addons/pvh-shorts/public/views/shorts-feed.php:16` |
| `pvh_before_single_playlist` | action | `templates/single-pvh_playlist.php:35` |
| `pvh_before_single_video` | action | `addons/live-streaming/templates/single-pvh_live_stream.php:118` |
| `pvh_before_tag_content` | action | `templates/taxonomy-pvh_tag.php:47` |
| `pvh_before_videos_content` | action | `public/views/shortcode-videos.php:49` |
| `pvh_can_comment` | filter | `addons/pvh-comments/pvh-comments.php:238` |
| `pvh_can_react` | filter | `addons/pvh-reactions/pvh-reactions.php:791` |
| `pvh_can_upload` | filter | `addons/pvh-uploads/pvh-uploads.php:1003` |
| `pvh_category_grid_after_item` | action | `templates/taxonomy-pvh_category.php:127` |
| `pvh_channel_before_delete` | action | `addons/pvh-channels/pvh-channels.php:1293` |
| `pvh_channel_created` | action | `addons/pvh-channels/pvh-channels.php:1173` |
| `pvh_channel_deleted` | action | `addons/pvh-channels/pvh-channels.php:1304` |
| `pvh_channel_header_actions` | action | `public/views/shortcode-channel.php:38` |
| `pvh_channel_subscribed` | action | `addons/pvh-channels/pvh-channels.php:1448` |
| `pvh_channel_unsubscribed` | action | `addons/pvh-channels/pvh-channels.php:1458` |
| `pvh_channel_updated` | action | `addons/pvh-channels/pvh-channels.php:1252` |
| `pvh_channel_visible_post_statuses` | filter | `addons/pvh-channels/pvh-channels.php:1081` |
| `pvh_chat_can_send` | filter | `addons/pvh-live-chat/pvh-live-chat.php:497` |
| `pvh_chat_message_content` | filter | `addons/pvh-live-chat/includes/class-pvh-live-chat-message.php:564` |
| `pvh_chat_message_deleted` | action | `addons/pvh-live-chat/includes/class-pvh-live-chat-message.php:499` |
| `pvh_chat_message_sent` | action | `addons/pvh-live-chat/includes/class-pvh-live-chat-message.php:148` |
| `pvh_chat_transport` | filter | `addons/pvh-live-chat/pvh-live-chat.php:205` |
| `pvh_comment_added` | action | `addons/pvh-comments/pvh-comments.php:911` |
| `pvh_comment_content` | filter | `addons/pvh-comments/pvh-comments.php:611` |
| `pvh_comment_deleted` | action | `addons/pvh-comments/includes/class-pvh-user-comments.php:474` |
| `pvh_comment_edited` | action | `addons/pvh-comments/pvh-comments.php:1040` |
| `pvh_comment_voted` | action | `addons/pvh-comments/pvh-comments.php:1353` |
| `pvh_dashboard_after_system_status` | action | `admin/views/dashboard-page.php:1156` |
| `pvh_dashboard_monetization_stats` | action | `admin/views/dashboard-page.php:1544` |
| `pvh_dashboard_register_widgets` | action | `admin/views/dashboard-page.php:1615` |
| `pvh_home_after_hero` | action | `public/views/shortcode-home.php:193` |
| `pvh_home_grid_after_item` | action | `public/views/shortcode-home.php:232` |
| `pvh_homepage_settings_after_hero` | action | `admin/views/settings-homepage-tab.php:355` |
| `pvh_live_stream_sidebar_top` | action | `addons/live-streaming/templates/single-pvh_live_stream.php:282` |
| `pvh_marketplace_earning_created` | action | `addons/marketplace/includes/class-pvh-marketplace-earnings.php:145` |
| `pvh_marketplace_earning_gross_amount` | filter | `addons/marketplace/includes/class-pvh-marketplace-woocommerce.php:119` |
| `pvh_marketplace_earning_status_changed` | action | `addons/marketplace/includes/class-pvh-marketplace-earnings.php:292` |
| `pvh_marketplace_earnings_released` | action | `addons/marketplace/includes/class-pvh-marketplace-cron.php:56` |
| `pvh_marketplace_refund_withdrawn_attempt` | action | `addons/marketplace/includes/class-pvh-marketplace-earnings.php:236` |
| `pvh_marketplace_refund_withdrawn_earnings` | action | `addons/marketplace/includes/class-pvh-marketplace-woocommerce.php:306` |
| `pvh_marketplace_vendor_profile_saved` | action | `addons/marketplace/includes/class-pvh-marketplace-vendor-profile.php:212` |
| `pvh_marketplace_withdrawal_created` | action | `addons/marketplace/includes/class-pvh-marketplace-withdrawals.php:194` |
| `pvh_marketplace_withdrawal_paid` | action | `addons/marketplace/includes/class-pvh-marketplace-withdrawals.php:476` |
| `pvh_marketplace_withdrawal_rejected` | action | `addons/marketplace/includes/class-pvh-marketplace-withdrawals.php:636` |
| `pvh_mobile_bar_after_home` | action | `public/class-polanger-videohub-public.php:1574` |
| `pvh_mobile_bar_after_items` | action | `public/class-polanger-videohub-public.php:1589` |
| `pvh_mobile_bar_after_popups` | action | `public/class-polanger-videohub-public.php:1691` |
| `pvh_mobile_bar_after_user` | action | `public/class-polanger-videohub-public.php:1561` |
| `pvh_mobile_bar_before_items` | action | `public/class-polanger-videohub-public.php:1542` |
| `pvh_mobile_bar_before_popups` | action | `public/class-polanger-videohub-public.php:1598` |
| `pvh_mobile_drawer_after_items` | action | `addons/pvh-navigation-panel/templates/mobile-drawer.php:205` |
| `pvh_mobile_drawer_before_items` | action | `addons/pvh-navigation-panel/templates/mobile-drawer.php:40` |
| `pvh_mobile_drawer_footer` | action | `addons/pvh-navigation-panel/templates/mobile-drawer.php:215` |
| `pvh_mobile_user_menu_items` | action | `public/class-polanger-videohub-public.php:1631` |
| `pvh_nav_panel_after_items` | action | `addons/pvh-navigation-panel/templates/navigation-panel.php:75` |
| `pvh_nav_panel_before_items` | action | `addons/pvh-navigation-panel/templates/navigation-panel.php:30` |
| `pvh_nav_panel_footer` | action | `addons/pvh-navigation-panel/templates/navigation-panel.php:260` |
| `pvh_nav_panel_items` | filter | `addons/pvh-navigation-panel/pvh-navigation-panel.php:462` |
| `pvh_playlist_deleted` | action | `includes/class-polanger-videohub.php:678` |
| `pvh_premium_validate_stream_ip` | filter | `addons/premium-content/includes/class-pvh-premium-content-secure-stream.php:303` |
| `pvh_profile_header_actions` | action | `addons/pvh-auth/public/views/profile.php:134` |
| `pvh_profile_tab_content_{$tab_key}` | action | `addons/pvh-auth/public/views/profile.php:511` |
| `pvh_profile_tabs` | filter | `addons/pvh-auth/public/views/profile.php:178` |
| `pvh_reactable_post_types` | filter | `addons/pvh-reactions/pvh-reactions.php:738` |
| `pvh_reaction_added` | action | `addons/pvh-reactions/pvh-reactions.php:458` |
| `pvh_reaction_counts` | filter | `addons/pvh-reactions/pvh-reactions.php:233` |
| `pvh_reaction_removed` | action | `addons/pvh-reactions/pvh-reactions.php:410` |
| `pvh_register_providers` | action | `includes/providers/class-pvh-provider-manager.php:106` |
| `pvh_sanitize_general_options` | filter | `admin/class-polanger-videohub-admin.php:710` |
| `pvh_sanitize_mobile_options` | filter | `admin/class-polanger-videohub-admin.php:728` |
| `pvh_search_after_filter_groups` | action | `addons/pvh-search/templates/search-bar.php:298` |
| `pvh_search_after_type_chips` | action | `addons/pvh-search/templates/search-bar.php:174` |
| `pvh_search_before_filter_groups` | action | `addons/pvh-search/templates/search-bar.php:191` |
| `pvh_search_before_type_chips` | action | `addons/pvh-search/templates/search-bar.php:131` |
| `pvh_search_filter_categories` | filter | `addons/pvh-search/templates/search-bar.php:43` |
| `pvh_search_filter_enabled` | filter | `addons/pvh-search/pvh-search.php:1168` |
| `pvh_search_has_filters` | filter | `addons/pvh-search/templates/search-bar.php:57` |
| `pvh_search_init` | action | `addons/pvh-search/pvh-search.php:141` |
| `pvh_search_query_args` | filter | `addons/pvh-search/pvh-search.php:780` |
| `pvh_search_results` | filter | `addons/pvh-search/pvh-search.php:817` |
| `pvh_search_settings` | filter | `addons/pvh-search/pvh-search.php:1148` |
| `pvh_search_settings_fields` | action | `addons/pvh-search/pvh-search.php:1287` |
| `pvh_search_settings_save` | filter | `addons/pvh-search/pvh-search.php:1329` |
| `pvh_search_settings_saved` | action | `addons/pvh-search/pvh-search.php:1339` |
| `pvh_search_suggestions` | filter | `addons/pvh-search/pvh-search.php:1035` |
| `pvh_search_video_data` | filter | `addons/pvh-search/pvh-search.php:1001` |
| `pvh_settings_general_tab_content` | action | `admin/views/settings-page.php:274` |
| `pvh_settings_mobile_tab_content` | action | `admin/views/settings-page.php:1230` |
| `pvh_settings_save` | action | `admin/class-polanger-videohub-admin.php:821` |
| `pvh_settings_tab_content_{$tab_slug}` | action | `admin/views/settings-page.php:1258` |
| `pvh_settings_tabs` | filter | `admin/views/settings-page.php:102` |
| `pvh_short_data` | filter | `addons/pvh-shorts/pvh-shorts.php:1659` |
| `pvh_short_deleted` | action | `includes/class-polanger-videohub.php:649` |
| `pvh_short_liked` | action | `addons/pvh-shorts/pvh-shorts.php:1605` |
| `pvh_short_viewed` | action | `addons/pvh-shorts/pvh-shorts.php:1569` |
| `pvh_shorts_before_render` | action | `addons/pvh-shorts/pvh-shorts.php:1314` |
| `pvh_shorts_feed_after_item` | action | `addons/pvh-shorts/public/views/shorts-feed.php:34` |
| `pvh_shorts_query_args` | filter | `addons/pvh-shorts/pvh-shorts.php:1300` |
| `pvh_upload_file_types` | filter | `addons/pvh-uploads/pvh-uploads.php:713` |
| `pvh_upload_form_after_details` | action | `addons/pvh-uploads/public/views/upload-edit.php:122` |
| `pvh_upload_max_size` | filter | `addons/pvh-uploads/pvh-uploads.php:695` |
| `pvh_upload_settings` | filter | `addons/pvh-uploads/pvh-uploads.php:961` |
| `pvh_uploads_should_enqueue_assets` | filter | `addons/pvh-uploads/pvh-uploads.php:574` |
| `pvh_user_dropdown_menu_items` | action | `addons/pvh-auth/pvh-auth.php:843` |
| `pvh_video_debug_is_supported_page` | filter | `includes/class-pvh-video-debug.php:651` |
| `pvh_video_debug_page_context` | filter | `includes/class-pvh-video-debug.php:652` |
| `pvh_video_debug_page_report` | filter | `includes/class-pvh-video-debug.php:766` |
| `pvh_video_deleted` | action | `includes/class-polanger-videohub.php:645` |
| `pvh_video_details_saved` | action | `addons/pvh-uploads/pvh-uploads.php:1577` |
| `pvh_video_file_replaced` | action | `addons/pvh-uploads/pvh-uploads.php:1751` |
| `pvh_video_imported` | action | `includes/providers/class-pvh-provider-manager.php:293` |
| `pvh_video_optimized` | action | `addons/pvh-media-optimizer/pvh-media-optimizer.php:1607` |
| `pvh_video_playback_milestone` | action | `addons/pvh-ads/pvh-ads.php:920` |
| `pvh_video_player_args` | filter | `public/class-polanger-videohub-public.php:1038` |
| `pvh_video_player_source` | filter | `public/class-polanger-videohub-public.php:745` |
| `pvh_video_published` | action | `addons/pvh-uploads/pvh-uploads.php:1590` |
| `pvh_video_sidebar_top` | action | `templates/single-pvh_video.php:232` |
| `pvh_video_status_changed` | action | `includes/class-polanger-videohub.php:707` |
| `pvh_video_updated` | action | `admin/class-polanger-videohub-admin.php:1338` |
| `pvh_video_uploaded` | action | `addons/pvh-uploads/pvh-uploads.php:1441` |