: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
area.className += ' ' + data.class;
if (data.rows !== undefined) {
f.appendChild(self._initControl(area, data));
if (data.codeeditor !== undefined) {
api.Helper.codeMirror(area, data.codeeditor).then(obj => {
obj?.editor.on('change', () => {
Themify.triggerEvent(area, ev);
if (data.after !== undefined) {
f.appendChild(self.after(data));
if (data.description !== undefined) {
f.appendChild(self.description(data.description));
return self.textarea.render(data, self);
let textarea = createElement('textarea',{class:'tb_lb_wp_editor fullwidth',rows:12,cols:40}),
if (self.is_repeat === true) {
id = 'tb_' + Math.random().toString(36).substr(2, 7);
textarea.className += self.is_sort === true ? ' tb_lb_sort_child' : ' tb_lb_option_child';
textarea.dataset.inputId = data.id;
if (data.control !== false) {
data.control.repeat = true;
textarea.className += ' tb_lb_option';
const wrapper = createElement('', {class:'wp-core-ui wp-editor-wrap tmce-active',id:'wp-' + id + '-wrap'}),
tools = createElement('', {class:'wp-editor-tools',id: 'wp-' + id + '-editor-tools'}),
media_buttons = createElement('',{class:'wp-media-buttons',id:'wp-' + id + '-media-buttons'}),
add_media = createElement('button',{type: 'button',class:'button insert-media add_media'}),
tabs = createElement('','wp-editor-tabs'),
container = createElement('',{class:'wp-editor-container',id:'wp-' + id + '-editor-container'});
if (data.class !== undefined) {
textarea.className += ' ' + data.class;
if (self.values[data.id] !== undefined) {
textarea.value = self.values[data.id];
container.append(textarea, createElement('',{class:'quicktags-toolbar',id:'qt_' + id + '_toolbar'}));
tabs.append(createElement('button',{type:'button',class:'wp-switch-editor switch-tmce',id:id + '-tmce','data-wp-editor-id':id},i18n.visual),createElement('button',{type:'button',class:'wp-switch-editor switch-html',id:id + '-html','data-wp-editor-id':id},i18n.text));
add_media.append(createElement('span','wp-media-buttons-icon'), createTextNode(i18n.add_media));
media_buttons.appendChild(add_media);
tools.append(media_buttons, tabs);
wrapper.append(tools, container);
self._editors.push({el: textarea, data: data});
/* Order By field in Post module, provides backward compatibility */
let v = self.getStyleVal(data.id);
if (v === 'meta_value_num') {
self.values[ data.id ] = 'meta_value';
self.values.meta_key_type = 'NUMERIC';
data.options = self.getOptions('orderBy');
return self.select.render(data, self);
const {recaptcha:recaptchaKey='recaptcha',hcaptcha:hcaptchaKey= 'hcaptcha'} = data,
label : data.label === false ? false : 'cptch',
id : data.id || 'captcha',
[recaptchaKey] : 'recptch',
delete option.options[''];
const result = self.create([ option ]),
select = result.querySelector( '.tb_lb_option' ),
const current=e.currentTarget,
value = selected=== recaptchaKey ? 'recaptcha' : ( selected === hcaptchaKey ? 'hcaptcha' : '' ),
error=current.nextElementSibling,
cache[ value ]??= await api.LocalFetch( { action : 'tb_validate_captcha', provider : value } );
error.innerHTML = cache[ value ].success?'':cache[ value ].data;
select.tfOn( 'change',callback,{passive:true} )
.after( createElement( '','tb_field_error_msg' ) );
self.afterRun.push(() => {
callback({currentTarget:select});
const item = self.getEl(id);
} else if (item[0] !== undefined) {
populate(data, select, self, v) {
const optgroups = self.getOptions(data);
for (let k in optgroups) {
if (opt.label !== undefined) {
let o = createElement('optgroup',{label:i18n[opt.label] || opt.label});
o.appendChild(this.make_options(opt, v, self));
select.appendChild(this.make_options(opt, v, self));
select.appendChild(this.make_options(data, v, self));
make_options(data, v, self) {
const d = createDocumentFragment(),
options = self.getOptions(data) || data;
let opt = createElement('option',{value:k},i18n[options[k]] || options[k]);
// Check for responsive disable
if (data.binding?.[k]?.responsive?.disabled.includes(data.id)) {
opt.className = 'tb_responsive_disable';
if (v === k || (v === undefined && k === data.default) || (Array.isArray(v) && v.includes(k))) {
const select_wrap = createElement('','tf_inline_b tf_vmiddle tf_rel'),
select = createElement('select','tf_scrollbar'),
d = createDocumentFragment(),
v = self.getStyleVal(data.id),
select.setAttribute('multiple', true);
select_wrap.className += ' multi';
if (self.is_repeat === true) {
select.className+= self.is_sort === true ? ' tb_lb_sort_child' : ' tb_lb_option_child';
select.dataset.inputId = data.id;
select.className+= ' tb_lb_option';
if (data.class !== undefined) {
select.className += ' ' + data.class;
if (data.setOptions !== false) {
cache_key += JSON.stringify(data.dataset_args);
if (this.cache.has(cache_key)) {
this.populate(this.cache.get(cache_key), select, self, v);
action: 'tb_get_ajax_data',
/* additional parameters to send to tb_get_ajax_data */
ajaxData.args = data.dataset_args;
select_wrap.className += ' tf_lazy';
api.LocalFetch(ajaxData).then(res => {
this.cache.set(cache_key, res.data);
this.populate(res.data, select, self, v);
api.Spinner.showLoader('error');
select_wrap.classList.remove('tf_lazy');
this.populate(data, select, self, v);
select_wrap.appendChild(self._initControl(select, data));
d.appendChild(select_wrap);
if (data.after !== undefined) {
d.appendChild(self.after(data));
if (data.description !== undefined) {
d.appendChild(self.description(data.description));
if (data.tooltip !== undefined) {
d.appendChild(self.hint(data.tooltip));
updateFontVariant(value, weight, self, type) {
type = '' === type || type === undefined ? undefined !== this.google[value] ? 'google' : 'cf' : type;
type = 'webfont' === type ? 'fonts' : type;
const variants = this[type][value]?.v || null;
if (!variants || variants.length === 0) {
weight.closest('.tb_field').classList.add('_tb_hide_binding');
let selected = self.getStyleVal(weight.id),
fr=createDocumentFragment();
if (undefined === selected) {
selected = 'google' === type ? 'regular' : 'normal';
weight.dataset.selected = value;
weight.closest('.tb_field').classList.remove('_tb_hide_binding');
for (let i = 0; i < variants.length; ++i) {
let opt = createElement('option',{value:variants[i]},variants[i]);
if (variants[i] === selected) {
weight.replaceChildren(fr);
loadGoogleFonts(fontFamilies) {
fontFamilies = [...new Set((fontFamilies.split('|')))];
const result = {google: [], cf: []},
loaded_fonts=this.loaded_fonts,
isFrontend=api.isFrontend;
for (let i = fontFamilies.length - 1; i > -1; --i) {
let font=fontFamilies[i];
if (font && font !== 'default' && this.safe[font]===undefined) {
let req = font.split(':'),
type = this.cf[req[0]] !== undefined ? 'cf' : 'google',
weight = ('regular' === req[1] || 'normal' === req[1] || 'italic' === req[1] || ~~req[1]) ? req[1] : '400,700',
f = req[0].split(' ').join('+') + ':' + weight;
if(this.safe[req[0]]===undefined){
if (!loaded_fonts.has(f) && !result[type].includes(f)) {
if (result.google.length > 0) {
const url = window.location.protocol + '//fonts.googleapis.com/css?family=' + encodeURI(result.google.join('|')) + '&display=swap';
Themify.loadCss(url, null, false);
topThemify.loadCss(url, null, false);
if (result.cf.length > 0) {
const url = themifyBuilder.cf_api_url + encodeURI(result.cf.join('|'));
Themify.loadCss(url, null, false);
topThemify.loadCss(url, null, false);
_controlChange(select, preview, pw, self) {
$combo = $(select).comboSelect({
comboClass: 'themify-combo-select',
comboArrowClass: 'themify-combo-arrow',
comboDropDownClass: 'themify-combo-dropdown tf_scrollbar',
inputClass: 'themify-combo-input',
disabledClass: 'themify-combo-disabled',
hoverClass: 'themify-combo-hover',
selectedClass: 'themify-combo-selected',
markerClass: 'themify-combo-marker'
$combo[0].tfOn(_CLICK_, function (e) {
if (target.classList.contains('themify-combo-item')) {
const value = target.dataset.value,
tab = select.closest('.tb_tab'),
type = this.querySelector('option[value="' + value + '"]')?.dataset.type;
if ('webfont' !== type && value) {
_this.loadGoogleFonts(value);
_this.updateFontVariant(value, tab.tfClass('font-weight-select')[0], self, type);
Themify.triggerEvent(select, 'change');
.tfOn('pointerover', function (e) {
if (target.classList.contains('themify-combo-item')) {
let value = target.dataset.value;
if (!$(target).is(':visible')) {
if (value === 'default') {
preview.style.top = target.offsetTop - target.parentNode.scrollTop + 30 + 'px';
preview.style.fontFamily = value;
preview.style.display = 'block';
if (value !== 'inherit' && !target.classList.contains('tb_font_loaded')) {
target.classList.add('tb_font_loaded');
const mode = target.ownerDocument === topWindowDoc ? 'top' : 'bottom';
if (!_this.fonts[mode].includes(value)) {
const callback = value => {
_this.fonts[mode].push(value);
pw.classList.remove('themify_show_wait');
type = this.querySelector('option[value="' + value + '"]')?.dataset.type;
if (type && type !== 'webfont') {
url = window.location.protocol + '//fonts.googleapis.com/css?family=' + encodeURI(value) + '&display=swap';
} else if ('cf' === type) {
url = themifyBuilder.cf_api_url + encodeURI(value);
pw.classList.add('themify_show_wait');
const tf = mode === 'top' ? topThemify : Themify;
tf.loadCss(url, null, false).then(callback);
target.style.fontFamily = value;
$combo.trigger('comboselect:open')
.on('comboselect:close', () => {
preview.style.display = 'none';
$combo[0].tfClass('themify-combo-arrow')[0].tfOn(_CLICK_, () => {
preview.style.display = 'none';
const select = self.getEl(id);
this.updateFontVariant(v, select.closest('.tb_tab').tfClass('font-weight-select')[0], self);
if (select.dataset.init === undefined) {
const groups = select.tfTag('optgroup'),
opt = createElement('option',{value:v,selected:''});
groups[i]?.replaceChildren();
if (this.safe[v] !== undefined) {
opt.textContent = this.safe[v];
groups[0].appendChild(opt);
} else if (this.google[v] !== undefined) {
opt.textContent = this.google[v].n;
groups[1].appendChild(opt);
} else if (this.cf[v] !== undefined) {
opt.textContent = this.cf[v].n;
groups[2].appendChild(opt);
groups[0].appendChild(opt);
select.parentNode.tfClass('themify-combo-input')[0].value = v;
const wrapper = createElement('','tb_font_preview_wrapper'),
select =createElement('select',{class:'tb_lb_option font-family-select tf_scrollbar',id:data.id}),
preview = createElement('span','tb_font_preview'),
pw = createElement('span','',i18n.font_preview),
d = createDocumentFragment(),
v = self.getStyleVal(data.id),
group = {safe: i18n.safe_fonts, google: i18n.google_fonts},
cfEmpty = Object.keys(this.cf).length < 1;
group.cf = i18n.cf_fonts;
d.appendChild(createElement('option',{value:''},'---'));
if (data.class !== undefined) {
select.className += ' ' + data.class;
const groupKeys = ['google', 'safe'];
for (let i = groupKeys.length - 1; i > -1; --i) {
let optgroup = createElement('optgroup',{label:group[groupKeys[i]]});
if ('safe' === groupKeys[i] && this.safe[v] !== undefined) {
} else if ('google' === groupKeys[i] && this.google[v] !== undefined) {
txt = this.cf[v]?.n ?? v;
optgroup.appendChild(createElement('option',{value:v,selected:''},txt));
const focusIn = function () {
this.tfOff('focusin tf_init', focusIn, {once: true, passive: true});
const fonts = _this.safe,
f = createDocumentFragment(),
sel = this.querySelector('select'),
groups = sel.tfTag('optgroup');
for (let h = groups.length - 1; h > -1; --h) {
groups[h].replaceChildren();
let opt = createElement('option',{value:i,'data-type':'webfont'},fonts[i]);
groups[cfEmpty ? 0 : 1].appendChild(f);
const extGroups = ['google'];
for (let g = extGroups.length - 1; g > -1; --g) {
let ff = _this[extGroups[g]],
fr = createDocumentFragment();
let opt =createElement('option',{value:i,'data-type':extGroups[g]},ff[i].n);