: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if (!class_exists('Themify_Builder_Options',false)) :
class Themify_Builder_Options {
private const KEY = 'themify_builder_setting';
private const SLUG = 'themify-builder';
public static function init() {
add_action('admin_menu', array(__CLASS__, 'add_plugin_page'));
add_action('wp_ajax_themify_builder_settings_save', array(__CLASS__, 'save'));
add_action('wp_head', array(__CLASS__, 'show_custom_css'));
public static function add_plugin_page() {
if (Themify_Access_Role::check_access_backend()) {
$can_manage_option = current_user_can('manage_options');
// This page will be under "Settings"
$name = __('Themify Builder', 'themify');
add_menu_page($name, $name, 'edit_posts', self::SLUG, $can_manage_option ? array(__CLASS__, 'create_admin_page') : '', "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' fill='%23ffcc08' viewBox='0 0 32 32'%3E%3Cpath d='M11.5 3.5c15.8-5 21.8 9 20.3 17.3-.9 4.5-10 5.7-18 6.5-6.9.7-12.1 2.3-12.1 2.3s6.2-4.7 2.1-6.8C1.4 21.6-6.6 9.1 11.5 3.5zm7.3 6c-1 0-1.9.8-1.9 1.8a2 2 0 0 0 2 1.9c1 0 1.8-.9 1.8-1.9 0-1-.8-1.9-1.9-1.9zm-9.4.9a1.9 1.9 0 0 0-1.9 1.9 2 2 0 0 0 2 1.8 2 2 0 0 0 1.8-1.8c0-1.1-.9-2-1.9-2zM7 17.8s7.7 9.8 18.2-1.8c0 0-12.1 7.2-18.2 1.8z'%3E%3C/path%3E%3C/svg%3E", 50);
if ($can_manage_option) {
add_submenu_page(self::SLUG, __('Settings', 'themify'), __('Settings', 'themify'), 'manage_options', self::SLUG);
add_submenu_page('themify-builder', __('Saved Layouts', 'themify'), __('Saved Layouts', 'themify'), 'edit_posts', 'edit.php?post_type=' . Themify_Builder_Layouts::LAYOUT_SLUG);
add_submenu_page('themify-builder', __('Layout Parts', 'themify'), __('Layout Parts', 'themify'), 'edit_posts', 'edit.php?post_type=' . Themify_Builder_Layouts::LAYOUT_PART_SLUG);
add_submenu_page('themify-builder', __('Global Styles', 'themify'), __('Global Styles', 'themify'), 'edit_posts', 'themify-global-styles', array(__CLASS__, 'global_styles_page'));
add_submenu_page('themify-builder', __('Custom Fonts', 'themify'), __('Custom Fonts', 'themify'), 'edit_posts', 'edit.php?post_type=' . Themify_Custom_Fonts::SLUG);
if (!$can_manage_option) {
remove_submenu_page(self::SLUG, self::SLUG);
public static function save() {
check_ajax_referer('tf_nonce', 'nonce');
if (current_user_can('manage_options') && Themify_Access_Role::check_access_backend()) {
if (isset($_POST['data'])) {
$data = stripslashes_deep($_POST['data']);
} elseif (isset($_FILES['data'])) {
$data = file_get_contents($_FILES['data']['tmp_name']);
if (isset($data)) {//don't use empty, when builder is empty need to remove data
$exist_data = get_option(self::KEY);
$isExist = $exist_data !== false;
if (empty($exist_data)) {
$data = json_decode($data, true);
foreach ($data as $k => $v) {
if ($v === '' || $v === 'default') {
$success = maybe_serialize($exist_data) === maybe_serialize($data) ? true : update_option(self::KEY, $data);
$success = $isExist === true ? delete_option(self::KEY) : true;
Themify_Enqueue_Assets::rewrite_htaccess(empty($data['performance-cache_gzip']), empty($data['performance-webp']), empty($data['performance-cache_browser']));
foreach (array('tablet_landscape', 'tablet', 'mobile') as $breakpoint) {
if (isset($data["builder_responsive_design_{$breakpoint}"], $exist_data["builder_responsive_design_{$breakpoint}"]) && $data["builder_responsive_design_{$breakpoint}"] !== $exist_data["builder_responsive_design_{$breakpoint}"]) {
Themify_Builder_Stylesheet::regenerate_css_files();
do_action( 'themify_builder_settings_save' );
* Display Builder Styles page content
public static function global_styles_page() {
if (!current_user_can('edit_posts')) {
wp_die(__('You do not have sufficient permissions to update this site.', 'themify'));
return Themify_Global_Styles::page_content();
private static function get_tab_settings():array {
$modules=Themify_Builder_Component_Module::load_modules('all');
$responsive = $disableModules = $feature_sizes = $disablePosts = array();
'tablet_landscape' => 1024,
foreach (themify_get_breakpoints('', true) as $bp => $val) {
$label = $bp === 'tablet_landscape' ? 'Tablet Landscape' : ($bp === 'tablet' ? 'Tablet Portrait' : ucfirst($bp));
'id' => 'builder_responsive_design_' . $bp,
'label' => sprintf(__('%s', 'themify'), $label),
'def' => $defBreakPoints[$bp],
'min' => is_array($val) ? $val[0] : 320,
'max' => is_array($val) ? $val[1] : $val
foreach ($modules as $k => $m) {
$name= is_string($m)?$m::get_module_name():$m->get_name();
$disableModules[] = array(
'label' => sprintf(__('"%s" module', 'themify'), $name),
'id' => 'builder_exclude_module_' . $k,
foreach (themify_get_image_sizes_list() as $opt) {
$feature_sizes[$opt['value']] = $opt['name'];
$excludes = array(Themify_Builder_Layouts::LAYOUT_PART_SLUG, Themify_Builder_Layouts::LAYOUT_SLUG, Themify_Global_Styles::SLUG, 'tbp_template');
$globalGutters = Themify_Builder_Model::get_gutters();
foreach (Themify_Builder::builder_post_types_support() as $v) {
if (!in_array($v, $excludes, true)) {
'label' => sprintf(__('"%s" type', 'themify'), $v),
'id' => 'builder_disable_tb_' . $v,
unset($excludes, $defBreakPoints);
$imageLibrary = wp_image_editor_supports() !== false;
'label' => __('Column Gutter Size', 'themify'),
'id' => 'setting-gutter',
'def' => $globalGutters['gutter'],
'after' => __('Normal gutter (%)', 'themify')
'id' => 'setting-narrow',
'def' => $globalGutters['narrow'],
'after' => __('Narrow gutter (%)', 'themify')
'def' => $globalGutters['none'],
'after' => __('None gutter (%)', 'themify')
'label' => __('Gallery Module Lightbox', 'themify'),
'id' => 'builder_lightbox',
'label' => __('Keyboard Shortcuts', 'themify'),
'id' => 'builder_disable_shortcuts',
'help' => __('Builder shortcuts (eg. disable shortcut like Cmd+S = save)', 'themify'),
'label' => __('WordPress Classic Editor', 'themify'),
'id' => 'builder_disable_wp_editor',
'help' => __('Enable/disable WordPress Classic Editor when Builder is in use', 'themify')
'label' => __('Google Fonts List', 'themify'),
'id' => 'builder_google_fonts',
'less' => __('Show recommended Google Fonts only', 'themify'),
'full' => __('Show all Google Fonts (showing all fonts will take longer to load)', 'themify'),
'label' => __('Download Google Fonts', 'themify'),
'desc' => __('Downloads all Google Fonts used in the Builder to your local server. Note: Google Maps, YouTube and any embeds loaded in iframe are excluded as they are loaded in the iframe.', 'themify'),
'action' => 'themify_clear_gfonts',
'text' => __('Clear Google Fonts Cache', 'themify'),
'clearing' => __('Clearing...', 'themify'),
'done' => __('Done', 'themify')
'label' => __('Animation Effects', 'themify'),
'label' => __('Appearance Animation', 'themify'),
'id' => 'builder_animation_appearance',
'mobile' => __('Disable on mobile & tablet', 'themify'),
'all' => __('Disable on all devices', 'themify')
'label' => __('Parallax Background', 'themify'),
'id' => 'builder_animation_parallax_bg',
'mobile' => __('Disable on mobile & tablet', 'themify'),
'all' => __('Disable on all devices', 'themify')
'label' => __('Scroll Effects', 'themify'),
'id' => 'builder_animation_scroll_effect',
'mobile' => __('Disable on mobile & tablet', 'themify'),
'all' => __('Disable on all devices', 'themify')
'label' => __('Responsive Breakpoints', 'themify'),
'id' => 'builder_scrollTo',
'label' => __('ScrollTo Offset', 'themify'),
'help' => __('Enter the top position where it should scrollTo', 'themify')
'id' => 'builder_scrollTo_speed',
'label' => __('ScrollTo Speed', 'themify'),
'help' => __('Speed of scrolling animation. Default: 0.9 second', 'themify')
'label' => __('Image Script', 'themify'),
'id' => 'image_setting-img_settings_use',
'help' => __('Image script crops the images to the entered size. If disabled, WordPress Featured Image or original images will be used.', 'themify'),
'disabled' => $imageLibrary ? '' : sprintf(__('This feature requires an <a href="%s" target="_blank">image processing library</a> to be installed on the server. Please contact your hosting provider to enable this.', 'themify'), 'https://www.php.net/manual/en/refs.utilspec.image.php'),
'show' => 'featured_size'
'hide' => 'featured_size'
'label' => __('Default Featured Image Size', 'themify'),
'wrap_class' => $imageLibrary ? 'featured_size' : '',
'id' => 'image_global_size_field',
'options' => $feature_sizes
'label' => __('Builder For Post Types', 'themify'),
'options' => $disablePosts
'label' => __('Builder Modules', 'themify'),
'options' => $disableModules
private static function get_tab_performance():array {
$htaccess_file = Themify_Enqueue_Assets::getHtaccessFile();
$htaccess_msg = Themify_Filesystem::is_file($htaccess_file) && Themify_Filesystem::is_writable($htaccess_file) ? '' : sprintf(__('The htaccess file %s isn`t writable. Please allow to write to enable this feauture', 'themify'), $htaccess_file);
$imageLibrary = wp_image_editor_supports() !== false;
'label' => __('Lazy Load', 'themify'),
'label' => __('Themify Lazy Load', 'themify'),
'id' => 'performance-disable-lazy',
'label' => __('Browser Caching', 'themify'),
'help' => __("Cache static assets (CSS, JS, images, etc.) on user's browser. HTML is not cached", 'themify'),
'disabled' => $htaccess_msg,
'id' => 'performance-cache_browser',
'label' => __('Gzip Scripts', 'themify'),
'id' => 'performance-cache_gzip',
'disabled' => $htaccess_msg,
'desc' => $htaccess_msg === '' ? sprintf(__('Enabling Gzip will add code to your .htaccess file %s', 'themify'), $htaccess_file) : '',
'label' => __('Enable jQuery Migrate', 'themify'),
'id' => 'performance-jquery_migrate',
'help' => __('Enable this option if you have plugins that use deprecated jQuery versions.', 'themify')
'label' => __('WebP Images', 'themify'),
'id' => 'performance-webp',
'help' => __('Enable WebP image (recommended)', 'themify'),
'disabled' => $imageLibrary ? '' : __('The GD library or Imagick extensions are not installed. Ask your host provider to enable them to use this feature.', 'themify'),
'label' => __('WebP Image Quality', 'themify'),
'help' => __('Lower quality has smaller file size, but image might appear pixelated/blurry.', 'themify'),
'wrap_class' => 'webp_group',
'disabled' => $imageLibrary ? '' : 'disable',
'id' => 'performance-webp_quality',
'1' => __('Lowest', 'themify'),
'2' => __('Low', 'themify'),
'3' => __('Medium', 'themify'),
'4' => __('Good', 'themify'),
'5' => __('High', 'themify'),
'6' => __('Highest', 'themify'),
'disabled' => $imageLibrary ? '' : 'disable',
'action' => 'themify_clear_all_webp',
'text' => __('Clear WebP Images', 'themify'),
'clearing' => __('Clearing...', 'themify'),
'done' => __('Done', 'themify')
'label' => __('Concate CSS', 'themify'),
'action' => 'themify_clear_all_concate',
'text' => __('Clear Concate CSS Cache', 'themify'),
'clearing' => __('Clearing...', 'themify'),
'done' => __('Done', 'themify'),
'disabled' => Themify_Enqueue_Assets::createDir() ? '' : __('It looks like the WordPress upload folder path is set wrong or have file permission issue. Please check the upload path on WP Settings > Media. Make sure the folder is set correctly and it has correct file permission.', 'themify'),
'network' => is_multisite() ? array('tmp_cache_concte_network' => __('Clear Concate cache in the whole network site', 'themify')) : '',
private static function get_tab_role_access():array {
'backend' => __('Builder Backend Access', 'themify'),
'frontend' => __('Builder Frontend Access', 'themify')
'default' => __('Default', 'themify'),
'enable' => __('Enable', 'themify'),
'disable' => __('Disable', 'themify')
$roles = $wp_roles->get_names();
$defaultRoles = apply_filters('tb_roles', $defaultRoles);
// Remove the adminitrator and subscriber user role from the array
unset($roles['administrator']);
// Remove all the user roles with no "edit_posts" capability
foreach ($roles as $role => $slug) {
if (empty($wp_roles->roles[$role]['capabilities']['edit_posts'])) {
foreach ($defaultRoles as $k => $v) {
foreach ($roles as $type => $name) {
'id' => 'setting-' . $k . '-' . $type,
'options' => $k === 'tbp' ? array_merge( $role_options, [ 'enableown' => __( 'Enable For Owned Posts', 'themify' ) ] ) : $role_options
private static function get_tab_custom_css():array {
'label' => __('Custom CSS', 'themify'),
'id' => 'custom_css-custom_css',
private static function get_tab_integration():array {
include_once THEMIFY_BUILDER_INCLUDES_DIR . '/optin-services/base.php';
$providers = Builder_Optin_Service::get_providers('all',true);
foreach ($providers as $id => $provider) {
$options = $provider::get_global_options();
foreach ($options as &$opt) {
if (isset($opt['description'])) {
$opt['desc'] = $opt['description'];
unset($opt['description']);
'action' => 'tb_optin_clear_cache',
'text' => __('Clear Cache', 'themify'),
'clearing' => __('Clearing...', 'themify'),
'done' => __('Done', 'themify'),
'label' => __('Google Map API Key', 'themify'),
'id' => 'builder_settings_google_map_key',
'desc' => sprintf(__('Google API key is required to use Builder Map module and Map shortcode. <a href="%s" target="_blank">Generate an API key</a> and insert it here. Also, please ensure you\'ve setup a <a href="%s" target="_blank">billing plan</a>.'), '//developers.google.com/maps/documentation/javascript/get-api-key#key', 'https://support.google.com/googleapi/answer/6158867')
'label' => __('Bing Map API Key', 'themify'),
'id' => 'builder_settings_bing_map_key',
'desc' => sprintf(__('To use Bing Maps, <a href="%s" target="_blank">generate an API key</a> and insert it here.', 'themify'), 'https://msdn.microsoft.com/en-us/library/ff428642.aspx')