Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nk-crew/visual-portfolio/llms.txt

Use this file to discover all available pages before exploring further.

This page documents the REST API endpoints provided by Visual Portfolio for dynamic content loading and portfolio management.

Base URL

All endpoints are prefixed with:
/wp-json/visual-portfolio/v1/
Namespace: visual-portfolio/v1

Endpoints

Get Layouts List

Retrieve a list of all saved portfolio layouts. Endpoint: GET /get_layouts/ Permission: edit_posts Response:
{
    "success": true,
    "response": [
        {
            "id": 123,
            "title": "My Portfolio",
            "edit_url": "https://example.com/wp-admin/post.php?post=123&action=edit"
        },
        {
            "id": 456,
            "title": "Image Gallery",
            "edit_url": "https://example.com/wp-admin/post.php?post=456&action=edit"
        }
    ]
}
Error Response:
{
    "error": true,
    "success": false,
    "error_code": "no_layouts_found",
    "response": "Layouts not found."
}
Example:
fetch( '/wp-json/visual-portfolio/v1/get_layouts/' )
    .then( response => response.json() )
    .then( data => {
        console.log( 'Layouts:', data.response );
    } );

Update Layout Data

Update portfolio layout configuration. Endpoint: POST /update_layout/ Permission: edit_post (for the specific post) Parameters:
  • post_id (integer, required) - Portfolio post ID
  • data (object, required) - Layout configuration data
Request Body:
{
    "post_id": 123,
    "data": {
        "vp_layout": "grid",
        "vp_items_style": "classic",
        "vp_items_gap": "30",
        "vp_items_count": "12"
    }
}
Response:
{
    "success": true,
    "response": true
}
Error Response:
{
    "error": true,
    "success": false,
    "error_code": "not_allowed",
    "response": "Sorry, you are not allowed to edit saved layouts data."
}
Example:
fetch( '/wp-json/visual-portfolio/v1/update_layout/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify( {
        post_id: 123,
        data: {
            vp_layout: 'masonry',
            vp_items_gap: '20'
        }
    } )
} )
.then( response => response.json() )
.then( data => console.log( data ) );

Get Filter Items

Retrieve filter items for a portfolio based on content source. Endpoint: POST /get_filter_items/ Permission: edit_posts Parameters:
  • content_source (string, required) - Content source type (‘post-based’, ‘images’)
  • post_id (integer, required) - Current post ID for URL generation
  • Additional parameters based on content source
For post-based content:
  • posts_source (string) - Posts source
  • post_types_set (array) - Post types to include
  • posts_taxonomies (object) - Taxonomy filters
  • posts_order_by (string) - Order by field
  • posts_order_direction (string) - Order direction
For images content:
  • images (array) - Array of image IDs
  • images_order_by (string) - Order by field
Request Body:
{
    "content_source": "post-based",
    "post_id": 789,
    "posts_source": "portfolio",
    "post_types_set": ["post", "portfolio"]
}
Response:
{
    "success": true,
    "response": [
        {
            "filter": "*",
            "label": "All",
            "description": "",
            "count": false,
            "active": true,
            "url": "https://example.com/portfolio/",
            "taxonomy": "",
            "id": 0,
            "parent": 0
        },
        {
            "filter": "15",
            "label": "Category Name",
            "description": "Category description",
            "count": 8,
            "active": false,
            "url": "https://example.com/portfolio/?vp_filter=category%3A15",
            "taxonomy": "category",
            "id": 15,
            "parent": 0
        }
    ]
}
Error Response:
{
    "error": true,
    "success": false,
    "error_code": "missing_params",
    "response": "Required parameters are missing."
}
Example:
fetch( '/wp-json/visual-portfolio/v1/get_filter_items/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify( {
        content_source: 'post-based',
        post_id: 789,
        posts_source: 'portfolio'
    } )
} )
.then( response => response.json() )
.then( data => {
    const filters = data.response;
    console.log( 'Available filters:', filters );
} );

Get Max Pages

Calculate the maximum number of pages for pagination. Endpoint: GET|POST /get-max-pages/ Permission: edit_posts Parameters:
  • content_source (string, required) - Content source type
  • items_count (integer, required) - Number of items per page
  • Additional content-specific parameters
Query String (GET):
/wp-json/visual-portfolio/v1/get-max-pages/?content_source=post-based&items_count=12&posts_source=portfolio
Request Body (POST):
{
    "content_source": "post-based",
    "items_count": 12,
    "posts_source": "portfolio",
    "post_types_set": ["post"]
}
Response:
{
    "max_pages": 5
}
Example (GET):
const params = new URLSearchParams( {
    content_source: 'post-based',
    items_count: 12,
    posts_source: 'portfolio'
} );

fetch( `/wp-json/visual-portfolio/v1/get-max-pages/?${params}` )
    .then( response => response.json() )
    .then( data => {
        console.log( 'Max pages:', data.max_pages );
    } );
Example (POST):
fetch( '/wp-json/visual-portfolio/v1/get-max-pages/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify( {
        content_source: 'images',
        items_count: 20,
        images: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
    } )
} )
.then( response => response.json() )
.then( data => console.log( 'Max pages:', data.max_pages ) );

Update the visibility state of the gallery items count notice. Endpoint: POST /update_gallery_items_count_notice_state/ Permission: manage_options and edit_post Parameters:
  • post_id (integer, required) - Portfolio post ID
  • notice_state (string, required) - Notice state value
Request Body:
{
    "post_id": 123,
    "notice_state": "dismissed"
}
Response:
{
    "success": true,
    "response": true
}

PHP Implementation

Accessing REST Endpoints in PHP

You can make internal REST API requests using WordPress functions. Example:
$request = new WP_REST_Request( 'GET', '/visual-portfolio/v1/get_layouts/' );
$response = rest_do_request( $request );
$server = rest_get_server();
$data = $server->response_to_data( $response, false );

if ( $data['success'] ) {
    $layouts = $data['response'];
    // Use layouts data
}

Making External API Calls

Using wp_remote_post:
$response = wp_remote_post(
    home_url( '/wp-json/visual-portfolio/v1/get_filter_items/' ),
    array(
        'headers' => array(
            'Content-Type' => 'application/json',
        ),
        'body' => wp_json_encode(
            array(
                'content_source' => 'post-based',
                'post_id' => get_the_ID(),
                'posts_source' => 'portfolio',
            )
        ),
    )
);

if ( ! is_wp_error( $response ) ) {
    $body = json_decode( wp_remote_retrieve_body( $response ), true );
    
    if ( isset( $body['success'] ) && $body['success'] ) {
        $filters = $body['response'];
        // Use filter items
    }
}

JavaScript Helper Functions

Making Authenticated Requests

With nonce authentication:
const { nonce } = window.VPData;

fetch( '/wp-json/visual-portfolio/v1/update_layout/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-WP-Nonce': nonce
    },
    body: JSON.stringify( {
        post_id: 123,
        data: { vp_layout: 'grid' }
    } )
} )
.then( response => response.json() )
.then( data => console.log( data ) );
Using jQuery with WordPress AJAX:
jQuery.ajax( {
    url: window.VPData.ajaxUrl,
    method: 'POST',
    data: {
        action: 'vp_custom_action',
        nonce: window.VPData.nonce,
        post_id: 123
    },
    success: function( response ) {
        console.log( response );
    }
} );

Error Handling

Common Error Codes

  • not_allowed - User lacks required permissions
  • missing_params - Required parameters not provided
  • no_layouts_found - No portfolio layouts exist
  • invalid_content_source - Invalid content source specified
  • post_id_required - Post ID parameter missing
  • user_dont_have_permission - User lacks specific permission

Error Response Format

All error responses follow this structure:
{
    "error": true,
    "success": false,
    "error_code": "error_code_here",
    "response": "Human-readable error message"
}

Handling Errors

JavaScript:
fetch( '/wp-json/visual-portfolio/v1/get_layouts/' )
    .then( response => response.json() )
    .then( data => {
        if ( data.error ) {
            console.error( 'Error:', data.error_code, data.response );
            return;
        }
        
        // Handle success
        console.log( data.response );
    } )
    .catch( error => {
        console.error( 'Request failed:', error );
    } );
PHP:
$response = rest_do_request( $request );

if ( is_wp_error( $response ) ) {
    // Handle WP_Error
    error_log( $response->get_error_message() );
} else {
    $data = $response->get_data();
    
    if ( isset( $data['error'] ) && $data['error'] ) {
        // Handle API error
        error_log( 'API Error: ' . $data['error_code'] );
    } else {
        // Handle success
        $result = $data['response'];
    }
}

Security

Permission Checks

All endpoints implement WordPress capability checks:
  • edit_posts - Required for reading layouts and filters
  • edit_post - Required for updating specific layouts
  • manage_options - Required for plugin settings

Nonce Verification

When making requests from the frontend, include the nonce:
const { nonce } = window.VPData;

fetch( endpoint, {
    headers: {
        'X-WP-Nonce': nonce
    }
} );

Data Sanitization

All input data is sanitized using:
  • sanitize_text_field() - For text inputs
  • intval() - For integer values
  • Visual_Portfolio_Security::sanitize_attributes() - For attribute arrays
  • Visual_Portfolio_Security::validate_calculate_max_pages_params() - For pagination params