Backend Features
Баннер
В этой секции:

Контейнеризированный WordPress

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-FPM сервис

PHP сервис запускает PHP скрипты, на которых написана серверная часть WordPress и WP BOX. Докер образ собирается со всеми рекомендуемыми и некоторыми необязательными дополнениями и библиотеками для максимальной эффективности.

  • GD and Imagick
  • MSMTP
  • Relay (for redis)
  • Composer
  • WP CLI
  • XDebug

NGINX сервис

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

POSTFIX сервис

Почтовый сервер, который управляет отправкой писем. В нем есть множество фишек, таких как очереди отправки и в целом он широко распространен. В WP BOX он настроен для отправки писем через SendGrid (у них есть бесплатный уровень для небольшого количества почты)

Отправляйте письма с вашего сайта единообразно во время разработки и в продакшене и не беспокойтесь о потерянной почте. Если сервис отправки писем недоступен — postfix сохраняет письма в файловой системе и пробует отправить повторно до получения положительного ответа.

CERTBOT сервис

Полезный сервис, который отвечает за создание 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 образы без значимых изменений.

  • db / pgdb:
    сервис базы данных, в зависимости от выбранной базы.
  • redis:
    сервис для объектного кэширования и снижения нагрузки на базу данных.
  • phpmyadmin / adminer:
    сервис для визуальной работы с базой данных.
  • node-custom:
    сервис для сборки фронтенда
В этой секции:

Классы Бэкенда

WP BOX реализует серверную логику темы и собственных плагинов в виде классов для взаимодействия с ядром WordPress, следуя архитектурным паттернам и стилю рекомендуемым сообществом. Вы можете использовать их как они есть, учиться на них или изменить в соответствии со своими нуждами.

Основная идея заключается в том, чтобы выделить отдельный класс для взаимодействия с каждой отдельной сущностью ядра, такими как посты и таксономии, а также использовать отдельные классы для реализации другой бизнес логики.

Некоторые примеры далее:

Uploads

Класс 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',
				],
			]
		);

Users

Этот отличный класс — первая необходимость если вы планируете создать любого рода личный кабинет и в общем предоставить пользователям функционал, доступный после авторизации.

Класс уже включает методы для подверждения почты, изменения адресов, логина и регистрации через нестандартные формы, и через сторонние социальные сети, такие как Google или Facebook.

PictureGenerator

Это мой любимый, потому что у него нет аналогов с похожей функциональностью. Что он делает, так это позволяет сгенерировать длинный и сложный <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);
	}

ThemeStyles

В целом довольно стандартный класс, чтобы регистрировать хуки и фильтры относящиеся к стилям. В случае WP BOX — класс регистрирует скомпилированный файл стилей формируемый через Tailwind CSS и добавляет некоторые модификаторы к методам ядра.

Также предусмотрено автоматическое подключение различных стилей, которые вы разместите в /styles/dist/, как в варианте только при необходимости, так и с глобальным подключением.

ThemeScripts

По аналогии с 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');

ThemeBlocks

Стоит обратить внимание на этот класс, отвечающий за единое управление Gutenberg блоками во всем проекте. В нем есть методы которые сканируют директории и находят файлы для регистрации блоков и их зависимостей.

По аналогии с этим классом, вы увидите несколько других, делающих тоже самое для перегрузки блоков, паттернов и вариаций — ThemeBlocksOverrides, ThemeBlocksPatters и ThemeBlocksVariations соответственно.