The Portfolio custom post type is a specialized content type designed for managing portfolio projects in Visual Portfolio. It provides a complete portfolio management system with categories, tags, and custom metadata.
Overview
The Portfolio post type is registered in /classes/class-custom-post-type.php:122-227 and includes:
- Custom taxonomies (Categories and Tags)
- Featured images
- Post formats support
- Custom meta fields
- Archive pages
- User roles and capabilities
The Portfolio post type can be disabled in Visual Portfolio settings if you prefer to use your own custom post types.
Post Type Registration
The Portfolio post type is registered with these parameters:
register_post_type('portfolio', array(
'labels' => array(
'name' => 'Portfolio',
'singular_name' => 'Project',
'menu_name' => 'Visual Portfolio',
),
'public' => true,
'publicly_queryable' => true,
'has_archive' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_admin_bar' => true,
'show_in_rest' => true, // Gutenberg support
'menu_icon' => 'dashicons-visual-portfolio',
'capability_type' => 'portfolio',
'map_meta_cap' => true,
'supports' => array(
'title',
'editor',
'author',
'thumbnail',
'comments',
'revisions',
'excerpt',
'post-formats',
'page-attributes',
'custom-fields',
),
));
Taxonomies
Portfolio Categories
Hierarchical taxonomy for organizing projects:
register_taxonomy('portfolio_category', 'portfolio', array(
'hierarchical' => true,
'publicly_queryable' => true,
'show_in_nav_menus' => true,
'show_in_rest' => true,
'show_admin_column' => true,
'rewrite' => array(
'slug' => 'portfolio-category',
),
));
Usage in queries:
'content_source' => 'post-based',
'posts_source' => 'portfolio',
'posts_taxonomies' => array(
'portfolio_category' => array(5, 10, 15) // Category IDs
)
Portfolio Tags
Non-hierarchical taxonomy for flexible classification:
register_taxonomy('portfolio_tag', 'portfolio', array(
'hierarchical' => false,
'publicly_queryable' => true,
'show_in_nav_menus' => true,
'show_in_rest' => true,
'show_admin_column' => true,
'rewrite' => array(
'slug' => 'portfolio-tag',
),
));
Archive Configuration
Portfolio archives are managed through Visual Portfolio settings:
Archive Page
Designate a WordPress page as your portfolio archive:
$archive_page = Visual_Portfolio_Settings::get_option(
'portfolio_archive_page',
'vp_general'
);
This page becomes the portfolio index and affects:
- Archive URL structure
- Breadcrumb navigation
- Portfolio menu links
Permalink Structure
Customize portfolio URLs:
$permalinks = Visual_Portfolio_Archive_Mapping::get_permalink_structure(true);
// Default structure:
array(
'portfolio_base' => 'portfolio', // Single project: /portfolio/project-name
'category_base' => 'portfolio-category', // Category: /portfolio-category/design
'tag_base' => 'portfolio-tag', // Tag: /portfolio-tag/featured
)
Custom Meta Fields
Video Format URL
Store video URLs for video format posts:
// Set video URL
Visual_Portfolio_Custom_Post_Meta::set_video_format_url(
$post_id,
'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
);
// Get video URL
$video_url = Visual_Portfolio_Custom_Post_Meta::get_video_format_url($post_id);
Usage in queries:
From /classes/class-get-portfolio.php:763-768:
if ('video' === $args['format']) {
$video_url = Visual_Portfolio_Custom_Post_Meta::get_video_format_url(get_the_ID());
if ($video_url) {
$args['video'] = $video_url;
$args['allow_popup'] = true;
}
}
Featured Image Focal Point
Control image crop positioning:
// Set focal point
Visual_Portfolio_Custom_Post_Meta::set_featured_image_focal_point(
$post_id,
array('x' => 0.5, 'y' => 0.3)
);
// Get focal point
$focal_point = Visual_Portfolio_Custom_Post_Meta::get_featured_image_focal_point($post_id);
From /classes/class-get-portfolio.php:739:
'focal_point' => Visual_Portfolio_Custom_Post_Meta::get_featured_image_focal_point(
get_the_ID()
),
Views Count
Track project views:
$views = Visual_Portfolio_Custom_Post_Meta::get_views_count($post_id);
Reading Time
Display estimated reading time:
$reading_time = Visual_Portfolio_Custom_Post_Meta::get_reading_time($post_id);
From /classes/class-get-portfolio.php:744:
'reading_time' => Visual_Portfolio_Custom_Post_Meta::get_reading_time(get_the_ID()),
User Roles and Capabilities
Visual Portfolio adds custom roles for portfolio management:
Portfolio Manager
Full access to portfolios and saved layouts:
$portfolio_cap = array(
'read_portfolio',
'edit_portfolios',
'edit_others_portfolios',
'publish_portfolios',
'delete_portfolios',
'manage_portfolio_terms',
);
Portfolio Author
Manage own portfolio items:
$wp_roles->add_role('portfolio_author', 'Portfolio Author', $author->capabilities);
Querying Portfolio Items
Basic Query
array(
'content_source' => 'post-based',
'posts_source' => 'portfolio',
'items_count' => 12,
'posts_order_by' => 'post_date',
'posts_order_direction' => 'desc'
)
Filtered by Category
array(
'content_source' => 'post-based',
'posts_source' => 'portfolio',
'posts_taxonomies' => array(
'portfolio_category' => array(5, 10) // Web Design, Branding
),
'posts_taxonomies_relation' => 'or'
)
Featured Projects
array(
'content_source' => 'post-based',
'posts_source' => 'portfolio',
'posts_taxonomies' => array(
'portfolio_tag' => array(15) // Featured tag
),
'posts_order_by' => 'menu_order'
)
Recent Projects with Videos
Display only video format projects:
$query = new WP_Query(array(
'post_type' => 'portfolio',
'posts_per_page' => 6,
'tax_query' => array(
array(
'taxonomy' => 'post_format',
'field' => 'slug',
'terms' => 'post-format-video',
),
),
));
Admin Customization
Custom Columns
Portfolio list shows thumbnail column:
// Add thumbnail column
add_filter('manage_portfolio_posts_columns', function($columns) {
$column_meta = array(
'portfolio_post_thumbs' => 'Thumbnail',
);
return array_slice($columns, 0, 1, true) +
$column_meta +
array_slice($columns, 1, null, true);
});
Taxonomy Filters
Filter portfolio items by category and tag in admin:
add_action('restrict_manage_posts', function($post_type) {
if ('portfolio' !== $post_type) return;
// Category dropdown
$taxonomy_obj = get_taxonomy('portfolio_category');
$terms = get_terms('portfolio_category');
// Render select dropdown
});
Item Data Structure
When queried, portfolio items return this data structure (from /classes/class-get-portfolio.php:727-746):
$args = array(
'uid' => hash('crc32b', 'post-' . get_the_ID()),
'post_id' => get_the_ID(),
'url' => get_permalink(),
'title' => get_the_title(),
'content' => get_the_content(),
'excerpt' => get_the_excerpt(),
'format' => get_post_format() ?: 'standard',
'published_time' => get_the_date('Y-m-d H:i:s'),
'filter' => implode(',', $filter_values),
'image_id' => get_post_thumbnail_id(),
'focal_point' => get_featured_image_focal_point(),
'categories' => $categories, // Array of category objects
'comments_count' => get_comments_number(),
'comments_url' => get_comments_link(),
'views_count' => get_views_count(),
'reading_time' => get_reading_time(),
'author' => get_the_author(),
'author_url' => get_author_posts_url(),
'author_avatar' => get_avatar_url(),
);
Filter Taxonomies
Control which taxonomies appear in Visual Portfolio filters:
add_filter('vpf_allow_taxonomy_for_filter', function($allowed, $taxonomy) {
// Allow custom taxonomy
if ('my_custom_taxonomy' === $taxonomy) {
return true;
}
return $allowed;
}, 10, 2);
Default allowed taxonomies (from /classes/class-get-portfolio.php:233-241):
- Any taxonomy with “category” in the name
jetpack-portfolio-type
product_cat (WooCommerce)
- Custom taxonomies defined in settings
Settings Configuration
Enable/Disable Portfolio Post Type
Visual_Portfolio_Settings::update_option(
'register_portfolio_post_type',
true, // or false
'vp_general'
);
Custom Filter Taxonomies
Add taxonomies to filter support:
Visual_Portfolio_Settings::update_option(
'filter_taxonomies',
'my_taxonomy,another_taxonomy',
'vp_general'
);
Migration and Compatibility
Visual Portfolio includes migration code for legacy versions (from /classes/class-migration.php:150-152):
// Convert old 'portfolio' source to 'post-based'
if ('portfolio' === get_post_meta($post->ID, 'vp_content_source', true)) {
update_post_meta($post->ID, 'vp_content_source', 'post-based');
update_post_meta($post->ID, 'vp_posts_source', 'portfolio');
}
Example Implementations
Portfolio Archive with Custom Query
array(
'content_source' => 'post-based',
'posts_source' => 'current_query', // Use current archive query
'layout_elements' => array(
'top' => array(
'elements' => array('filter'),
'align' => 'center'
),
'bottom' => array(
'elements' => array('pagination'),
'align' => 'center'
)
)
)
Related Projects
// Get current post categories
$categories = wp_get_post_terms(get_the_ID(), 'portfolio_category', array('fields' => 'ids'));
// Query related projects
array(
'content_source' => 'post-based',
'posts_source' => 'portfolio',
'posts_taxonomies' => array(
'portfolio_category' => $categories
),
'posts_excluded_ids' => array(get_the_ID()),
'items_count' => 3
)
Related Resources