: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$props['data-lax'] = 'true';
if ($is_lax !== 'done') {
\Themify_Enqueue_Assets::addPrefetchJs(THEMIFY_URI . '/js/modules/lax.js', THEMIFY_VERSION);
if (isset($fields_args['custom_css_id'])) {
$props['id'] = $fields_args['custom_css_id'];
* Map animation speed parameter and returns new speed
* @param string $val Initial speed value
* @param string $attr attribute name
* @return float|int Returns speed of element based on initial value
private static function map_animation_speed(float $val,string $attr = ''):float {
$speed = $val===3?200:($val<3?(70*$val):(670-(10-$val)*70));
* Map initial origin value and returns transform origin property
* @param string $props Initial origin value
* @return string Returns transform origin value of element based on initial value
private static function map_transform_origin(string $props):string {
$output = 'center center';
$output = 'right center';
$output = 'bottom center';
$output = 'bottom right';
$perc = \explode(',', $props);
$output = $perc[0] . '% ' . $perc[1] . '%';
* Return the correct animation css class name
public static function parse_animation_effect($settings, array $attr = array()) {
/* backward compatibility for addons */
if (!is_array($settings)) {
$has = \Themify_Builder_Model::is_animation_active();
if (!empty($settings['hover_animation_effect'])) {
$attr['data-tf-animation_hover'] = $settings['hover_animation_effect'];
if (isset($attr['class'])) {
$attr['class'] .= ' hover-wow';
$attr['class'] = 'hover-wow';
if (!empty($settings['animation_effect'])) {
$attr['data-tf-animation'] = $settings['animation_effect'];
if (!in_array($settings['animation_effect'], array('fade-in', 'fly-in', 'slide-up'), true)) {
if (isset($attr['class'])) {
$attr['class'] .= ' wow';
if (!empty($settings['animation_effect_delay'])) {
$attr['data-tf-animation_delay'] = $settings['animation_effect_delay'];
if (!empty($settings['animation_effect_repeat'])) {
$attr['data-tf-animation_repeat'] = $settings['animation_effect_repeat'];
\Themify_Enqueue_Assets::preFetchAnimtion();
public static function load_modules(string $mod_name = 'active', bool $ignore = false) {
if ($mod_name !== 'active' && $mod_name !== 'all') {
if(isset(Themify_Builder_Model::$modules[$mod_name])){//backward will be removed in the future
return Themify_Builder_Model::$modules[$mod_name];
$className=self::get_module_class($mod_name);
if(class_exists($className,false)){
return $className::is_available()?$className:'';
$dir = \Themify_Builder_Model::get_modules($mod_name,$ignore);
$dir=THEMIFY_BUILDER_MODULES_DIR;
require $dir . '/module-' . $mod_name . '.php';
$className=self::get_module_class($mod_name);//the second call need for backward
return isset(Themify_Builder_Model::$modules[$mod_name])?Themify_Builder_Model::$modules[$mod_name]:($className::is_available()?$className:'');
$items = \Themify_Builder_Model::get_modules($mod_name);
foreach ($items as $m => $dir) {
$dir = THEMIFY_BUILDER_MODULES_DIR;
require_once $dir . '/module-' . $m . '.php';
if(isset(Themify_Builder_Model::$modules[$m])){
$item=Themify_Builder_Model::$modules[$m];
$className=self::get_module_class($m);
if(!$className::is_available()){
public static function get_modules_assets():array {
public static function add_modules_assets($k, $item):void {
self::$assets[$k] = $item;
public static function render(string $slug, string $mod_id, $builder_id, array &$settings = array(), bool $echo = false) {
$template = $slug === 'highlight' || $slug === 'testimonial' || $slug === 'post' || $slug === 'portfolio' ? 'blog' : $slug;
'builder_id' => $builder_id,
'mod_settings' => $settings
$vars = apply_filters('themify_builder_module_render_vars', $vars, $slug);
return self::retrieve_template('template-' . $template . '.php', $vars, '', '', $echo);
* If there's not an options tab in Themify Custom Panel meta box already defined for this post type, like "Portfolio Options", add one.
* @param array $meta_boxes
public static function cpt_meta_boxes(array $meta_boxes = array()):array {
Themify_Builder_Model::load_general_metabox(); // setup common fields
$meta_box_id = static::SLUG . '-options';
if (!in_array($meta_box_id, wp_list_pluck($meta_boxes, 'id'), true)) {
$options = static::get_metabox();
$meta_boxes = array_merge($meta_boxes, array(
'name' => sprintf(__('%s Options', 'themify'), self::get_module_name()),
public static function get_module_title(array $fields_args,string $key = 'mod_title'):string {
if (isset($fields_args[$key]) && $fields_args[$key] !== '') {
$titleTag=apply_filters('themify_builder_module_title_tag', 'h3');
$startTag='<'.$titleTag.' class="module-title"';
if($key!=='' && (Themify_Builder::$frontedit_active === true || Themify_Builder_Model::is_front_builder_activate())){
$startTag.=' data-name="'.$key.'" contenteditable="false"';
return $startTag .'>'. $fields_args[$key] . '</'.$titleTag.'>';
public static function get_paged_query():int {
if (isset($_GET['tf-page']) && is_numeric($_GET['tf-page'])) {
$page = (int) $_GET['tf-page'];
$qpaged = get_query_var('paged');
$qpaged = wp_parse_args($wp->matched_query);
$page = isset($qpaged['paged']) && $qpaged['paged'] > 0?(int)$qpaged['paged']:1;
public static function query(array $args):WP_Query {
$isPaged = isset($args['paged']) && $args['paged'] > 1;
$hasSticky = isset($args['ignore_sticky_posts']) && $args['ignore_sticky_posts'] === false;
$maxPage = (int) $args['posts_per_page'];
if ($hasSticky === true) {
$sticky_posts = get_option('sticky_posts');
if (empty($sticky_posts)) {
$sticky_posts = array_slice($sticky_posts, 0, $maxPage);
if ($hasSticky === true && $isPaged === false) {
'post_status' => 'publish',
'post_type' => $args['post_type'],
'post__in' => $sticky_posts,
'posts_per_page' => $maxPage,
'ignore_sticky_posts' => true
if (isset($args['tax_query'])) {
$params['tax_query'] = $args['tax_query'];
if (isset($args['meta_key'])) {
$params['meta_key'] = $args['meta_key'];
if (isset($args['post__not_in'])) {
$params['post__not_in'] = $args['post__not_in'];
$the_query = new WP_Query($params);
if ($the_query->post_count < $maxPage) {
if (isset($args['post__not_in'])) {
$args['post__not_in'] = array_merge($args['post__not_in'],$sticky_posts);;
$args['post__not_in'] = $sticky_posts;
$args['ignore_sticky_posts'] = true;
$args['posts_per_page'] = $maxPage - $the_query->post_count;
$q = new WP_Query($args);
$the_query->found_posts = $q->found_posts;
$the_query->posts = array_merge($the_query->posts, $q->posts);
$the_query->post_count = count($the_query->posts);
$the_query->max_num_pages = ceil($the_query->found_posts / $maxPage);
if ($isPaged === true && $hasSticky === true) {
if (isset($args['post__not_in'])) {
$args['post__not_in']= array_merge($args['post__not_in'],$sticky_posts);
$args['post__not_in'] = $sticky_posts;
$the_query = new WP_Query($args);
* @param string Markup to show before pagination links
* @param string Markup to show after pagination links
* @param object WordPress query object to use
* @param original_offset number of posts configured to skip over
public static function get_pagination($before = '', $after = '', $query = false, $original_offset = 0, $max_page = 0, $paged = 0):string {
$paged = (int) self::get_paged_query();
$numposts = $query->found_posts;
$original_offset = (int) $original_offset;
// $query->found_posts does not take offset into account, we need to manually adjust that
if ($original_offset > 0) {
$numposts -= $original_offset;
$max_page = ceil($numposts / $query->query_vars['posts_per_page']);
Themify_Builder_Model::loadCssModules('pagenav', THEMIFY_BUILDER_CSS_MODULES . 'pagenav.css', THEMIFY_VERSION);
if (!is_string($query) && is_single()) {
return themify_get_pagenav($before, $after, $query, $max_page, $paged);
* Get template for module
public static function template(array &$mod, $builder_id = 0,bool $echo = true) {
if (Themify_Builder::$frontedit_active === false) {
/* allow addons to control the display of the modules */
$display = apply_filters('themify_builder_module_display', true, $mod, $builder_id);
if (false === $display || ( isset($mod['mod_settings']['visibility_all']) && $mod['mod_settings']['visibility_all'] === 'hide_all' )) {
if (!isset($mod['mod_name'])) {
$slug = $mod['mod_name'];
static $isLoaded = array();
self::$isFirstModule = false;
if (!isset($isLoaded[$slug])) {//load only the modules in the page
$module = self::load_modules($slug);
if($module===''){// check whether module active or not
if (Themify_Builder::$frontedit_active === false && empty($mod['mod_settings']['_render_plain_content'])) {
$assets = \is_string($module) ? $module::get_js_css() : $module->get_assets();
static $count = 0; //only need to load the modules styles in concate for the first 2 modules to show LCP asap,even if they should load as async
$ver = isset($assets['ver']) ? $assets['ver'] : THEMIFY_VERSION;
self::$isFirstModule = $count < 2;
if (isset($assets['css']) && ($count < 2 || !isset($assets['async']))) {
$assets['css'] = (array) $assets['css'];
$content_url=content_url();
foreach ($assets['css'] as $k => $s) {
$key = is_int($k) ? $slug : $k;
$s = THEMIFY_BUILDER_CSS_MODULES . $slug . '.css';
if (\strpos($s, 'http') === false && \strpos($s,$content_url)===false) {
$s = THEMIFY_BUILDER_CSS_MODULES . $s;
if (\strpos($s, '.css') === false) {
\Themify_Builder_Model::loadCssModules($key, $s, $ver);
if (isset($assets['js']) || isset($assets['css'])) {
if (self::$isFirstModule === true && isset($assets['js'])) {
$u = THEMIFY_BUILDER_JS_MODULES . $slug . '.js';
if (\strpos($u, 'http') === false && \strpos($s, content_url())===false) {
$u = THEMIFY_BUILDER_JS_MODULES . $u;
if (\strpos($u, '.js') === false) {
\Themify_Enqueue_Assets::addPrefetchJs($u, $ver);
self::$assets[$slug] = $assets;
if ($slug === 'feature' || $slug === 'menu' || $slug === 'tab' || $slug === 'accordion') {
\Themify_Enqueue_Assets::addPrefetchJs(THEMIFY_BUILDER_JS_MODULES . $slug . '.js', $ver);
$mod['mod_settings'] = isset($mod['mod_settings']) ? $mod['mod_settings'] : array();
$output .= PHP_EOL; // add line break
do_action('themify_builder_background_styling', $builder_id, array('styling' => $mod['mod_settings'], 'mod_name' => $slug, 'element_id' => $mod['element_id']), 'module', '');
$output .= ob_get_clean() . PHP_EOL;
elseif ($slug === 'slider' && Themify_Builder::$frontedit_active === false) {
$res = self::render($slug, 'tb_' . $mod['element_id'], $builder_id, $mod['mod_settings'], $echo);
if ($slug === 'slider' && Themify_Builder::$frontedit_active === false) {
$output = \themify_make_lazy($output, false);
if (isset($isEcho) && $isEcho === true) {
return $output . PHP_EOL;
* Retrieve saved settings for a module
public static function get_element_settings( $post_id, $element_id ):array {
$data = Themify_Builder::get_builder_modules_list( $post_id );
if ( ! empty( $data ) ) {
foreach ( $data as $module ) {
if ( isset( $module['element_id'], $module['mod_settings'] ) && $module['element_id'] === $element_id ) {
return $module['mod_settings'];