<?php
declare(strict_types=1);
namespace MPBC;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
final class Assets {
/**
* Item format:
* - <code>[ $handle => $file ]</code>
* - <code>[ $handle => [ $file, $dependencies?, $version?, $in_footer? = true ] ]</code>
* - <code>[ $handle => [ [ $file, $min_file ], $dependencies?, $version?, $in_footer? = true ] ]</code>
*/
private const SCRIPTS = array(
'vendors' => array(
'flatpickr' => array( array( 'flatpickr-4.6.13/dist/flatpickr.js', 'flatpickr-4.6.13/dist/flatpickr.min.js' ), array(), '4.6.13' ),
'flatpickr-l10n' => array( 'flatpickr-4.6.13/dist/l10n/default.js', array(), '4.6.13' ), // Replace "default" later
),
'admin' => array(
'mpbc-edit-booking' => 'admin/edit-booking.js',
'mpbc-manage-properties' => array( 'admin/manage-properties.js', array( 'wp-api-fetch' ) ),
),
'public' => array(
'mpbc-public' => array( 'public/public.js', array( 'flatpickr', 'flatpickr-l10n', 'wp-api-fetch', 'wp-date', 'wp-hooks', 'wp-i18n', 'wp-url' ) ),
),
);
/**
* Item format:
* - <code>[ $handle => $file ]</code>
* - <code>[ $handle => [ $file, $dependencies?, $version?, $media? = "all" ] ]</code>
* - <code>[ $handle => [ [ $file, $min_file ], $dependencies?, $version?, $media? = "all" ] ]</code>
*/
private const STYLES = array(
'vendors' => array(
'flatpickr' => array( array( 'flatpickr-4.6.13/dist/flatpickr.css', 'flatpickr-4.6.13/dist/flatpickr.min.css' ), array(), '4.6.13' ),
),
'admin' => array(
'mpbc-admin' => 'admin/admin.css',
'mpbc-edit-booking' => 'admin/edit-booking.css',
'mpbc-manage-properties' => 'admin/manage-properties.css',
'mpbc-settings' => 'admin/settings.css',
'mpbc-upgrade-to-premium' => 'admin/upgrade-to-premium.css',
),
'public' => array(
'mpbc-icons' => array( 'icons/mpbc-icons.css' ),
'mpbc-public' => array( 'public/public.css', array( 'flatpickr', 'mpbc-icons' ) ),
),
);
private const BUNDLES = array(
'mpbc-property-calendar' => array(
'dir' => 'property-calendar/',
'style_deps' => array( 'wp-components' ),
),
'mpbc-property-form' => array(
'dir' => 'property-form/',
'style_deps' => array( 'wp-components', 'wp-edit-blocks', 'wp-block-editor' ),
),
'mpbc-guide' => array(
'dir' => 'guide/',
'style_deps' => array( 'wp-components' ),
),
);
private array $scripts = array();
private array $styles = array();
private array $enqueued_scripts = array();
/**
* @var array [ Handle => [ Object name => Object data (array) ] ]
*/
private array $script_data = array();
public function __construct() {
if ( ! wp_doing_ajax() && ! wp_doing_cron() ) {
// The plugin uses priority 5 to register scripts like Flatpickr
// before other plugins (in particular, Appointment Booking) and use
// its own version
add_action( 'init', array( $this, 'init_assets' ), 5 );
if ( is_admin() ) {
add_action( 'admin_enqueue_scripts', array( $this, 'register_assets' ), 5 );
} else {
// Use "init" instead of "wp_enqueue_scripts". Otherwise, the
// Appointment Booking plugin will register its own and more
// outdated version of Flatpickr.
add_action( 'init', array( $this, 'register_assets' ), 5 );
}
// The default priority of 10 may be too late. Add inline scripts
// before calling wp_enqueue_script().
add_action( 'wp_print_footer_scripts', array( $this, 'flush_script_data' ), 9 );
add_action( 'admin_print_footer_scripts', array( $this, 'flush_script_data' ), 9 );
}
}
/**
* @access private
*/
public function init_assets(): void {
if ( is_admin() && ( wp_doing_ajax() || wp_doing_cron() ) ) {
return;
}
if ( is_admin() ) {
$scripts = self::SCRIPTS['vendors'] + self::SCRIPTS['admin'];
$styles = self::STYLES['vendors'] + self::STYLES['admin'];
} else {
$scripts = self::SCRIPTS['vendors'] + self::SCRIPTS['public'];
$styles = self::STYLES['vendors'] + self::STYLES['public'];
}
// Add scripts
$plugin_version = mpbc()->get_version();
foreach ( $scripts as $handle => $script_args ) {
list( $file, $dependencies, $version, $in_footer )
= (array) $script_args + array( '', array(), $plugin_version, true );
$this->scripts[ $handle ] = array( $file, $dependencies, $version, $in_footer );
}
// Add styles
foreach ( $styles as $handle => $style_args ) {
list( $file, $dependencies, $version, $media )
= (array) $style_args + array( '', array(), $plugin_version, 'all' );
$this->styles[ $handle ] = array( $file, $dependencies, $version, $media );
}
// Change Flatpickr localization script for current language
$flatpickr_locale = Settings::get_flatpickr_locale();
if ( $flatpickr_locale !== 'default' ) {
$l10n_script = $this->scripts['flatpickr-l10n'][0];
$l10n_script = str_replace( 'default.js', "{$flatpickr_locale}.js", $l10n_script );
$this->scripts['flatpickr-l10n'][0] = $l10n_script;
}
}
/**
* @access private
*/
public function register_assets(): void {
// Register scripts
foreach ( $this->scripts as $handle => $script_args ) {
list( $file, $dependencies, $version, $in_footer ) = $script_args;
wp_register_script(
$handle,
$this->get_file_url( $file ),
$dependencies,
$version,
$in_footer
);
}
// Register styles
foreach ( $this->styles as $handle => $style_args ) {
list( $file, $dependencies, $version, $media ) = $style_args;
wp_register_style(
$handle,
$this->get_file_url( $file ),
$dependencies,
$version,
$media
);
}
}
public function enqueue_assets( string $handle ): void {
$this->enqueue_script( $handle );
$this->enqueue_style( $handle );
}
public function enqueue_script( string $handle ): void {
if ( ! array_key_exists( $handle, $this->scripts ) // Not our script
|| in_array( $handle, $this->enqueued_scripts ) // Already enqueued
) {
return;
}
wp_enqueue_script( $handle );
$this->enqueued_scripts[] = $handle;
// Load script translations
$dependencies = $this->scripts[ $handle ][1];
if ( in_array( 'wp-i18n', $dependencies ) ) {
wp_set_script_translations( $handle, 'motopress-booking-calendar', mpbc()->get_file_path( 'languages/' ) );
}
}
public function enqueue_style( string $handle ): void {
wp_enqueue_style( $handle );
}
public function enqueue_bundle( string $bundle_name ): void {
$bundle = self::BUNDLES[ $bundle_name ] ?? null;
if ( is_null( $bundle ) ) {
return;
}
$dir = $bundle['dir'];
$index_file = $bundle['index'] ?? $dir . 'index.asset.php';
$script_file = $bundle['script'] ?? $dir . 'index.js';
$style_file = $bundle['style'] ?? $dir . 'index.css';
$index_path = mpbc()->get_file_path( 'assets/' . $index_file );
$script_args = is_file( $index_path )
? require $index_path
: array(
'dependencies' => array(),
'version' => mpbc()->get_version(),
);
if ( ! empty( $script_file ) ) {
wp_enqueue_script(
$bundle_name,
$this->get_file_url( $script_file ),
$script_args['dependencies'],
$script_args['version'],
true
);
}
if ( ! empty( $style_file ) ) {
wp_enqueue_style(
$bundle_name,
$this->get_file_url( $style_file ),
$bundle['style_deps'] ?? array(),
mpbc()->get_version(),
'all'
);
}
// Load script translations
if ( in_array( 'wp-i18n', $script_args['dependencies'] ) ) {
wp_set_script_translations( $bundle_name, 'motopress-booking-calendar', mpbc()->get_file_path( 'languages/' ) );
}
}
/**
* @param string|string[] $dependency
*/
public function add_script_dependency( string $handle, $dependency ): void {
if ( ! array_key_exists( $handle, $this->scripts ) ) {
return;
}
if ( ! is_array( $dependency ) ) {
$this->scripts[ $handle ][1][] = $dependency;
} else {
$this->scripts[ $handle ][1] = array_merge( $this->scripts[ $handle ][1], $dependency );
}
}
public function add_script_data( string $handle, string $object_name, array $data ): void {
if ( ! isset( $this->script_data[ $handle ][ $object_name ] ) ) {
$this->script_data[ $handle ][ $object_name ] = $data;
} else {
$this->script_data[ $handle ][ $object_name ] = mpbc_array_merge_recursive_distinct( $this->script_data[ $handle ][ $object_name ], $data );
}
}
/**
* @access private
*/
public function flush_script_data(): void {
$handles = $this->enqueued_scripts;
foreach ( $handles as $handle ) {
if ( ! array_key_exists( $handle, $this->script_data ) ) {
continue;
}
foreach ( $this->script_data[ $handle ] as $object_name => $object_data ) {
$data_str = json_encode( $object_data );
$data_js = "const {$object_name} = {$data_str};";
wp_add_inline_script( $handle, $data_js, 'before' );
}
}
}
/**
* @param string|string[] $file
*/
private function get_file_url( $file ): string {
if ( is_array( $file ) ) {
if ( static::is_script_debug() ) {
$file = $file[0];
} else {
$file = $file[1];
}
}
return mpbc()->get_file_url( 'assets/' . $file );
}
/**
* @return string[] Script handles.
*/
private function get_scripts_by_dependency( string $dependency ): array {
$scripts_with_dependency = array();
foreach ( $this->scripts as $handle => $script_args ) {
if ( in_array( $dependency, $script_args[1] ) ) {
$scripts_with_dependency[] = $handle;
}
}
return $scripts_with_dependency;
}
public static function is_script_debug(): bool {
return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
}
}