Skip to main content

Overview

Visual Portfolio supports video and audio content types, allowing you to create multimedia portfolios with YouTube, Vimeo, self-hosted videos, and audio files. Content can be displayed inline or in lightbox popups.

Post Format Support

The plugin uses WordPress post formats to identify video and audio content:
// Format detection in templates
switch ( $args['format'] ) {
    case 'video':
        visual_portfolio()->include_template( 'icons/play' );
        break;
    case 'audio':
        visual_portfolio()->include_template( 'icons/music' );
        break;
    case 'gallery':
        visual_portfolio()->include_template( 'icons/gallery' );
        break;
}

Video Format Configuration

Adding Video URL to Posts

Video URLs are stored in post meta:
// class-custom-post-meta.php:244
public static function get_video_format_url( $post_id ) {
    $video_url = get_post_meta( $post_id, '_vp_format_video_url', true );
    return $video_url;
}

Meta Box for Video URL

The plugin adds a meta box to posts with video format:
// class-custom-post-meta.php:159
public static function add_video_format_metabox( $post ) {
    $video_url = self::get_video_format_url( $post->ID );
    ?>
    <input class="vp-input" 
           name="_vp_format_video_url" 
           type="url" 
           value="<?php echo esc_attr( $video_url ); ?>" 
           placeholder="<?php echo esc_attr__( 'https://', 'visual-portfolio' ); ?>">
    <?php
}

Supported Video Sources

YouTube

https://www.youtube.com/watch?v=VIDEO_ID
https://youtu.be/VIDEO_ID

Vimeo

https://vimeo.com/VIDEO_ID

Self-Hosted Videos

https://example.com/videos/my-video.mp4
https://example.com/videos/my-video.webm

Supported Formats

  • MP4 (H.264)
  • WebM
  • OGG/OGV

Video Popup Implementation

Video popup data is rendered in a hidden template:
// templates/popup/video-popup-data.php
<template class="vp-portfolio__item-popup"
    style="display: none;"
    data-vp-popup-video="<?php echo esc_url( $video_data['url'] ); ?>"
    data-vp-popup-poster="<?php echo $video_data['poster'] ? esc_url( $video_data['poster'] ) : ''; ?>">
    
    <?php if ( $video_data[ $title_source ] ) : ?>
        <h3 class="vp-portfolio__item-popup-title">
            <?php echo wp_kses_post( $video_data[ $title_source ] ); ?>
        </h3>
    <?php endif; ?>
    
    <?php if ( $video_data[ $description_source ] ) : ?>
        <div class="vp-portfolio__item-popup-description">
            <?php echo wp_kses_post( $content ); ?>
        </div>
    <?php endif; ?>
</template>

Video Data Structure

$video_data = [
    'url' => 'https://youtube.com/watch?v=...',
    'poster' => 'https://example.com/poster.jpg',
    'item_title' => 'Video Title',
    'item_description' => 'Video description',
    'item_author' => 'Author Name',
    'item_author_url' => 'https://example.com/author',
];

Format Detection and Icons

Icon Templates

The plugin includes icon templates for different media types:
templates/icons/
  play.php      - Video icon
  music.php     - Audio icon
  gallery.php   - Gallery icon
  image.php     - Image icon

Format-Based Icons

// templates/items-list/item-parts/icon.php:23
switch ( $args['format'] ) {
    case 'video':
        visual_portfolio()->include_template( 'icons/play' );
        break;
    case 'audio':
        visual_portfolio()->include_template( 'icons/music' );
        break;
}

Video URL Processing

Retrieving Video URL

// class-get-portfolio.php:763
if ( 'video' === $args['format'] ) {
    $video_url = Visual_Portfolio_Custom_Post_Meta::get_video_format_url( get_the_ID() );
}

Adding Video to Item Data

// class-get-portfolio.php:2289
if ( 'video' === $args['format'] && $args['video'] ) {
    $item_data['video_url'] = $args['video'];
}

Format-Specific Image Handling

// class-get-portfolio.php:671
if ( 'video' === $args['format'] && isset( $img['video_url'] ) && $img['video_url'] ) {
    // Handle video poster image
}

Audio Format Support

While the code shows audio format detection in icons and format switches, audio implementation follows similar patterns to video:
case 'audio':
    visual_portfolio()->include_template( 'icons/music' );
    break;

Audio File Support

  • MP3
  • WAV
  • OGG

Audio Players

  • WordPress native audio player
  • Custom audio player via popup
  • Embedded audio services (SoundCloud, etc.)

Click Actions

Configure what happens when users click portfolio items:
$args['vp_opts']['items_click_action'] = 'popup_gallery';
  • popup_gallery: Open in lightbox
  • url: Navigate to URL
  • false: No action

Video in Popup

When video format is detected with popup action:
if ( 'video' === $format && 'popup_gallery' === $click_action ) {
    // Display video icon
    visual_portfolio()->include_template( 'icons/play' );
}

Supported Lightbox Plugins

PhotoSwipe

Default lightbox with video support

Fancybox

// classes/3rd/plugins/class-fancybox.php
class Visual_Portfolio_3rd_Fancybox {
    // Integration with Fancybox for video popups
}

Video Player in Lightbox

  • YouTube/Vimeo: Embedded iframe player
  • Self-hosted: HTML5 video player
  • Audio: HTML5 audio player

Video Poster Images

The featured image serves as the video poster:
$poster = get_the_post_thumbnail_url( $post_id, 'large' );

Lazy Loading Posters

Poster images benefit from lazy loading:
// Video posters use lazy loading when enabled
if ( Visual_Portfolio_Images::$allow_vp_lazyload ) {
    $image = Visual_Portfolio_Images::add_image_placeholders( $image );
}

Custom Video Sources

Adding Custom Video Providers

add_filter( 'vpf_video_url', function( $video_url, $post_id ) {
    // Add support for custom video provider
    if ( strpos( $video_url, 'custom-video-site.com' ) !== false ) {
        // Transform URL for embedding
        $video_url = str_replace( '/watch/', '/embed/', $video_url );
    }
    return $video_url;
}, 10, 2 );

Responsive Video Embedding

Videos automatically adapt to container width:
.vp-portfolio__item-video {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 aspect ratio */
    height: 0;
    overflow: hidden;
}

.vp-portfolio__item-video iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

Video Performance Optimization

Lazy Loading Videos

// Only load video iframe when popup opens
data-vp-popup-video="<?php echo esc_url( $video_url ); ?>"

Thumbnail Optimization

  • Use optimized poster images
  • Lazy load poster images
  • Generate multiple sizes for responsive images

Hooks and Filters

Modify Video URL

add_filter( 'vpf_video_url', function( $url, $post_id ) {
    // Modify video URL before rendering
    return $url;
}, 10, 2 );

Customize Video Popup

add_filter( 'vpf_video_popup_data', function( $data, $post_id ) {
    // Add custom data to video popup
    $data['custom_field'] = get_post_meta( $post_id, 'custom_meta', true );
    return $data;
}, 10, 2 );

Change Video Icon

add_action( 'vpf_template_icons_play', function() {
    // Custom play icon SVG
    ?>
    <svg><!-- Custom icon --></svg>
    <?php
});

Examples

Video Portfolio with Filters

echo do_shortcode( '[visual_portfolio 
    id="123" 
    content_source="post-based"
    posts_source="portfolio"
    posts_filter="true"
    posts_filter_taxonomy="portfolio_category"
    layout="tiles"
    items_click_action="popup_gallery"
]' );
// Query posts with different formats
$query = new WP_Query([
    'post_type' => 'post',
    'tax_query' => [
        [
            'taxonomy' => 'post_format',
            'field' => 'slug',
            'terms' => [
                'post-format-video',
                'post-format-audio',
                'post-format-gallery',
                'post-format-image',
            ]
        ]
    ]
]);

Self-Hosted Video

// Add self-hosted video URL
update_post_meta( $post_id, '_vp_format_video_url', 
    'https://example.com/videos/my-video.mp4' 
);

// Set post format
set_post_format( $post_id, 'video' );

Best Practices

  • Use appropriate resolution (1080p for most cases)
  • Optimize file size for web delivery
  • Provide multiple formats (MP4, WebM)
  • Use poster images to reduce bandwidth
  • Always include poster images
  • Provide clear play button indicators
  • Ensure videos are responsive
  • Test playback on mobile devices
  • Lazy load video thumbnails
  • Don’t autoplay videos
  • Use CDN for video hosting
  • Consider YouTube/Vimeo for large videos
  • Provide video transcripts
  • Include captions/subtitles
  • Use descriptive titles
  • Ensure keyboard navigation works

Troubleshooting

Video Not Playing in Popup

Check:
  1. Video URL is correctly formatted
  2. Video is publicly accessible
  3. Lightbox plugin is active
  4. Browser console for JavaScript errors

Poster Image Not Showing

Solution:
// Ensure featured image is set
if ( ! has_post_thumbnail( $post_id ) ) {
    set_post_thumbnail( $post_id, $attachment_id );
}

Videos Not Responsive

Add CSS:
.vp-portfolio__item-video {
    max-width: 100%;
    height: auto;
}

Build docs developers (and LLMs) love