Visual Composer website builder is packed with many built-in elements to design the frontend more quickly. Today we will learn how to create a custom element for visual composer.
We are going to build a simple visual composer element to display the latest posts at the frontend. We required following fields to generate the output.
- The Number of Posts to display
- Sorting Order By Date / Title
- Collect Post by Category
- The text length for the excerpt text
Table of content
We need to start the implementation with a good structure to make the files well organized. We are creating a vc-elements folder for our selected theme directory. And create a file latest_posts.php
under the vc-elements directory.
Register Before Initialization
The next step is to register the latest_posts.php
file before visual composer initialization. We are going to use the vc_before_init
action hook to do so.
add_action( 'vc_before_init', 'wp23598_vc_before_init_actions' );
function wp23598_vc_before_init_actions() {
// Require New Custom Element
require_once( get_template_directory().'/vc-elements/latest_posts.php' );
}
Initializing New Element
The next step to open the latest_posts.php file and start writing the codes for the new element.
class LatestPosts
{
public function __construct()
{
add_action( 'init', array( $this, 'vcMap' ) );
add_shortcode( 'vc_latest_posts', array( $this, 'render' ) );
}
public function vcMap()
{
....
....
}
public function render($atts, $content = null)
{
....
....
}
}
We are extending the visual composer with the vcMap() method that generates the output like the screenshot.
public function vcMap()
{
vc_map(array(
"name" => "Latest Posts",
"base" => "vc_latest_posts",
"category" => ' Webomnizz Elements',
"allowed_container_element" => 'vc_row',
"params" => array(
array(
"type" => "textfield",
"heading" => "Number of Posts",
"param_name" => "number_of_posts",
"admin_label" => true
),
array(
"type" => "dropdown",
"heading" => "Order By",
"param_name" => "order_by",
"value" => array(
"Title" => "title",
"Date" => "date"
),
'save_always' => true,
"admin_label" => true
),
array(
"type" => "dropdown",
"heading" => "Order",
"param_name" => "order",
"value" => array(
"ASC" => "ASC",
"DESC" => "DESC"
),
'save_always' => true,
"admin_label" => true
),
array(
"type" => "textfield",
"heading" => "Category Slug",
"param_name" => "category",
"description" => "Leave empty for all or use comma for list",
"admin_label" => true
),
array(
"type" => "textfield",
"heading" => "Text length",
"param_name" => "text_length",
"description" => "Number of characters"
),
)
));
}
The render() method is basically for the frontend section that takes care of the User Interface.
public function render($atts, $content = null)
{
$args = array(
"number_of_posts" => "",
"order_by" => "",
"order" => "",
"category" => "",
"text_length" => "",
);
$params = shortcode_atts($args, $atts);
$query = new \WP_Query(
array('orderby' => $params['order_by'], 'order' => $params['order'], 'posts_per_page' => $params['number_of_posts'], 'category_name' => $params['category'])
);
$html = '<div class="lp-holder">';
$html .= '<ul>';
while ($query->have_posts()) : $query->the_post();
$html .= '<li>
<div class="latest_post">
<h2><a href="'.get_permalink().'">'.get_the_title().'</a></h2>
'.wp_kses_post($this->getExcerpt(get_the_ID(), $params['text_length'])).'
</div>
</li>';
endwhile;
$html .= '</ul>
</div>';
return $html;
}
We have created the getExcerpt() method to generate the excerpt string as per the text length option.
This is how our latest_posts.php file looks.
<?php
class LatestPosts
{
public function __construct()
{
add_action( 'init', array( $this, 'vcMap' ) );
add_shortcode( 'vc_latest_posts', array( $this, 'render' ) );
}
public function vcMap()
{
vc_map(array(
"name" => "Latest Posts",
"base" => 'vc_latest_posts',
"category" => 'Webomnizz Elements',
"allowed_container_element" => 'vc_row',
"params" => array(
array(
"type" => "textfield",
"heading" => "Number of Posts",
"param_name" => "number_of_posts",
"admin_label" => true
),
array(
"type" => "dropdown",
"heading" => "Order By",
"param_name" => "order_by",
"value" => array(
"Title" => "title",
"Date" => "date"
),
'save_always' => true,
"admin_label" => true
),
array(
"type" => "dropdown",
"heading" => "Order",
"param_name" => "order",
"value" => array(
"ASC" => "ASC",
"DESC" => "DESC"
),
'save_always' => true,
"admin_label" => true
),
array(
"type" => "textfield",
"heading" => "Category Slug",
"param_name" => "category",
"description" => "Leave empty for all or use comma for list",
"admin_label" => true
),
array(
"type" => "textfield",
"heading" => "Text length",
"param_name" => "text_length",
"description" => "Number of characters"
),
)
));
}
public function render($atts, $content = null)
{
$args = array(
"number_of_posts" => "",
"order_by" => "",
"order" => "",
"category" => "",
"text_length" => "",
);
$params = shortcode_atts($args, $atts);
$query = new \WP_Query(
array('orderby' => $params['order_by'], 'order' => $params['order'], 'posts_per_page' => $params['number_of_posts'], 'category_name' => $params['category'])
);
$html = '<div class="lp-holder">';
$html .= '<ul>';
while ($query->have_posts()) : $query->the_post();
$html .= '<li>
<div class="latest_post">
<h2><a href="'.get_permalink().'">'.get_the_title().'</a></h2>
'.wp_kses_post($this->getExcerpt(get_the_ID(), $params['text_length'])).'
</div>
</li>';
endwhile;
$html .= '</ul>
</div>';
return $html;
}
public function getExcerpt($postId, $text_length = 100)
{
$excerpt = '';
if($text_length !== '0') {
$excerpt .= '<p class="excerpt">';
$excerpt .= $text_length > 0 ? mb_substr(get_the_excerpt(), 0, intval($text_length)) : get_the_excerpt($postId);
$excerpt .= '...</p>';
}
return $excerpt;
}
}
Now the final step is to load our latest_posts.php file. Open the functions.php file and the following at the very bottom of the file.
include_once get_template_directory() . '/vc-elements/latest_posts.php';
Once you finished the editing to the functions.php file then hit save. Now open/edit any page and you will see a new tab with the custom element on the visual composer page builder section.