Full developer API for registering, modifying, and extending WPBakery Page Builder elements.
Every vc_map() param has a type that determines the UI control and how data is stored.
| Type | UI Control | Stored Value Format |
|---|---|---|
textfield |
Text input | Plain string |
textarea |
Textarea | Plain string |
textarea_html |
WYSIWYG. ONE per shortcode, param_name MUST be "content" | Content between shortcode tags |
textarea_raw_html |
Textarea for raw code | Base64-encoded string |
dropdown |
Select | Selected option value string |
checkbox |
Checkbox(es) | Comma-separated checked values |
colorpicker |
Color picker | Hex color "#ff0000" |
attach_image |
Media library (single) | Attachment ID integer as string |
attach_images |
Media library (multi) | Comma-separated IDs |
posttypes |
Post type checkboxes | Comma-separated slugs |
taxonomies |
Taxonomy checkboxes | Comma-separated slugs |
exploded_textarea |
Textarea (line = item) | Comma-separated string |
exploded_textarea_safe |
Same + encoding | Encoded comma-separated |
css_editor |
Visual CSS editor | .vc_custom_TIMESTAMP{prop: val !important;} |
vc_link |
Link dialog | `url:... |
loop |
Query builder | `post_type:post |
autocomplete |
Search input | Comma-separated IDs/slugs |
param_group |
Repeater field group | URL-encoded base64 JSON |
google_fonts |
Google Fonts selector | `font_family:... |
font_container |
Font settings | `tag:h2 |
iconpicker |
Icon picker | CSS class: "fas fa-adjust" |
animation_style |
CSS animation picker | Animation name: "fadeIn" |
widgetised_sidebars |
Widget area dropdown | Sidebar ID string |
el_id |
Element ID input | String |
hidden |
Hidden field | Any string |
tab_id |
Tab identifier | String ID |
Register a new element. Hook: vc_before_init.
add_action('vc_before_init', function() {
vc_map([
// Required
'name' => __('My Element'), // Display name
'base' => 'my_element', // Shortcode tag
// Optional metadata
'description' => __('Description'),
'category' => __('Content'), // "Content","Social","Structure", or custom
'icon' => 'dashicons-star-filled', // URL or CSS class
'weight' => 0, // Higher = appears first in panel
'show_settings_on_create' => true,
// Container settings
'is_container'=> false, // true for parent containers
'as_parent' => ['only' => 'child_tag'], // Restrict which children allowed
'as_child' => ['only' => 'parent_tag'],// Restrict which parents allowed
'js_view' => 'VcColumnView', // Required for containers
'default_content' => '', // Initial child shortcodes
// Visibility
'content_element' => true, // false to hide from add panel
'deprecated' => '', // Version string to mark deprecated
// Asset enqueueing
'admin_enqueue_js' => [],
'admin_enqueue_css' => [],
'front_enqueue_js' => [],
'front_enqueue_css' => [],
// Template
'html_template' => '', // Path to custom template file
'php_class_name' => '', // Custom PHP class
// Parameters
'params' => [
[
'type' => 'textfield', // See Parameter Types table
'heading' => __('Title'),
'param_name' => 'title', // Maps to shortcode attribute name
'value' => 'Default value', // Default displayed value
'std' => '', // Default selected/saved value
'description'=> 'Help text',
'admin_label'=> true, // Show in backend preview
'holder' => 'div', // HTML tag to show value in backend
'group' => 'General', // Settings tab name
'weight' => 0,
'save_always'=> false, // Force save even if matches default
'edit_field_class' => 'vc_col-sm-6', // Layout width in settings panel
'dependency' => [ // Show/hide based on another param
'element' => 'other_param',
'value' => ['val1', 'val2'],
'not_empty' => true,
],
],
],
]);
});vc_lean_map('my_element', function() {
return ['name' => 'My Element', 'base' => 'my_element', 'params' => [...]];
});
// Or with file:
vc_lean_map('my_element', null, get_template_directory() . '/vc/my-element.php');All hook on vc_after_init:
// Add parameter
vc_add_param('vc_row', [
'type' => 'textfield', 'heading' => 'My Param', 'param_name' => 'my_param'
]);
// Add multiple parameters
vc_add_params('vc_row', [/* array of param arrays */]);
// Update element properties
vc_map_update('vc_message', ['name' => 'New Name', 'category' => 'New Category']);
// Update a single parameter
vc_update_shortcode_param('vc_single_image', [
'type' => 'textfield', 'param_name' => 'img_size', 'value' => 'full'
]);
// Remove element entirely
vc_remove_element('vc_flickr');
// Remove parameter
vc_remove_param('vc_message', 'el_class');
// Remove ALL elements (clean slate)
vc_remove_all_elements();
// Get element's full mapping data
$settings = vc_get_shortcode('vc_row');
// Get all attributes with defaults
$atts = vc_map_get_attributes('my_element', $atts);
// Get only defaults
$defaults = vc_map_get_defaults('my_element');// Pull another element's params with a prefix
$btn_params = vc_map_integrate_shortcode('vc_btn', 'btn_', 'Button', [
'exclude' => ['css']
]);
// Merge into your element's params array
// In render callback, parse the integrated attributes
$btn_data = vc_map_integrate_parse_atts('my_element', 'vc_btn', $atts, 'btn_');
$btn_output = wpbakery()->getShortCode('vc_btn')->render(array_filter($btn_data));// 1. Register shortcode handler
add_shortcode('my_box', function($atts, $content = '') {
$atts = vc_map_get_attributes('my_box', $atts);
$css_class = vc_shortcode_custom_css_class($atts['css'], ' ');
return '<div class="my-box' . esc_attr($css_class) . '">'
. '<h3>' . esc_html($atts['title']) . '</h3>'
. '<div>' . wp_kses_post($content) . '</div></div>';
});
// 2. Map to WPBakery
add_action('vc_before_init', function() {
vc_map([
'name' => 'My Box', 'base' => 'my_box', 'category' => 'Content',
'params' => [
['type'=>'textfield', 'heading'=>'Title', 'param_name'=>'title'],
['type'=>'textarea_html', 'heading'=>'Content', 'param_name'=>'content'],
['type'=>'css_editor', 'heading'=>'CSS', 'param_name'=>'css', 'group'=>'Design Options'],
],
]);
});// Parent element
add_action('vc_before_init', function() {
vc_map([
'name' => 'My Tabs', 'base' => 'my_tabs',
'is_container' => true,
'show_settings_on_create' => false,
'as_parent' => ['only' => 'my_tab'],
'default_content' => '[my_tab title="Tab 1"][/my_tab][my_tab title="Tab 2"][/my_tab]',
'js_view' => 'VcColumnView',
'params' => [],
]);
});
// MUST extend WPBakeryShortCodesContainer
class WPBakeryShortCode_My_Tabs extends WPBakeryShortCodesContainer {}
// Child element
add_action('vc_before_init', function() {
vc_map([
'name' => 'Tab', 'base' => 'my_tab',
'as_child' => ['only' => 'my_tabs'],
'is_container' => true,
'content_element' => true,
'js_view' => 'VcColumnView',
'params' => [
['type'=>'textfield', 'heading'=>'Title', 'param_name'=>'title', 'admin_label'=>true],
['type'=>'textarea_html', 'heading'=>'Content', 'param_name'=>'content'],
],
]);
});
class WPBakeryShortCode_My_Tab extends WPBakeryShortCodesContainer {}Class naming convention: WPBakeryShortCode_ + base name with dashes as underscores.
WPBakeryShortCode— for leaf elements (no children)WPBakeryShortCodesContainer— for container elements (can hold children)
vc_add_shortcode_param('my_type', 'my_type_callback', $optional_js_url);
function my_type_callback($settings, $value) {
return '<input name="' . esc_attr($settings['param_name'])
. '" class="wpb_vc_param_value wpb-textinput '
. esc_attr($settings['param_name']) . ' '
. esc_attr($settings['type']) . '_field"'
. ' type="text" value="' . esc_attr($value) . '" />';
// MUST include class "wpb_vc_param_value" for WPBakery to parse on save
}// Parse vc_link → array
$link = vc_build_link($atts['link']);
// Returns: ['url' => '...', 'title' => '...', 'target' => '...', 'rel' => '...']
// Parse css_editor → class name
$css_class = vc_shortcode_custom_css_class($atts['css'], ' ');
// Returns: " vc_custom_1664369671640"
// Parse param_group → array of items
$items = vc_param_group_parse_atts($atts['my_group']);
// Returns: [['field1' => 'val1', 'field2' => 'val2'], ...]
// Get all attributes with defaults (replaces shortcode_atts since v4.6)
$atts = vc_map_get_attributes('my_shortcode', $atts);// 1. BEFORE template rendering
add_filter('vc_shortcode_content_filter', function($output, $tag, $atts) {
return $output;
}, 10, 3);
// 2. AFTER template rendering
add_filter('vc_shortcode_content_filter_after', function($output, $tag, $atts, $content) {
return $output;
}, 10, 4);
// 3. FINAL output
add_filter('vc_shortcode_output', function($output, $shortcode_obj, $atts, $tag) {
if ($tag === 'vc_separator') {
$output = '<div class="wrap">' . $output . '</div>';
}
return $output;
}, 10, 4);add_filter('vc_shortcodes_css_class', function($class_string, $tag) {
if ($tag === 'vc_row') {
$class_string = str_replace('vc_row', 'my_row', $class_string);
}
if ($tag === 'vc_column') {
$class_string = preg_replace('/vc_col-sm-(\d+)/', 'my_col-$1', $class_string);
}
return $class_string;
}, 10, 2);// Theme mode — hides Design Options and Custom CSS tabs
add_action('vc_before_init', function() { vc_set_as_theme(); });
// Disable frontend editor
vc_disable_frontend();
// Set post types for WPBakery
vc_set_default_editor_post_types(['page', 'post', 'my_cpt']);
vc_editor_set_post_types(['page', 'post']);
// Override template directory
vc_set_shortcodes_templates_dir(get_stylesheet_directory() . '/vc_templates');Copy element templates from:
wp-content/plugins/js_composer/include/templates/shortcodes/{base}.php
To:
wp-content/themes/your-theme/vc_templates/{base}.php
Templates must echo output, not return it. Custom directory via vc_set_shortcodes_templates_dir().
add_action('vc_load_default_templates_action', function() {
vc_add_default_templates([
'name' => 'My Template',
'weight' => 0,
'image_path' => plugins_url('images/thumb.jpg', __FILE__),
'custom_class' => 'my_template',
'content' => '[vc_row][vc_column][vc_column_text]Hello[/vc_column_text][/vc_column][/vc_row]',
]);
});
// Filter to modify/remove defaults
add_filter('vc_load_default_templates', function($data) {
return array(); // removes all
});vc_basic_grid— Post grid (posts, pages, CPTs)vc_media_grid— Media library gridvc_masonry_grid— Masonry post gridvc_masonry_media_grid— Masonry media grid
add_filter('vc_grid_item_shortcodes', function($shortcodes) {
$shortcodes['my_grid_el'] = [
'name' => 'My Grid Element',
'base' => 'my_grid_el',
'category' => 'Content',
'post_type' => Vc_Grid_Item_Editor::postType(),
];
return $shortcodes;
});
add_shortcode('my_grid_el', function($atts) {
return '{{ post_data:post_title }}';
});{{ post_data:ID }}— Post ID{{ post_data:post_title }}— Title{{ featured_image:data }}— Featured image- Custom: register via
vc_gitem_template_attribute_{name}filter
- Normal — Main display (3 rows, dividable into columns)
- Hover — On hover (requires animation preset ≠ "Single block")
- Additional — Around Normal/Hover, not animated
WooCommerce elements use different hooks than standard elements:
function remove_woo_elements() {
if (is_plugin_active('woocommerce/woocommerce.php')) {
vc_remove_element('woocommerce_cart');
vc_remove_element('recent_products');
}
}
add_action('vc_build_admin_page', 'remove_woo_elements', 11);
add_action('vc_load_shortcode', 'remove_woo_elements', 11);