Skip to main content
Visual Portfolio provides extensive hooks and filters to customize and extend the plugin functionality. All hooks are prefixed with vpf_ to avoid conflicts.

Core Actions

Portfolio Output

vpf_before_get_output

Fires before portfolio output is generated.
do_action( 'vpf_before_get_output', $options );
Parameters:
  • $options (array) - Portfolio configuration options
Example:
add_action( 'vpf_before_get_output', function( $options ) {
    // Custom logic before portfolio renders
    error_log( 'Rendering portfolio ID: ' . $options['id'] );
}, 10, 1 );

vpf_after_get_output

Fires after portfolio output is generated.
do_action( 'vpf_after_get_output', $options, $style_options );
Parameters:
  • $options (array) - Portfolio configuration options
  • $style_options (array) - Item style specific options

Wrapper Actions

vpf_before_wrapper_start

Fires before the portfolio wrapper opens.
do_action( 'vpf_before_wrapper_start', $options, $style_options );

vpf_after_wrapper_start

Fires after the portfolio wrapper opens.
do_action( 'vpf_after_wrapper_start', $options, $style_options );

vpf_before_wrapper_end

Fires before the portfolio wrapper closes.
do_action( 'vpf_before_wrapper_end', $options, $style_options );

vpf_after_wrapper_end

Fires after the portfolio wrapper closes.
do_action( 'vpf_after_wrapper_end', $options, $style_options );

Items Wrapper Actions

vpf_before_items_wrapper_start

Fires before the items wrapper opens.
do_action( 'vpf_before_items_wrapper_start', $options, $style_options );

vpf_after_items_wrapper_start

Fires after the items wrapper opens.
do_action( 'vpf_after_items_wrapper_start', $options, $style_options );

vpf_before_items_wrapper_end

Fires before the items wrapper closes.
do_action( 'vpf_before_items_wrapper_end', $options, $style_options );

vpf_after_items_wrapper_end

Fires after the items wrapper closes.
do_action( 'vpf_after_items_wrapper_end', $options, $style_options );

Each Item Actions

vpf_before_each_item

Fires before each portfolio item is rendered.
do_action( 'vpf_before_each_item', $args );
Parameters:
  • $args (array) - Item arguments including post_id, url, title, image_id, etc.

vpf_each_item_start

Fires at the start of each item’s inner content.
do_action( 'vpf_each_item_start', $args );

vpf_each_item_end

Fires at the end of each item’s inner content.
do_action( 'vpf_each_item_end', $args );

vpf_after_each_item

Fires after each portfolio item is rendered.
do_action( 'vpf_after_each_item', $args );

Asset Actions

vpf_before_assets_enqueue

Fires before portfolio assets are enqueued.
do_action( 'vpf_before_assets_enqueue', $options, $layout_id );
Example:
add_action( 'vpf_before_assets_enqueue', function( $options, $layout_id ) {
    // Enqueue custom styles for specific layout
    if ( $layout_id === 123 ) {
        wp_enqueue_style( 'my-custom-portfolio-style' );
    }
}, 10, 2 );

vpf_after_assets_enqueue

Fires after portfolio assets are enqueued.
do_action( 'vpf_after_assets_enqueue', $options, $layout_id );

vpf_before_assets_register

Fires before assets are registered.
do_action( 'vpf_before_assets_register' );

vpf_after_assets_register

Fires after assets are registered.
do_action( 'vpf_after_assets_register' );

Core Filters

Layout & Items Style Registration

vpf_extend_layouts

Register custom portfolio layouts.
$layouts = apply_filters( 'vpf_extend_layouts', array() );
Example:
add_filter( 'vpf_extend_layouts', function( $layouts ) {
    $layouts['custom_layout'] = array(
        'title'    => __( 'Custom Layout', 'text-domain' ),
        'icon'     => '<svg>...</svg>',
        'controls' => array(
            array(
                'type'    => 'number',
                'label'   => __( 'Columns', 'text-domain' ),
                'name'    => 'custom_layout_columns',
                'default' => 3,
                'min'     => 1,
                'max'     => 6,
            ),
        ),
    );
    return $layouts;
}, 10 );

vpf_extend_layout__controls

Extend specific layout controls.
$controls = apply_filters( 'vpf_extend_layout_masonry_controls', $controls );
Example:
add_filter( 'vpf_extend_layout_masonry_controls', function( $controls ) {
    $controls[] = array(
        'type'    => 'checkbox',
        'label'   => __( 'Custom Option', 'text-domain' ),
        'name'    => 'masonry_custom_option',
        'default' => false,
    );
    return $controls;
}, 10 );

vpf_extend_items_styles

Register custom item styles.
$items_styles = apply_filters( 'vpf_extend_items_styles', array() );
Example:
add_filter( 'vpf_extend_items_styles', function( $items_styles ) {
    $items_styles['custom_style'] = array(
        'title'            => __( 'Custom Style', 'text-domain' ),
        'builtin_controls' => array(
            'show_title'      => true,
            'show_categories' => true,
            'show_date'       => true,
            'show_excerpt'    => true,
        ),
        'controls'         => array(
            array(
                'type'    => 'color',
                'label'   => __( 'Overlay Color', 'text-domain' ),
                'name'    => 'items_style_custom_style__overlay_color',
                'default' => '#000000',
            ),
        ),
    );
    return $items_styles;
}, 10 );

vpf_extend_item_style__controls

Extend specific item style controls.
$controls = apply_filters( 'vpf_extend_item_style_fade_controls', $controls );

Template Filters

vpf_include_template

Filter template file path.
$template = apply_filters( 'vpf_include_template', $template, $template_name, $args );
Parameters:
  • $template (string) - Resolved template file path
  • $template_name (string) - Template name requested
  • $args (array) - Template arguments
Example:
add_filter( 'vpf_include_template', function( $template, $template_name, $args ) {
    // Override specific template
    if ( $template_name === 'items-list/items-style/fade/meta' ) {
        $custom_template = get_stylesheet_directory() . '/vp-templates/custom-meta.php';
        if ( file_exists( $custom_template ) ) {
            return $custom_template;
        }
    }
    return $template;
}, 10, 3 );

vpf_include_template_args

Filter template arguments before template is included.
$args = apply_filters( 'vpf_include_template_args', $args, $template_name );
Example:
add_filter( 'vpf_include_template_args', function( $args, $template_name ) {
    // Modify template arguments
    if ( $template_name === 'items-list/item-parts/title' ) {
        $args['custom_data'] = 'Custom value';
    }
    return $args;
}, 10, 2 );

vpf_allowed_template_dirs

Filter allowed template directories for security.
$allowed_dirs = apply_filters( 'vpf_allowed_template_dirs', $allowed_dirs, $real_path );
Example:
add_filter( 'vpf_allowed_template_dirs', function( $allowed_dirs, $real_path ) {
    // Add custom plugin template directory
    $allowed_dirs[] = MY_PLUGIN_PATH . 'templates/';
    return $allowed_dirs;
}, 10, 2 );

vpf_include_template_style

Filter template style file path.
$path = apply_filters( 'vpf_include_template_style', $path, $template_name, $deps, $ver, $media );

Options & Configuration

vpf_get_options

Filter portfolio options.
$options = apply_filters( 'vpf_get_options', $options, $atts );
Example:
add_filter( 'vpf_get_options', function( $options, $atts ) {
    // Modify portfolio options
    if ( isset( $options['id'] ) && $options['id'] === 123 ) {
        $options['items_gap'] = 20;
    }
    return $options;
}, 10, 2 );

vpf_extend_options_before_query_args

Filter options before query arguments are built.
$options = apply_filters( 'vpf_extend_options_before_query_args', $options, $layout_id );

vpf_extend_query_args

Filter WP_Query arguments.
$query_opts = apply_filters( 'vpf_extend_query_args', $query_opts, $options, $layout_id );
Example:
add_filter( 'vpf_extend_query_args', function( $query_opts, $options, $layout_id ) {
    // Modify query arguments
    if ( $layout_id === 123 ) {
        $query_opts['meta_query'] = array(
            array(
                'key'     => 'featured',
                'value'   => '1',
                'compare' => '=',
            ),
        );
    }
    return $query_opts;
}, 10, 3 );

Custom Output

vpf_custom_output

Replace entire portfolio output.
$custom_output = apply_filters( 'vpf_custom_output', false, $uid, $class, $options );
Example:
add_filter( 'vpf_custom_output', function( $custom_output, $uid, $class, $options ) {
    // Return custom output for password protected portfolios
    if ( post_password_required( $options['id'] ) ) {
        return get_the_password_form( $options['id'] );
    }
    return $custom_output;
}, 10, 4 );

vpf_custom_query_result

Provide custom query result object for non-standard content sources.
$custom_query = apply_filters( 'vpf_custom_query_result', false, $query_opts, $options );
Example:
add_filter( 'vpf_custom_query_result', function( $custom_query, $query_opts, $options ) {
    if ( $options['content_source'] === 'custom_api' ) {
        // Return custom query-like object
        return new Custom_Portfolio_Query( $query_opts );
    }
    return $custom_query;
}, 10, 3 );

vpf_custom_items

Provide custom items array for non-standard content sources.
$custom_items = apply_filters( 'vpf_custom_items', false, $each_item_args, $query_opts, $options );
Example:
add_filter( 'vpf_custom_items', function( $custom_items, $item_args, $query_opts, $options ) {
    if ( $options['content_source'] === 'custom_api' ) {
        $api_items = fetch_from_custom_api();
        $items = array();
        
        foreach ( $api_items as $api_item ) {
            $items[] = array_merge( $item_args, array(
                'uid'      => $api_item['id'],
                'title'    => $api_item['title'],
                'url'      => $api_item['link'],
                'image_id' => $api_item['image_id'],
            ) );
        }
        
        return $items;
    }
    return $custom_items;
}, 10, 4 );

Item Arguments

vpf_each_item_args

Filter item arguments before rendering.
$args = apply_filters( 'vpf_each_item_args', $args );
Example:
add_filter( 'vpf_each_item_args', function( $args ) {
    // Add custom data to each item
    if ( $args['post_id'] ) {
        $args['custom_field'] = get_post_meta( $args['post_id'], 'custom_field', true );
    }
    return $args;
}, 10 );

vpf_post_item_args

Filter post-based item arguments.
$args = apply_filters( 'vpf_post_item_args', $args, $post_id );

vpf_image_item_args

Filter image-based item arguments.
$args = apply_filters( 'vpf_image_item_args', $args, $img );

vpf_each_item_tag_name

Filter item wrapper tag name.
$tag_name = apply_filters( 'vpf_each_item_tag_name', $tag_name, $args );
Example:
add_filter( 'vpf_each_item_tag_name', function( $tag_name, $args ) {
    // Use article tag for blog posts
    if ( isset( $args['post_id'] ) && get_post_type( $args['post_id'] ) === 'post' ) {
        return 'article';
    }
    return $tag_name;
}, 10, 2 );

vpf_each_item_tag_attrs

Filter item wrapper tag attributes.
$attrs = apply_filters( 'vpf_each_item_tag_attrs', $attrs, $args );
Example:
add_filter( 'vpf_each_item_tag_attrs', function( $attrs, $args ) {
    // Add custom data attribute
    if ( isset( $args['post_id'] ) ) {
        $attrs['data-post-type'] = get_post_type( $args['post_id'] );
    }
    return $attrs;
}, 10, 2 );

Data Attributes & Classes

vpf_extend_portfolio_data_attributes

Filter portfolio wrapper data attributes.
$data_attrs = apply_filters( 'vpf_extend_portfolio_data_attributes', $data_attrs, $options, $style_options );
Example:
add_filter( 'vpf_extend_portfolio_data_attributes', function( $data_attrs, $options, $style_options ) {
    // Add custom data attribute
    $data_attrs['data-custom-attr'] = 'custom-value';
    return $data_attrs;
}, 10, 3 );

vpf_extend_portfolio_class

Filter portfolio wrapper CSS classes.
$class = apply_filters( 'vpf_extend_portfolio_class', $class, $options, $style_options );
Example:
add_filter( 'vpf_extend_portfolio_class', function( $class, $options, $style_options ) {
    // Add custom class
    if ( $options['layout'] === 'masonry' ) {
        $class .= ' custom-masonry-class';
    }
    return $class;
}, 10, 3 );

vpf_extend_portfolio_items_class

Filter portfolio items wrapper CSS classes.
$items_class = apply_filters( 'vpf_extend_portfolio_items_class', $items_class, $options, $style_options );

Filter & Sort

vpf_allow_taxonomy_for_filter

Determine if taxonomy should be available in filter.
$allowed = apply_filters( 'vpf_allow_taxonomy_for_filter', $default_allowed, $taxonomy );
Example:
add_filter( 'vpf_allow_taxonomy_for_filter', function( $allowed, $taxonomy ) {
    // Allow custom taxonomy in filter
    if ( $taxonomy === 'custom_taxonomy' ) {
        return true;
    }
    return $allowed;
}, 10, 2 );

vpf_custom_filter_terms

Provide custom filter terms.
$terms = apply_filters( 'vpf_custom_filter_terms', false, $query_opts, $active_item, $vp_options );

vpf_extend_filter_items

Filter the filter items array.
$items = apply_filters( 'vpf_extend_filter_items', $items, $vp_options );

vpf_popup_output

Filter popup gallery data output.
$popup_output = apply_filters( 'vpf_popup_output', $popup_output, $args );

vpf_popup_custom_image_data

Provide custom popup image data.
$popup_image = apply_filters( 'vpf_popup_custom_image_data', false, $image_id );

Lazy Loading

vpf_images_lazyload

Enable or disable lazy loading.
$lazyload = apply_filters( 'vpf_images_lazyload', true );
Example:
add_filter( 'vpf_images_lazyload', function( $lazyload ) {
    // Disable lazy loading on specific pages
    if ( is_front_page() ) {
        return false;
    }
    return $lazyload;
}, 10 );

vpf_lazyload_images_blocked_classes

Filter CSS classes that should prevent lazy loading.
$blocked_classes = apply_filters( 'vpf_lazyload_images_blocked_classes', $blocked_classes );

vpf_lazyload_images_blocked_src

Filter image sources that should prevent lazy loading.
$blocked_src = apply_filters( 'vpf_lazyload_images_blocked_src', $blocked_src );

Controls & Settings

vpf_register_control

Filter control arguments when registering.
$args = apply_filters( 'vpf_register_control', $args, $name );

vpf_registered_controls

Filter all registered controls.
$controls = apply_filters( 'vpf_registered_controls', $controls );

vpf_control_value

Filter control value when retrieved.
$value = apply_filters( 'vpf_control_value', $value, $name, $post_id );
Example:
add_filter( 'vpf_control_value', function( $value, $name, $post_id ) {
    // Modify specific control value
    if ( $name === 'items_gap' && $post_id === 123 ) {
        return 30;
    }
    return $value;
}, 10, 3 );

Breakpoints

vpf_breakpoint_xs

Filter extra small breakpoint value.
$breakpoint = apply_filters( 'vpf_breakpoint_xs', 576 );

vpf_breakpoint_sm

Filter small breakpoint value.
$breakpoint = apply_filters( 'vpf_breakpoint_sm', 768 );

vpf_breakpoint_md

Filter medium breakpoint value.
$breakpoint = apply_filters( 'vpf_breakpoint_md', 992 );

vpf_breakpoint_lg

Filter large breakpoint value.
$breakpoint = apply_filters( 'vpf_breakpoint_lg', 1200 );

vpf_breakpoint_xl

Filter extra large breakpoint value.
$breakpoint = apply_filters( 'vpf_breakpoint_xl', 1400 );

Plugin Assets

vpf_enqueue_plugin_isotope

Control Isotope library enqueue.
$enqueue = apply_filters( 'vpf_enqueue_plugin_isotope', true );

vpf_enqueue_plugin_photoswipe

Control PhotoSwipe library enqueue.
$enqueue = apply_filters( 'vpf_enqueue_plugin_photoswipe', true );

vpf_enqueue_plugin_fancybox

Control Fancybox library enqueue.
$enqueue = apply_filters( 'vpf_enqueue_plugin_fancybox', true );

vpf_enqueue_plugin_swiper

Control Swiper library enqueue.
$enqueue = apply_filters( 'vpf_enqueue_plugin_swiper', true );

Common Use Cases

Adding Custom Portfolio Layout

add_filter( 'vpf_extend_layouts', function( $layouts ) {
    $layouts['custom_carousel'] = array(
        'title'    => __( 'Custom Carousel', 'text-domain' ),
        'icon'     => '<svg width="20" height="20">...</svg>',
        'controls' => array(
            array(
                'type'    => 'number',
                'label'   => __( 'Slides Per View', 'text-domain' ),
                'name'    => 'custom_carousel_slides',
                'default' => 3,
                'min'     => 1,
                'max'     => 10,
            ),
            array(
                'type'    => 'checkbox',
                'label'   => __( 'Auto Play', 'text-domain' ),
                'name'    => 'custom_carousel_autoplay',
                'default' => true,
            ),
        ),
    );
    return $layouts;
}, 10 );

Modifying Item Output

// Add custom field to item args
add_filter( 'vpf_post_item_args', function( $args, $post_id ) {
    $args['rating'] = get_post_meta( $post_id, 'product_rating', true );
    return $args;
}, 10, 2 );

// Display custom field in template
add_action( 'vpf_each_item_end', function( $args ) {
    if ( ! empty( $args['rating'] ) ) {
        echo '<div class="custom-rating">' . esc_html( $args['rating'] ) . '</div>';
    }
}, 10 );

Custom Content Source

// Provide custom query
add_filter( 'vpf_custom_query_result', function( $custom_query, $query_opts, $options ) {
    if ( $options['content_source'] === 'woocommerce_products' ) {
        $query_opts['post_type'] = 'product';
        return new WP_Query( $query_opts );
    }
    return $custom_query;
}, 10, 3 );

// Modify custom items
add_filter( 'vpf_post_item_args', function( $args, $post_id ) {
    if ( get_post_type( $post_id ) === 'product' ) {
        $product = wc_get_product( $post_id );
        $args['price'] = $product->get_price_html();
    }
    return $args;
}, 10, 2 );

Override Template Location

add_filter( 'vpf_include_template', function( $template, $template_name, $args ) {
    // Check custom location first
    $custom_template = get_stylesheet_directory() . '/visual-portfolio-templates/' . $template_name . '.php';
    
    if ( file_exists( $custom_template ) ) {
        return $custom_template;
    }
    
    return $template;
}, 10, 3 );

Best Practices

  1. Always check parameters - Verify options and IDs before modifying data
  2. Return original value - Always return the original value if your conditions aren’t met
  3. Use appropriate priority - Default is 10, use lower for earlier execution
  4. Sanitize and escape - Always sanitize input and escape output for security
  5. Check dependencies - Verify required data exists before accessing it
  6. Use namespacing - Prefix your function names to avoid conflicts
  7. Document your code - Add comments explaining custom logic

Security Considerations

  • Always use wp_verify_nonce() when handling form submissions
  • Sanitize user input with appropriate WordPress functions
  • Escape output using esc_html(), esc_attr(), esc_url(), etc.
  • Check user capabilities with current_user_can()
  • Validate file paths when working with templates

Build docs developers (and LLMs) love