Developer Documentation
Complete reference for all hooks, filters, and APIs available in Polanger VideoHub. Build powerful integrations and custom addons.
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.
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.
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
/**
* 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.
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
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.
{
"type": "polanger-videohub-addon",
"slug": "pvh-example-addon",
"main": "pvh-example-addon.php",
"requires_core": "1.8.1"
}
Main File Template
<?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.
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.
/**
* 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
Fires when a video file is uploaded via the frontend upload form.
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
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
Fires when a video is imported from an external source (YouTube, Vimeo, etc.).
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
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
Fires after a video's metadata is saved/updated.
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
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
Fires before a video is permanently deleted.
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
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
Fires when a video's status changes (pending → published, etc.).
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
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
Fires after a video has been optimized by the Media Optimizer addon.
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
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
Fires after a video is uploaded via AJAX (frontend upload form). Use this for post-upload processing like AI analysis, thumbnail generation, or notifications.
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
// 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 );
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.
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
// 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
Fires before the video player on single video pages.
add_action( 'pvh_before_single_video', function( $video_id ) {
echo '<div class="custom-banner">Featured Video</div>';
} );
polanger_videohub_video_actions
Fires below the video title. Use this to add custom action buttons.
add_action( 'polanger_videohub_video_actions', function( $video_id ) {
echo '<button class="download-btn">Download</button>';
} );
polanger_videohub_after_video_details
Fires after video description. Add custom sections here.
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
Fires after main video content. Perfect for comments or related videos.
pvh_video_sidebar_top
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 the video player configuration arguments.
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 the video source URL before rendering.
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
Add custom tabs to the VideoHub settings page.
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
Add custom tabs to user profile pages.
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.
All player instances are accessible via window.PVHPlayer object.
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.
// 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.
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
/**
* 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.
// 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
Fires after each video in category grids.
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
Fires after each video in homepage grids.
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
Fires after each video in archive grids.
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
Add custom tabs to user profile pages.
$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
Add action buttons to author header.
pvh_profile_header_actions
Add buttons to user's own profile header.
Shorts Addon Hooks
Hooks specific to the Shorts (vertical video) addon.
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
Fires after each short item in the feed, perfect for injecting ads between shorts.
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
Disable specific filters programmatically.
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
Add custom filter groups to the search panel.
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
Fires after an earning record is created from a video sale.
// 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
Fires after a withdrawal is marked as paid.
// 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.
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 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 |
// 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 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 |
// 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
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 |
// 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
Fires when an ad interaction is completed (clicked). Use for rewarding users or tracking conversions.
// 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
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) |
// 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:
// 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.
| 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` |