HEX
Server: Apache
System: Linux linplesk41.pumo.com.tw 3.10.0-962.3.2.lve1.5.27.el7.x86_64 #1 SMP Sat Nov 30 02:18:52 EST 2019 x86_64
User: rajlaw (10192)
PHP: 7.4.24
Disabled: phpinfo,passthru,exec,shell_exec,system,popen,proc_open,proc_close,show_source,pcntl_exec,escapeshellcmd,proc_get_status,proc_nice,proc_terminate,escapeshellarg
Upload Files
File: /home/httpd/vhosts/rajlaw.com.tw/httpdocs/wp-content/plugins/blockart-blocks/includes/Blocks.php
<?php
/**
 * BlockArt Blocks.
 *
 * Manages all the blocks & block categories.
 * Manages the blocks that need to be prepared for CSS generation.
 *
 * @since 1.0.0
 * @package BlockArt
 */

namespace BlockArt;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

use BlockArt\BlockTypes\Image;
use BlockArt\BlockTypes\ImageComparison;
use BlockArt\Traits\Singleton;
use BlockArt\BlockTypes\Button;
use BlockArt\BlockTypes\Column;
use BlockArt\BlockTypes\Buttons;
use BlockArt\BlockTypes\Slider;
use BlockArt\BlockTypes\Testimonial;
use BlockArt\BlockTypes\Heading;
use BlockArt\BlockTypes\Counter;
use BlockArt\BlockTypes\Section;
use BlockArt\BlockTypes\Spacing;
use BlockArt\BlockTypes\Team;
use BlockArt\BlockTypes\Info;
use BlockArt\BlockTypes\Paragraph;
use BlockArt\BlockTypes\FAQ;
use BlockArt\BlockTypes\FAQs;
use BlockArt\BlockTypes\SocialShare;
use BlockArt\BlockTypes\SocialInner;
use BlockArt\BlockTypes\Tabs;
use BlockArt\BlockTypes\Tab;
use BlockArt\BlockTypes\TabTitles;
use BlockArt\BlockTypes\TableOfContents;
use BlockArt\BlockTypes\Lottie;
use BlockArt\BlockTypes\Countdown;
use BlockArt\BlockTypes\Progress;
use BlockArt\BlockTypes\CallToAction;
use BlockArt\BlockTypes\Slide;
use BlockArt\BlockTypes\TestimonialSlide;
use BlockArt\BlockTypes\Map;
use BlockArt\BlockTypes\AbstractBlock;
use BlockArt\BlockTypes\Blockquote;
use BlockArt\BlockTypes\Timeline;
use BlockArt\BlockTypes\TimelineInner;
use BlockArt\BlockTypes\Notice;
use BlockArt\BlockTypes\ImageGallery;
use BlockArt\BlockTypes\PriceList;
use BlockArt\BlockTypes\PriceListChild;
use BlockArt\BlockTypes\Price;
use BlockArt\BlockTypes\IconList;
use BlockArt\BlockTypes\IconListItem;
use BlockArt\BlockTypes\Icon;
use BlockArt\BlockTypes\Modal;

/**
 * BlockArt Blocks.
 *
 * Manages all the blocks & block categories.
 * Manages the blocks that need to be prepared for CSS generation.
 *
 * @since 1.0.0
 */
class Blocks {

	use Singleton;

	/**
	 * Block styles.
	 *
	 * @var BlockStyles|null $block_styles
	 */
	private $block_styles;

	/**
	 * Blocks that need to be prepared for CSS generation.
	 *
	 * @var array $prepared_blocks
	 */
	private $prepared_blocks = array();

	/**
	 * Prepared widget blocks.
	 *
	 * @var array
	 */
	private $prepared_widget_blocks = array();

	/**
	 * Constructor.
	 */
	protected function __construct() {
		$this->init_hooks();
	}

	/**
	 * Init hooks.
	 *
	 * @since 1.0.0
	 */
	private function init_hooks() {
		$block_categories_hook   = version_compare( get_bloginfo( 'version' ), '5.8', '>=' ) ?
			'block_categories_all' :
			'block_categories';
		$preload_api_hook_handle = class_exists( 'WP_Block_Editor_Context' ) ? 'block_editor_rest_api_preload_paths' : 'block_editor_preload_paths';

		add_action( 'init', array( $this, 'register_block_types' ) );
		add_filter( $block_categories_hook, array( $this, 'block_categories' ), PHP_INT_MAX, 2 );
		add_filter( $preload_api_hook_handle, array( $this, 'preload_rest_api_path' ), 10, 2 );

		add_filter( 'pre_render_block', array( $this, 'maybe_prepare_blocks' ), 10, 3 );
		add_filter( 'wp_head', array( $this, 'maybe_prepare_blocks' ), 0 );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_blocks_styles' ), 100 );

		add_action( 'customize_save_after', array( $this, 'maybe_clear_widget_block_styles' ) );
		add_action( 'rest_after_save_widget', array( $this, 'maybe_clear_widget_block_styles' ) );
		add_action( 'after_switch_theme', array( $this, 'maybe_clear_block_styles_on_theme_switch' ), 10, 2 );
		add_action( 'save_post', array( $this, 'maybe_clear_block_styles' ), 10, 2 );
		add_action( 'delete_post', array( $this, 'maybe_clear_block_styles' ), 10, 2 );
		add_action( 'blockart_responsive_breakpoints_changed', array( $this, 'regenerate_block_styles' ) );
	}

	/**
	 * Preload REST api path.
	 *
	 * @param array                                   $paths Rest API paths.
	 * @param \WP_Block_Editor_Context|\WP_Post|mixed $context Current editor context.
	 *
	 * @return array
	 */
	public function preload_rest_api_path( array $paths, $context ): array {
		if (
			$context instanceof \WP_Post ||
			( isset( $context->name ) && in_array( $context->name, array( 'core/edit-site', 'core/edit-post' ), true ) )
		) {
			$paths[] = '/blockart/v1/library-data';
		}
		return $paths;
	}

	/**
	 * Prepare blocks for FSE themes.
	 */
	public function maybe_prepare_blocks() {
		if ( blockart_is_block_theme() && doing_filter( 'pre_render_block' ) ) {
			$args                    = func_get_args();
			$block                   = $args[1];
			$this->prepared_blocks[] = $block;
			return $args[0];
		}
		if ( ! blockart_is_block_theme() && doing_action( 'wp_head' ) ) {
			$this->prepared_blocks        = parse_blocks( get_the_content() );
			$this->prepared_widget_blocks = $this->get_widget_blocks();
		}
	}

	/**
	 * Enqueue blocks styles.
	 *
	 * @return void
	 */
	public function enqueue_blocks_styles() {
		$fonts = [];

		if ( ! blockart_is_block_theme() ) {
			$this->prepared_widget_blocks = blockart_process_blocks( $this->prepared_widget_blocks );
			$widget_styles                = blockart_generate_blocks_styles( $this->prepared_widget_blocks, 'widgets' );
			$fonts                        = $widget_styles->get_fonts();
			$widget_styles->enqueue();

			if ( empty( $this->prepared_blocks ) ) {
				$widget_styles->enqueue_fonts();
			}
		}

		if ( ! empty( $this->prepared_blocks ) ) {
			$this->prepared_blocks = blockart_process_blocks( $this->prepared_blocks );
			$styles                = blockart_generate_blocks_styles( $this->prepared_blocks );
			$styles->enqueue_fonts( $fonts );
			$styles->enqueue();
		}
	}

	/**
	 * Register block types.
	 *
	 * @return void
	 */
	public function register_block_types() {
		$block_types = $this->get_block_types();
		foreach ( $block_types as $block_type ) {
			new $block_type();
		}
	}

	/**
	 * Get block types.
	 *
	 * @return AbstractBlock[]
	 */
	private function get_block_types(): array {
		return apply_filters(
			'blockart_block_types',
			array(
				Button::class,
				Buttons::class,
				Slider::class,
				Heading::class,
				Counter::class,
				Paragraph::class,
				Column::class,
				Section::class,
				Spacing::class,
				Info::class,
				Image::class,
				FAQ::class,
				FAQs::class,
				SocialShare::class,
				SocialInner::class,
				Tabs::class,
				Tab::class,
				TabTitles::class,
				TableOfContents::class,
				Lottie::class,
				Team::class,
				Countdown::class,
				Blockquote::class,
				Timeline::class,
				TimelineInner::class,
				Notice::class,
				Progress::class,
				CallToAction::class,
				Slide::class,
				Testimonial::class,
				TestimonialSlide::class,
				Map::class,
				ImageGallery::class,
				IconList::class,
				IconListItem::class,
				Icon::class,
				Modal::class,
				ImageComparison::class,
				PriceList::class,
				PriceListChild::class,
				Price::class,
			)
		);
	}

	/**
	 * Add "BlockArt" category to the blocks listing in post edit screen.
	 *
	 * @param array $block_categories All registered block categories.
	 * @return array
	 * @since 1.0.0
	 */
	public function block_categories( array $block_categories ): array {
		return array_merge(
			array(
				array(
					'slug'  => 'blockart',
					'title' => esc_html__( 'BlockArt', 'blockart' ),
				),
			),
			$block_categories
		);
	}

	/**
	 * Clear cached widget styles when widget is updated.
	 *
	 * @return void
	 */
	public function maybe_clear_widget_block_styles() {
		$cached = get_option( '_blockart_blocks_css', array() );
		blockart_array_forget( $cached, 'widgets' );
		update_option( '_blockart_blocks_css', $cached );
	}

	/**
	 * Clear cached styles when theme is switched.
	 *
	 * If is block theme then clear all cached styles stored in options table.
	 * As block theme fully depends on blocks.
	 *
	 * @param string    $name string Theme name.
	 * @param \WP_Theme $theme Theme object.
	 * @return void
	 */
	public function maybe_clear_block_styles_on_theme_switch( string $name, \WP_Theme $theme ) {
		if ( $theme->is_block_theme() ) {
			delete_option( '_blockart_blocks_css' );
		}
	}

	/**
	 * Clear or update cached styles.
	 *
	 * @param int      $id Post ID.
	 * @param \WP_Post $post Post object.
	 * @return void
	 */
	public function maybe_clear_block_styles( $id, \WP_Post $post ) {
		if ( doing_action( 'save_post' ) ) {
			// Don't make style for reusable blocks.
			if ( 'wp_block' === $post->post_type ) {
				return;
			}

			// Clear cached styles when template part or template is updated.
			if ( 'wp_template_part' === $post->post_type || 'wp_template' === $post->post_type ) {
				delete_option( '_blockart_blocks_css' );
				return;
			}

			delete_post_meta( $id, '_blockart_blocks_css' );
		}

		if ( doing_action( 'delete_post' ) ) {
			$filesystem = blockart_get_filesystem();
			if ( $filesystem ) {
				$css_files = $filesystem->dirlist( BLOCKART_UPLOAD_DIR );
				if ( ! empty( $css_files ) ) {
					foreach ( $css_files as $css_file ) {
						if ( false !== strpos( $css_file['name'], "ba-style-$id-" ) ) {
							$filesystem->delete( BLOCKART_UPLOAD_DIR . $css_file['name'] );
							break;
						}
					}
				}
			}
		}
	}

	/**
	 * Get widget blocks.
	 *
	 * @return array
	 */
	private function get_widget_blocks() {
		return parse_blocks(
			array_reduce(
				get_option( 'widget_block', array() ),
				function ( $acc, $curr ) {
					if ( ! empty( $curr['content'] ) ) {
						$acc .= $curr['content'];
					}
					return $acc;
				},
				''
			)
		);
	}

	/**
	 * Regenerate block styles.
	 *
	 * @return void
	 */
	public function regenerate_block_styles() {
		delete_option( '_blockart_blocks_css' );
		delete_post_meta_by_key( '_blockart_blocks_css' );

		$filesystem = blockart_get_filesystem();

		if ( $filesystem ) {
			$filesystem->delete( BLOCKART_UPLOAD_DIR, true );
		}
	}
}