Skip to main content
Visual Portfolio provides multiple ways to customize layouts: CSS variables, WordPress hooks, custom templates, and JavaScript events. This guide covers all customization methods.

Customization Methods

Visual Portfolio offers four primary customization approaches:
  1. CSS Variables - Quick styling changes
  2. WordPress Hooks - Modify behavior and output
  3. Custom Templates - Override default templates
  4. JavaScript Events - Extend JavaScript functionality

CSS Customization

CSS Variables

Visual Portfolio uses CSS custom properties for easy styling:
/* Override portfolio variables */
.vp-portfolio {
  /* Gap between items */
  --vp-items-gap: 20px;
  
  /* Item styles */
  --vp-item-background: #fff;
  --vp-item-border-radius: 8px;
  
  /* Overlay styles */
  --vp-overlay-background: rgba(0, 0, 0, 0.8);
  --vp-overlay-color: #fff;
  
  /* Typography */
  --vp-title-font-size: 20px;
  --vp-title-color: #333;
  
  /* Animations */
  --vp-transition-duration: 0.3s;
  --vp-transition-timing: ease-in-out;
}

Layout-Specific Variables

Slider Layout

.vp-portfolio[data-vp-layout="slider"] {
  --vp-layout-slider--auto-items__height: 400px;
  --vp-slider-navigation-size: 50px;
  --vp-slider-navigation-color: #fff;
  --vp-slider-bullets-color: #333;
}

Grid and Masonry

.vp-portfolio[data-vp-layout="grid"],
.vp-portfolio[data-vp-layout="masonry"] {
  --vp-grid-columns: 3;
  --vp-grid-gap: 20px;
}

Custom CSS Classes

Add custom classes to portfolio blocks:
[visual_portfolio 
  layout="grid"
  class="my-custom-portfolio"
]
Then style with CSS:
.my-custom-portfolio .vp-portfolio__item {
  border: 2px solid #ddd;
  border-radius: 10px;
}

.my-custom-portfolio .vp-portfolio__item-img {
  filter: grayscale(100%);
  transition: filter 0.3s;
}

.my-custom-portfolio .vp-portfolio__item:hover .vp-portfolio__item-img {
  filter: grayscale(0%);
}

WordPress Hooks

Filter Hooks

Modify Layout Options

// Add custom layout option
add_filter('vpf_registered_layouts', function($layouts) {
  $layouts['custom-layout'] = array(
    'title' => 'Custom Layout',
    'description' => 'My custom layout',
    'controls' => array(
      // Layout controls
    ),
  );
  return $layouts;
});

Modify Item Output

// Filter item classes
add_filter('vpf_each_item_classes', function($classes, $args, $opts) {
  if ($args['featured']) {
    $classes[] = 'featured-item';
  }
  return $classes;
}, 10, 3);

Customize Item Meta

// Add custom meta data
add_filter('vpf_each_item_args', function($args, $opts) {
  $args['custom_field'] = get_post_meta($args['id'], 'custom_field', true);
  return $args;
}, 10, 2);

Action Hooks

Before/After Portfolio

// Add content before portfolio
add_action('vpf_before_portfolio', function($opts) {
  echo '<div class="custom-intro">Featured Work</div>';
});

// Add content after portfolio
add_action('vpf_after_portfolio', function($opts) {
  echo '<div class="custom-footer">View all work →</div>';
});

Enqueue Custom Assets

// Enqueue custom stylesheet
add_action('wp_enqueue_scripts', function() {
  if (has_block('visual-portfolio/block')) {
    wp_enqueue_style(
      'my-portfolio-custom',
      get_stylesheet_directory_uri() . '/portfolio-custom.css'
    );
  }
});

Custom Templates

Template Hierarchy

Visual Portfolio follows WordPress template hierarchy:
theme/visual-portfolio/
├── items-list/
│   ├── layouts/
│   │   └── slider/
│   │       ├── arrows.php
│   │       ├── bullets.php
│   │       └── thumbnails.php
│   ├── items-style/
│   │   ├── fade/
│   │   │   ├── image.php
│   │   │   └── meta.php
│   │   ├── image.php
│   │   └── meta.php
│   └── item-parts/
│       ├── title.php
│       ├── excerpt.php
│       └── meta-categories.php
└── global/
    ├── link-start.php
    └── link-end.php

Override Templates

  1. Create directory: wp-content/themes/your-theme/visual-portfolio/
  2. Copy template from plugin to theme
  3. Modify as needed
Example: Custom Title Template Create: theme/visual-portfolio/items-list/item-parts/title.php
<?php
if (!defined('ABSPATH')) {
  exit;
}

if ($opts['show_title'] && $args['title']) : ?>
  <h3 class="vp-portfolio__item-title custom-title">
    <?php
    if ($allow_links) {
      visual_portfolio()->include_template('global/link-start', array(
        'href' => $args['url'],
        'class' => 'vp-portfolio__item-title-link',
      ));
    }
    
    echo esc_html($args['title']);
    
    // Add custom icon
    echo ' <span class="custom-icon">★</span>';
    
    if ($allow_links) {
      visual_portfolio()->include_template('global/link-end');
    }
    ?>
  </h3>
<?php endif; ?>

JavaScript Customization

JavaScript Events

Visual Portfolio triggers jQuery events for customization:
import $ from 'jquery';

// Hook into initialization
$(document).on('initOptions.vpf', (event, self) => {
  if (event.namespace !== 'vpf') return;
  
  // Modify options before initialization
  console.log('Portfolio options:', self.options);
});

// Hook into layout initialization
$(document).on('initLayout.vpf', (event, self) => {
  if (event.namespace !== 'vpf') return;
  
  if (self.options.layout === 'grid') {
    // Custom grid modifications
    self.addStyle('.vp-portfolio__item-wrap', {
      border: '2px solid #ddd',
    });
  }
});

// After items loaded
$(document).on('afterInitItems.vpf', (event, self) => {
  if (event.namespace !== 'vpf') return;
  
  console.log('Items loaded:', self.items.length);
});

// Before Isotope initialization
$(document).on('beforeInitIsotope.vpf', (event, self, initOptions) => {
  if (event.namespace !== 'vpf') return;
  
  // Modify Isotope options
  initOptions.transitionDuration = '0.5s';
});

// After Isotope initialization
$(document).on('afterInitIsotope.vpf', (event, self) => {
  if (event.namespace !== 'vpf') return;
  
  console.log('Isotope initialized');
});

Extend VP Class

// Add custom methods to VP class
$(document).on('extendClass.vpf', (event, VP) => {
  if (event.namespace !== 'vpf') return;
  
  // Add custom method
  VP.prototype.customMethod = function() {
    const self = this;
    console.log('Custom method called on', self.options.layout);
  };
});

Access VP Instance

// Access portfolio instance
const $portfolio = $('.vp-portfolio');
if ($portfolio.length && $portfolio[0].vpf) {
  const vpInstance = $portfolio[0].vpf;
  
  // Call methods
  vpInstance.customMethod();
  
  // Access options
  console.log(vpInstance.options);
  
  // Refresh layout
  vpInstance.isotope.layout();
}

Advanced Customization Examples

Custom Grid Columns Based on Screen Size

$(document).on('initLayout.vpf', (event, self) => {
  if (self.options.layout !== 'grid') return;
  
  // Custom breakpoints
  const breakpoints = [
    { width: 1920, columns: 6 },
    { width: 1440, columns: 5 },
    { width: 1024, columns: 4 },
    { width: 768, columns: 3 },
    { width: 480, columns: 2 },
  ];
  
  breakpoints.forEach(bp => {
    self.addStyle('.vp-portfolio__item-wrap', {
      width: `${100 / bp.columns}%`,
    }, `screen and (max-width: ${bp.width}px)`);
  });
});

Add Custom Loading Animation

// Add loading HTML
add_action('vpf_before_portfolio', function($opts) {
  echo '<div class="custom-loader"><div class="spinner"></div></div>';
});
/* Loading animation */
.custom-loader {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 100;
}

.vp-portfolio.vp-loaded .custom-loader {
  display: none;
}

.spinner {
  width: 50px;
  height: 50px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #333;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

Custom Filter Integration

// Custom filter behavior
$(document).on('click', '.custom-filter-button', function() {
  const filter = $(this).data('filter');
  const $portfolio = $('.vp-portfolio');
  
  if ($portfolio.length && $portfolio[0].vpf) {
    const vpInstance = $portfolio[0].vpf;
    
    // Apply filter
    if (vpInstance.isotope) {
      vpInstance.isotope.arrange({
        filter: filter === '*' ? '*' : `.filter-${filter}`,
      });
    }
  }
});

Best Practices

  • Use CSS variables for easy theme switching
  • Avoid !important unless absolutely necessary
  • Test responsive behavior
  • Use browser dev tools for debugging
  • Keep overrides minimal and maintainable
  • Document your changes
  • Test after plugin updates
  • Use child themes for changes
  • Always check event.namespace === ‘vpf’
  • Use early returns for better performance
  • Test thoroughly before deployment
  • Avoid blocking operations
  • Minimize custom JavaScript
  • Optimize custom CSS
  • Test with many items
  • Monitor console for errors

Common Customization Scenarios

Change Default Columns

add_filter('vpf_default_options', function($defaults) {
  $defaults['gridColumns'] = 4;
  $defaults['masonryColumns'] = 4;
  return $defaults;
});

Add Custom Item Classes

add_filter('vpf_each_item_classes', function($classes, $args, $opts) {
  // Add category classes
  if (!empty($args['categories'])) {
    foreach ($args['categories'] as $cat) {
      $classes[] = 'category-' . $cat['slug'];
    }
  }
  return $classes;
}, 10, 3);

Modify Image Sizes

add_filter('vpf_each_item_image_size', function($size, $args, $opts) {
  // Use larger images for featured items
  if ($args['featured']) {
    return 'large';
  }
  return $size;
}, 10, 3);

Debugging

Enable Debug Mode

// Log all VPF events
$(document).on('*.vpf', (event) => {
  console.log('VPF Event:', event.type, event);
});

Check Portfolio Instance

const $portfolio = $('.vp-portfolio');
if ($portfolio.length) {
  console.log('Portfolio found:', $portfolio[0].vpf);
  console.log('Options:', $portfolio[0].vpf.options);
  console.log('Items:', $portfolio[0].vpf.items);
} else {
  console.log('No portfolio found');
}

Further Reading

Hooks & Filters

Complete list of WordPress hooks

Custom Templates

Template override guide

JavaScript API

JavaScript methods and events

CSS Variables

Complete CSS variables reference

Source Code Reference

  • JavaScript Events: assets/js/layout-*.js
  • Template Loading: classes/class-templates.php
  • Hook System: classes/class-visual-portfolio.php
  • CSS Variables: templates/items-list/items-style/_variables.scss:1

Build docs developers (and LLMs) love