Создание дополнительных breakpoints в Oxygen Builder
Если вы используете плагин Oxygen Builder в качестве создания сайтов на Wordpress, то вы могли заметить проблему данного плагина ,а именно точек остановки для создания responsive
дизайна всего 3. Это крайне мало и вызывает недоумение, чтобы такой мощный конструктор страниц предлагал такое ограниченное количество breakpoints.
Эту тему не раз поднимали на гитхабе плагина, но с того момента так ничего и не изменилось. Пришло время это исправить. Вообще сразу скажу, что скрипты в отношении мобильного дизайна работают мягко говоря странно и дальше вы поймёте почему.
Содержание статьи
Требования
- Wordpress 6
- PHP 7.4
- Oxygen builder 4.9
Файлы, которые подверглись изменению
- oxygen/component-framework/component-init.php
- oxygen/component-framework/toolbar/views/global-settings/page-width.view.php
- oxygen/component-framework/angular/controllers/controller.media-queries.js
- oxygen/component-framework/angular/controllers/controller.options.js
- oxygen/component-framework/angular/controllers/iframe.min.js
Теперь подробно разберем какие правки я внес по каждому файлу.
PHP-обработка breakpoints в Oxygen builder
Файл component-init.php
Практически в самом начале я вижу создание переменных под разные точки остановки media query
$media_tablet_width = oxygen_vsb_get_breakpoint_width('tablet');
$media_phone_landscape_width = oxygen_vsb_get_breakpoint_width('phone-landscape');
$media_phone_portrait_width = oxygen_vsb_get_breakpoint_width('phone-portrait');
Добавляем свои переменные. Всего я добавил 4 дополнительных точки:
- small-desktop
- ipad-portrait
- phone-xl
- phone-xs
$media_small_desktop_width = oxygen_vsb_get_breakpoint_width('small-desktop');
$media_ipad_portrait_width = oxygen_vsb_get_breakpoint_width('ipad-portrait');
$media_tablet_width = oxygen_vsb_get_breakpoint_width('tablet');
$media_phone_landscape_width = oxygen_vsb_get_breakpoint_width('phone-landscape');
$media_phone_portrait_width = oxygen_vsb_get_breakpoint_width('phone-portrait');
$media_phone_xl_width = oxygen_vsb_get_breakpoint_width('phone-xl');
$media_phone_xs_width = oxygen_vsb_get_breakpoint_width('phone-xs');
Ниже в массивы добавим свои точки остановки.
Готовый код:
global $media_queries_list;
$media_queries_list = array (
"default" => array(
"maxSize" => "100%",
"title" => "Full Screen"
),
"page-width" => array(
"maxSize" => "", // set when actually use
"title" => "Page container and below"
),
"small-desktop" => array(
"maxSize" => ($media_small_desktop_width) . 'px',
"title" => "Less than {$media_small_desktop_width}px"
),
"ipad-portrait" => array(
"maxSize" => ($media_ipad_portrait_width) . 'px',
"title" => "Less than {$media_ipad_portrait_width}px"
),
"tablet" => array(
"maxSize" => ($media_tablet_width - 1) . 'px',
"title" => "Less than {$media_tablet_width}px"
),
"phone-landscape" => array(
"maxSize" => ($media_phone_landscape_width - 1) . 'px',
"title" => "Less than {$media_phone_landscape_width}px"
),
"phone-portrait" => array(
"maxSize" => ($media_phone_portrait_width - 1) . 'px',
"title" => "Less than {$media_phone_portrait_width}px"
),
"phone-xl" => array(
"maxSize" => ($media_phone_xl_width - 1) . 'px',
"title" => "Less than {$media_phone_xl_width}px"
),
"phone-xs" => array(
"maxSize" => ($media_phone_xs_width - 1) . 'px',
"title" => "Less than {$media_phone_xs_width}px"
),
);
global $media_queries_list_above;
$media_queries_list_above = array (
"default" => array(
"minSize" => "100%",
"title" => "Full Screen"
),
"page-width" => array(
"minSize" => "", // set when actually use
"title" => "Above page container"
),
"small-desktop" => array(
"minSize" => $media_small_desktop_width . 'px',
"title" => "At or above {$media_small_desktop_width}px"
),
"ipad-portrait" => array(
"minSize" => $media_ipad_portrait_width . 'px',
"title" => "At or above {$media_ipad_portrait_width}px"
),
"tablet" => array(
"minSize" => $media_tablet_width . 'px',
"title" => "At or above {$media_tablet_width}px"
),
"phone-landscape" => array(
"minSize" => $media_phone_landscape_width . 'px',
"title" => "At or above {$media_phone_landscape_width}px"
),
"phone-portrait" => array(
"minSize" => $media_phone_portrait_width . 'px',
"title" => "At or above {$media_phone_portrait_width}px"
),
"phone-xl" => array(
"minSize" => $media_phone_xs_width . 'px',
"title" => "At or above {$media_phone_xl_width}px"
),
"phone-xs" => array(
"minSize" => $media_phone_xs_width . 'px',
"title" => "At or above {$media_phone_xs_width}px"
),
);
Далее внизу на строке 4915 пропишем значения по умолчанию:
"breakpoints" => array(
'small-desktop' => 1285,
'ipad-portrait' => 1026,
'tablet' => 992,
'phone-landscape' => 768,
'phone-portrait' => 480,
'phone-xl' => 435,
'phone-xs' => 380,
),
Файл page-width.view.php
Здесь происходит вывод полей в настройки конструктора Oxygen builder. Добавляем также свои breakpoints
<?php
$ct_breakpoints = array(
'small-desktop' => __("Small desktop", 'oxygen'),
'ipad-portrait' => __("Ipad", 'oxygen'),
'tablet' => __("Tablet", 'oxygen'),
'phone-landscape' => __("Landscape", 'oxygen'),
'phone-portrait' => __("Portrait", 'oxygen'),
'phone-xl' => __("Phone Xl", 'oxygen'),
'phone-xs' => __("Phone Xs", 'oxygen'),
);
foreach ($ct_breakpoints as $bp_name => $bp_label){
?>
JS обработка breakpoints
Файл controller.media-queries.js
Здесь в самом начале в функцию initMedia
добавим свои переменные:
$scope.initMedia = function() {
var pageWidth = $scope.getPageWidth();
var smallDesktopWidth = $scope.getBreakPointWidth('small-desktop');
var ipadPortraitWidth = $scope.getBreakPointWidth('ipad-portrait');
var tabletWidth = $scope.getBreakPointWidth('tablet');
var phoneLandscapeWidth = $scope.getBreakPointWidth('phone-landscape');
var phonePortraitWidth = $scope.getBreakPointWidth('phone-portrait');
var phoneXlWidth = $scope.getBreakPointWidth('phone-xl');
var phoneXsWidth = $scope.getBreakPointWidth('phone-xs');
$scope.previousBreakPointsValues = {
'page-width': {
'page': $scope.pageSettingsMeta['max-width'],
'global': $scope.globalSettings['max-width'],
},
'small-desktop': $scope.globalSettings.breakpoints['small-desktop'],
'ipad-portrait': $scope.globalSettings.breakpoints['ipad-portrait'],
'tablet': $scope.globalSettings.breakpoints['tablet'],
'phone-landscape': $scope.globalSettings.breakpoints['phone-landscape'],
'phone-portrait': $scope.globalSettings.breakpoints['phone-portrait'],
'phone-xl': $scope.globalSettings.breakpoints['phone-xl'],
'phone-xs': $scope.globalSettings.breakpoints['phone-xs'],
};
$scope.mediaList = {
default: {
maxSize: "100%",
title: "Full Screen"
},
"page-width": {
maxSize: pageWidth + "px",
title: "Page container (" + pageWidth + "px) and below"
},
"small-desktop": {
maxSize: (smallDesktopWidth - 1) + "px",
title: "Less than " + smallDesktopWidth + "px"
},
"ipad-portrait": {
maxSize: (ipadPortraitWidth) + "px",
title: "Less than " + ipadPortraitWidth + "px"
},
"tablet": {
maxSize: (tabletWidth - 1) + "px",
title: "Less than " + tabletWidth + "px"
},
"phone-landscape": {
maxSize: (phoneLandscapeWidth - 1) + "px",
title: "Less than " + phoneLandscapeWidth + "px"
},
"phone-portrait": {
maxSize: (phonePortraitWidth - 1) + "px",
title: "Less than " + phonePortraitWidth + "px"
},
"phone-xl": {
maxSize: (phoneXlWidth - 1) + "px",
title: "Less than " + phoneXlWidth + "px"
},
"phone-xs": {
maxSize: (phoneXsWidth - 1) + "px",
title: "Less than " + phoneXsWidth + "px"
}
};
$scope.mediaListAbove = {
default: {
minSize: "100%",
title: "Full Screen"
},
"page-width": {
minSize: (pageWidth + 1) + "px",
title: "Above Page container (" + pageWidth + "px)"
},
"small-desktop": {
minSize: smallDesktopWidth + "px",
title: "At or above " + smallDesktopWidth + "px"
},
"ipad-portrait": {
minSize: ipadPortraitWidth + "px",
title: "At or above " + ipadPortraitWidth + "px"
},
"tablet": {
minSize: tabletWidth + "px",
title: "At or above " + tabletWidth + "px"
},
"phone-landscape": {
minSize: phoneLandscapeWidth + "px",
title: "At or above " + phoneLandscapeWidth + "px"
},
"phone-portrait": {
minSize: phonePortraitWidth + "px",
title: "At or above " + phonePortraitWidth + "px"
},
"phone-xl": {
minSize: phoneXlWidth + "px",
title: "At or above " + phoneXlWidth + "px"
},
"phone-xs": {
minSize: phoneXsWidth + "px",
title: "At or above " + phoneXsWidth + "px"
}
};
}
Файл controller.options.js
Здесь в функцию breakPointsUpdate
в оператор switch
добавим:
switch(id) {
case 'small-desktop':
minWidth = $scope.getBreakPointWidth('small-desktop')+1;
maxWidth = $scope.getBreakPointWidth('small-desktop');
name = 'Small desktop';
break;
case 'ipad-portrait':
minWidth = $scope.getBreakPointWidth('ipad-portrait')+1;
maxWidth = $scope.getBreakPointWidth('ipad-portrait');
name = 'Ipad portrait';
break;
case 'tablet':
minWidth = $scope.getBreakPointWidth('phone-landscape')+1;
maxWidth = $scope.getPageWidth()-1;
name = 'Tablet';
break;
case 'phone-landscape':
minWidth = $scope.getBreakPointWidth('phone-portrait')+1;
maxWidth = $scope.getBreakPointWidth('tablet')-1;
name = 'Landscape';
break;
case 'phone-portrait':
minWidth = 320;
maxWidth = $scope.getBreakPointWidth('phone-landscape')-1;
name = 'Portrait';
break;
case 'phone-xl':
minWidth = $scope.getBreakPointWidth('phone-xl')+1;
maxWidth = $scope.getBreakPointWidth('phone-xl')-1;
name = 'Phone Xl';
break;
case 'phone-xs':
minWidth = $scope.getBreakPointWidth('phone-xs')+1;
maxWidth = $scope.getBreakPointWidth('phone-xs')-1;
name = 'Phone Xs';
break;
default:
validate = false;
}
Ниже необходимо закомментировать код, который проверяет значение минимальной ширины, если этого не сделать работать нормально не будет:
if( width < minWidth ){
error = "<div>" + name + " value must be greater than or equal to " + minWidth + "</div>";
} else
if( width > maxWidth ) {
error = "<div>" + name + " value must be less than or equal to " + maxWidth + "</div>";
}
Получаем такой код:
if( validate ){
/*if( width < minWidth ){
error = "<div>" + name + " value must be greater than or equal to " + minWidth + "</div>";
} else
if( width > maxWidth ) {
error = "<div>" + name + " value must be less than or equal to " + maxWidth + "</div>";
}*/
if( error ){
// Revert to previous breakpoint width if the entered value is invalid
$scope.globalSettings.breakpoints[id] = $scope.previousBreakPointsValues[id];
$scope.showNoticeModal(error);
return;
}
// Store the new value as new valid breakpoint value
$scope.previousBreakPointsValues[id] = $scope.globalSettings.breakpoints[id];
}
Файл iframe.min.js
Теперь переходим к самой главной боли данного плагина. Данный файл представляет собой минифицированный webpack, который очень сложно было разбирать и находить, что где работает.
В контроллер ControllerMediaQueries
добавляем свои переменные новых breakpoints:
var e = c.getPageWidth();
var sd = c.getBreakPointWidth("small-desktop");
var ip = c.getBreakPointWidth("ipad-portrait");
var t = c.getBreakPointWidth("tablet");
var i = c.getBreakPointWidth("phone-landscape");
var s = c.getBreakPointWidth("phone-portrait");
var xl = c.getBreakPointWidth("phone-xl");
var xs = c.getBreakPointWidth("phone-xs");
c.previousBreakPointsValues = {
"page-width": {
page: c.pageSettingsMeta["max-width"],
global: c.globalSettings["max-width"]
},
"small-desktop": c.globalSettings.breakpoints["small-desktop"],
"ipad-portrait": c.globalSettings.breakpoints["ipad-portrait"],
tablet: c.globalSettings.breakpoints.tablet,
"phone-landscape": c.globalSettings.breakpoints["phone-landscape"],
"phone-portrait": c.globalSettings.breakpoints["phone-portrait"],
"phone-xl": c.globalSettings.breakpoints["phone-xl"],
"phone-xs": c.globalSettings.breakpoints["phone-xs"]
};
c.mediaList = {
default: {
maxSize: "100%",
title: "Full Screen"
},
"page-width": {
maxSize: e + "px",
title: "Page container (" + e + "px) and below"
},
"small-desktop": {
maxSize: sd + 1 + "px",
title: "Less than " + sd + "px"
},
"ipad-portrait": {
maxSize: ip + 1 + "px",
title: "Less than " + ip + "px"
},
tablet: {
maxSize: t - 1 + "px",
title: "Less than " + t + "px"
},
"phone-landscape": {
maxSize: i - 1 + "px",
title: "Less than " + i + "px"
},
"phone-portrait": {
maxSize: s - 1 + "px",
title: "Less than " + s + "px"
},
"phone-xl": {
maxSize: xl + 1 + "px",
title: "Less than " + xl + "px"
},
"phone-xs": {
maxSize: xs + 1 + "px",
title: "Less than " + xs + "px"
}
};
c.mediaListAbove = {
default: {
minSize: "100%",
title: "Full Screen"
},
"page-width": {
minSize: e + 1 + "px",
title: "Above Page container (" + e + "px)"
},
"small-desktop": {
minSize: sd + "px",
title: "At or above " + sd + "px"
},
"ipad-portrait": {
minSize: ip + "px",
title: "At or above " + ip + "px"
},
tablet: {
minSize: t + "px",
title: "At or above " + t + "px"
},
"phone-landscape": {
minSize: i + "px",
title: "At or above " + i + "px"
},
"phone-portrait": {
minSize: s + "px",
title: "At or above " + s + "px"
},
"phone-xl": {
minSize: xl + "px",
title: "At or above " + xl + "px"
},
"phone-xs": {
minSize: xs + "px",
title: "At or above " + xs + "px"
},
};
};
Примерно на строке 10709 вносим изменения в код и обязательно комментируем проверку в if (s)
:
b.breakPointsUpdate = function (e) {
var o;
var t;
var n;
var i = b.getBreakPointWidth(e);
var s = true;
var a = false;
switch (e) {
case "tablet":
o = b.getBreakPointWidth("phone-landscape") + 1;
t = b.getPageWidth() - 1;
n = "Tablet";
break;
case "phone-landscape":
o = b.getBreakPointWidth("phone-portrait") + 1;
t = b.getBreakPointWidth("tablet") - 1;
n = "Landscape";
break;
case "phone-portrait":
o = 320;
t = b.getBreakPointWidth("phone-landscape") - 1;
n = "Portrait";
break;
case "small-desktop":
o = b.getBreakPointWidth("small-desktop") + 1;
t = b.getBreakPointWidth("small-desktop") + 1;
n = "Small Desktop";
break;
case "ipad-portrait":
o = b.getBreakPointWidth("ipad-portrait") + 1;
t = b.getPageWidth() - 1;
n = "iPad Portrait";
break;
case "phone-xl":
o = b.getBreakPointWidth("phone-xl") + 1;
t = b.getPageWidth() - 1;
n = "Phone Xl";
break;
case "phone-xs":
o = b.getBreakPointWidth("phone-xs") + 1;
t = b.getPageWidth() - 1;
n = "Phone Xs";
break;
default:
s = false;
}
if (s) {
/* if (i < o) {
a = "<div>" + n + " value must be greater than or equal to " + o + "</div>";
} else if (t < i) {
a = "<div>" + n + " value must be less than or equal to " + t + "</div>";
}*/
if (a) {
b.globalSettings.breakpoints[e] = b.previousBreakPointsValues[e];
b.showNoticeModal(a);
return;
}
b.previousBreakPointsValues[e] = b.globalSettings.breakpoints[e];
}
b.mediaList[e] = {
maxSize: i + "px",
title: "Less than " + i + "px"
};
b.mediaListAbove[e] = {
minSize: i + "px",
title: "At or above " + i + "px"
};
b.updateAllComponentsCacheStyles();
b.outputCSSOptions();
b.outputPageSettingsCSS();
y.adjustViewportContainer();
b.unsavedChanges();
};
Иконки, которые изменяют breakpoints в конструкторе
В директории oxygen/component-framework/toolbar/UI/oxygen-icons/media-query есть названия иконок и необходимо либо подгрузить свои иконки, либо скопировать и вставить уже текущие только с новыми названиями. Я сделал по второму варианту и как вы видите названия иконок соответствуют названию breakpoints. Если этого не сделать, то иконки не появятся в конструкторе.
Настройки breakpoints в конструкторе
Важный момент без которого у вас не заработают свои точки остановки и вы не будете видеть изменения в редакторе. В файле component-init.php мы указывали значения своих точек остановок по умолчанию и чтобы выставить корректно настройку нужно прибавить 5 пикселей. Если в значении по умолчанию у вас было 480px, то в настройках выставляете 485px или выше. По сути точные значения не нужны при мобильной верстке, но корректно редактор будет работать именно при таких значений (+5px).
Проверка точек остановок
Как видите все точки появились и вам обязательно нужно будет очистить кеш в настройках конструктора.
Плюсы моего решения
- В самом редакторе разработчиками было сделано так, что точки остановки показывали страницу не совсем корректно, а именно если у вас точка остановки была 768px а другая за ним 480px, то страница показывала 481px вместо 768px, что затрудняло верстку сайта. Теперь значение приближено к тому размеру, какое было указано вами.
- Теперь можно полностью создать страницу без использования своего кода при мобильной верстке.
Минусы решения
Нельзя обновлять плагин
Файлы для скачивания
Я подготовил файлы сразу для замены в плагине. Просто распакуйте и перенесите в папку plugins соглашаясь с заменами.
Обратите внимание, что я не несу ответственность, если у вас пойдет что-то не так и не занимаюсь бесплатной технической поддержкой плагина!
Заключение
Сегодня мы решили вопрос с дополнительными breakpoints в плагине Oxygen builder и это не может не радовать!