
WP BOX сразу доступен с Docker Compose установкой и скриптами для сборки Docker образов. При установке и запуске вы получите 8 контейнеров, со всем, что нужно для работы вебсайта. Благодаря этому подходу WP BOX можно установить как на удаленный сервер, так и на ваш персональный компьютер за короткое время и с начальными опытом работы с серверным ПО. Легко сделайте сервер из вашего личного ПК!
Перед установкой вы сможете выбрать MariaDB или PostgreSQL заготовку, которая и будет использовать для запуска сайта.
services:
php-fpm-custom:
depends_on:
- db
user: ${USER_ID}:${GROUP_ID}
image: php-fpm-custom:latest
container_name: php-fpm-custom
links:
- nginx-custom:nginx-custom
- postfix-custom:postfix-custom
build:
context: docker/php-fpm/
args:
USER_ID: ${USER_ID}
GROUP_ID: ${GROUP_ID}
POSTFIX_DOMAIN: ${POSTFIX_DOMAIN}
ENABLE_XDEBUG: ${ENABLE_XDEBUG}
restart: always
ports:
- 9000:9000
volumes:
- .:/var/www/site
networks:
- wpbox-network
PHP сервис запускает PHP скрипты, на которых написана серверная часть WordPress и WP BOX. Докер образ собирается со всеми рекомендуемыми и некоторыми необязательными дополнениями и библиотеками для максимальной эффективности.
Nginx это вебсервер который перенаправляет запросы пользователей на соответствующие ресурсы. При сборке образа передаются переменные из .env, так что вам не придется вручную редактировать конфигурацию вебсервера.
Дополнительные переменные также подключат SSL и доступ к менеджеру базы данных — phpmyadmin или adminer.
services:
nginx-custom:
image: nginx-custom:latest
container_name: nginx-custom
build:
context: docker/nginx/
args:
USER_ID: ${USER_ID}
GROUP_ID: ${GROUP_ID}
SITE_DOMAIN: ${SITE_DOMAIN}
DB_HOST: ${DB_HOST}
DB_ADMIN_WEBPATH: ${DB_ADMIN_WEBPATH}
restart: always
volumes:
- .:/var/www/site
- ./certbot/conf/:/etc/letsencrypt/:ro
- ./certbot/www/:/var/www/letsencrypt/:ro
extra_hosts:
- "host.docker.internal:host-gateway"
expose:
- '80'
- '443'
ports:
- 80:80
- 443:443
networks:
- wpbox-network
services:
postfix-custom:
image: postfix-custom:latest
container_name: postfix-custom
build:
context: docker/postfix/
environment:
- DOCKER_SUBNET=${DOCKER_SUBNET}
- POSTFIX_DOMAIN=${POSTFIX_DOMAIN}
- MY_DESTINATION=${MY_DESTINATION}
restart: always
volumes:
- ./postfix:/var/spool/postfix
expose:
- '25'
- '465'
- '587'
networks:
- wpbox-network
Почтовый сервер, который управляет отправкой писем. В нем есть множество фишек, таких как очереди отправки и в целом он широко распространен. В WP BOX он настроен для отправки писем через SendGrid (у них есть бесплатный уровень для небольшого количества почты)
Отправляйте письма с вашего сайта единообразно во время разработки и в продакшене и не беспокойтесь о потерянной почте. Если сервис отправки писем недоступен — postfix сохраняет письма в файловой системе и пробует отправить повторно до получения положительного ответа.
Полезный сервис, который отвечает за создание SSL сертификатов.
Если WP BOX установлен на сервере и привязан к домену — сервис создаст сертификат через Lets Encrypt и будет автоматически продлевать его, в другом случае будет использоваться самоподписанный сертификат.
Сервис также обновляет конфигурацию Nginx и перезапускает контейнер при обновлении сертфиката.
services:
certbot-custom:
container_name: certbot-custom
image: certbot-custom:latest
build:
context: docker/certbot/
args:
USER_ID: ${USER_ID}
GROUP_ID: ${GROUP_ID}
restart: always
environment:
- USER_ID=${USER_ID}
- GROUP_ID=${GROUP_ID}
- FIRST_USER_EMAIL=${FIRST_USER_EMAIL}
- SITE_DOMAIN=${SITE_DOMAIN}
- CERT_MODE=${CERT_MODE}
- HOOK=docker restart nginx-custom
volumes:
- ./certbot/www/:/var/www/letsencrypt/:rw
- ./certbot/conf/:/etc/letsencrypt/:rw
- /var/run/docker.sock:/var/run/docker.sock
services:
node-custom:
container_name: node-custom
image: node-custom:latest
tty: true
stdin_open: true
volumes:
- .:/var/www/site
build:
context: docker/node/
args:
USER_ID: ${USER_ID}
GROUP_ID: ${GROUP_ID}
restart: always
command: "tail -f /dev/null"
networks:
- wpbox-network
Оставшиеся сервисы в основном используют официальные Docker образы без значимых изменений.
WP BOX реализует серверную логику темы и собственных плагинов в виде классов для взаимодействия с ядром WordPress, следуя архитектурным паттернам и стилю рекомендуемым сообществом. Вы можете использовать их как они есть, учиться на них или изменить в соответствии со своими нуждами.
Основная идея заключается в том, чтобы выделить отдельный класс для взаимодействия с каждой отдельной сущностью ядра, такими как посты и таксономии, а также использовать отдельные классы для реализации другой бизнес логики.
Некоторые примеры далее:
Класс Uploads устанавливает размеры изображений для ресайза при загрузке, сохраняет место на диске за счет удаления больших оригиналов, заменяя их крупным ресайзом и модифицирует базу данных, чтобы сохранить эти манипуляции.
Вполне нужная вещь, да?
class Uploads
{
public function __construct()
{
add_action('after_setup_theme', [ 'WPBOX\Uploads', 'thumbnails_supports' ]);
add_action('after_setup_theme', [ 'WPBOX\Uploads', 'media_uploads_setup' ]);
add_filter('wp_generate_attachment_metadata', [ 'WPBOX\Uploads', 'delete_fullsize_image' ]);
}
class Users
{
public function __construct()
{
add_action('rest_api_init', [ $this, 'rest_hooks' ]);
add_action('init', [ $this, 'ajax_hooks' ]);
add_action('generate_rewrite_rules', [ $this, 'rewrite_rules' ], 999);
}
public function rewrite_rules( \WP_Rewrite $wp_rewrite )
{
$rules[ 'authors/?$' ] = 'index.php?pagename=authors';
$rules[ 'authors/page/([0-9]+)?/?$' ] = 'index.php?pagename=authors&paged=$matches[1]';
$rules[ 'authors/([^/]*)/?$' ] = 'index.php?author_name=$matches[1]';
$wp_rewrite->rules = ( $rules + $wp_rewrite->rules );
}
public function rest_hooks()
{
register_rest_route(
'usermeta',
'/validate',
[
'permission_callback' => '__return_true',
'methods' => 'GET',
'callback' => [
$this,
'validate_confirmation_key',
],
]
);
Этот отличный класс — первая необходимость если вы планируете создать любого рода личный кабинет и в общем предоставить пользователям функционал, доступный после авторизации.
Класс уже включает методы для подверждения почты, изменения адресов, логина и регистрации через нестандартные формы, и через сторонние социальные сети, такие как Google или Facebook.
Это мой любимый, потому что у него нет аналогов с похожей функциональностью. Что он делает, так это позволяет сгенерировать длинный и сложный <picture> с множеством источников для разных экранов и с поддержкой разных типов файлов через всего один универсальный метод.
Вот так просто:PictureGenerator::the_picture_html($image_id, $class_names, $max_width, $max_height, $caption, $object_fit);
Он во всю используется в блоках ядра через перегрузку, а также при рендере блоков WP BOX. Генерация файлов .webp реализована через плагин WebpExpress, который автоматически устанавливается как зависимость при установке WP BOX.
<figure>
<picture>
<source srcset="https://example.com/app/uploads/2024/05/a-600x600.png.webp 600w"
type="image/webp" media="(max-width: 600px)" sizes="600px">
<source srcset="https://example.com/app/uploads/2024/05/a-600x600.png 600w"
type="image/png" media="(max-width: 600px)" sizes="600px">
<source srcset="https://example.com/app/uploads/2024/05/a-992x992.png.webp 992w"
type="image/webp" media="(max-width: 992px)" sizes="992px">
<source srcset="https://example.com/app/uploads/2024/05/a-992x992.png 992w"
type="image/png" media="(max-width: 992px)" sizes="992px">
<source srcset="https://example.com/app/uploads/2024/05/a.png.webp 1024w"
type="image/webp" media="(max-width: 1024px)" sizes="1024px">
<source srcset="https://example.com/app/uploads/2024/05/a.png 1024w" type="image/png"
media="(max-width: 1024px)" sizes="1024px">
<source srcset="https://example.com/app/uploads/2024/05/a.png.webp 1024w"
type="image/webp" sizes="1024px">
<source srcset="https://example.com/app/uploads/2024/05/a.png 1024w" type="image/png"
sizes="1024px"><img decoding="async" class="text-wrap p-4 html lazy rounded-md h-full w-full object-cover" loading="lazy"
fetchpriority="low" src="https://example.com/app/uploads/2024/05/a.png"
srcset="https://example.com/app/uploads/2024/05/a-600x600.png 600w, https://example.com/app/uploads/2024/05/a-992x992.png 992w, https://example.com/app/uploads/2024/05/a.png 1024w, https://example.com/app/uploads/2024/05/a.png"
sizes="(max-width: 600px) 600px(max-width: 992px) 992px(max-width: 1024px) 1024px" alt=""
title="ComfyUI_temp_rysjp_00008_">
</picture>
</figure>
class ThemeStyles
{
public function __construct()
{
add_action('wp_enqueue_scripts', [ 'WPBOX\ThemeStyles', 'tailwind_styles' ]);
add_action('wp_enqueue_scripts', [ 'WPBOX\ThemeStyles', 'public_libs' ]);
add_action('wp_body_open', [ 'WPBOX\ThemeStyles', 'apply_theme_styles_from_localstorage' ]);
add_filter('safe_style_css', [ 'WPBOX\ThemeStyles', 'safe_style_css' ]);
add_filter('safecss_filter_attr_allow_css', [ 'WPBOX\ThemeStyles', 'safecss_filter_attr_allow_css' ], 10, 2);
add_action('wp_enqueue_scripts', [ 'WPBOX\ThemeStyles', 'deregister_styles' ], 100);
// Admin methods
add_action('admin_enqueue_scripts', [ 'WPBOX\ThemeStyles', 'tailwind_styles' ], 99999);
add_action('enqueue_block_editor_assets', [ 'WPBOX\ThemeStyles', 'tailwind_styles' ], 99999);
add_action('enqueue_block_assets', [ 'WPBOX\ThemeStyles', 'tailwind_styles' ], 99999);
}
В целом довольно стандартный класс, чтобы регистрировать хуки и фильтры относящиеся к стилям. В случае WP BOX — класс регистрирует скомпилированный файл стилей формируемый через Tailwind CSS и добавляет некоторые модификаторы к методам ядра.
Также предусмотрено автоматическое подключение различных стилей, которые вы разместите в /styles/dist/, как в варианте только при необходимости, так и с глобальным подключением.
По аналогии с ThemeStyles этот обычный класс делает все, что необходимо для регистрации и подключения скриптов.
Не относящиеся к блокам скрипты подключаются глобально, тогда как библиотеки нужные для работы скриптов блоков только регистрируются и подключаются если указаны в зависимостях Gutenberg блоков.
class ThemeScripts
{
public function __construct()
{
add_action('admin_enqueue_scripts', [ $this, 'admin_scripts' ], 1);
add_action('wp_enqueue_scripts', [ $this, 'public_libs' ], 1);
add_action('wp_enqueue_scripts', [ $this, 'public_scripts' ], 1);
}
class ThemeBlocks
{
public function __construct()
{
add_action('init', [ 'WPBOX\ThemeBlocks', 'theme_gutenberg_blocks' ]);
add_filter('should_load_remote_block_patterns', '__return_false'); //remove remote patterns from internet in editor
add_filter('block_categories_all', [ 'WPBOX\ThemeBlocks', 'register_block_categories' ]);
add_action('after_setup_theme', [ 'WPBOX\ThemeBlocks', 'blocks_supports' ]);
}
private static function register_blocks( string $directory_path, bool $child_theme = false )
{
$block_files = glob($directory_path . '**/*.block.js');
$theme_directory_uri = $child_theme ? get_stylesheet_directory_uri() : get_template_directory_uri();
$theme_directory_path = $child_theme ? get_stylesheet_directory() : get_template_directory();
if (! empty($block_files)) {
foreach ($block_files as $block_file) {
$block_json = dirname($block_file) . '/block.json';
$block_basename = basename($block_file, '.block.js');
$block_name = str_replace('_', '-', $block_basename);
$has_frontend_script = file_exists(dirname($block_file) . '/assets/js/script.min.js');
Стоит обратить внимание на этот класс, отвечающий за единое управление Gutenberg блоками во всем проекте. В нем есть методы которые сканируют директории и находят файлы для регистрации блоков и их зависимостей.
По аналогии с этим классом, вы увидите несколько других, делающих тоже самое для перегрузки блоков, паттернов и вариаций — ThemeBlocksOverrides, ThemeBlocksPatters и ThemeBlocksVariations соответственно.