# elementor/4.3.0-beta3/modules/variables/services/variables-service.php

Elementor Website Builder – more than just a page builder, version 4.3.0-beta3. 275 lines.

- Page: https://pluginprobe.com/plugins/elementor/4.3.0-beta3/code/modules/variables/services/variables-service.php
- Raw: https://pluginprobe.com/plugins/elementor/4.3.0-beta3/raw/modules/variables/services/variables-service.php
- Modified: 2026-09-17T09:04:38+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/elementor/4.3.0-beta3/code/modules/variables/services/variables-service.php#L10-L20`.

```php
<?php

namespace Elementor\Modules\Variables\Services;

use Elementor\Modules\Variables\Services\Batch_Operations\Batch_Error_Formatter;
use Elementor\Modules\Variables\Services\Batch_Operations\Batch_Processor;
use Elementor\Modules\Variables\Storage\Entities\Variable;
use Elementor\Modules\Variables\Storage\Exceptions\BatchOperationFailed;
use Elementor\Modules\Variables\Storage\Variables_Repository;
use Elementor\Modules\Variables\Storage\Exceptions\FatalError;
use Elementor\Modules\Variables\PropTypes\Size_Variable_Prop_Type;
use Elementor\Utils as ElementorUtils;

class Variables_Service {
	private Variables_Repository $repo;
	private Batch_Processor $batch_processor;

	public function __construct( Variables_Repository $repository, Batch_Processor $batch_processor ) {
		$this->repo = $repository;
		$this->batch_processor = $batch_processor;
	}

	public function get_variables_list(): array {
		return $this->load()['data'];
	}

	public function find_by_label_or_id( string $needle ): ?array {
		$needle = trim( $needle );
		$needle = ltrim( $needle, '-' );

		if ( '' === $needle ) {
			return null;
		}

		$variables = $this->get_variables_list();

		if ( isset( $variables[ $needle ] ) ) {
			$variable = $variables[ $needle ];

			if ( ! empty( $variable['deleted'] ) ) {
				return null;
			}

			return array_merge( [ 'id' => $needle ], $variable );
		}

		foreach ( $variables as $id => $variable ) {
			if ( ! empty( $variable['deleted'] ) ) {
				continue;
			}

			if ( strcasecmp( $variable['label'] ?? '', $needle ) === 0 ) {
				return array_merge( [ 'id' => $id ], $variable );
			}
		}

		return null;
	}

	public function load() {
		$collection = $this->repo->load()->serialize( true );
		foreach ( $collection['data'] as $id => $variable ) {
			if ( ! ElementorUtils::has_pro() && Size_Variable_Prop_Type::get_key() === $variable['type'] ) {
				unset( $collection['data'][ $id ] );
			}
		}
		return $collection;
	}

	/**
	 * @throws BatchOperationFailed Thrown when one of the operations fails and $lenient is false.
	 * @throws FatalError Failed to save after batch.
	 */
	public function process_batch( array $operations, bool $lenient = false ) {
		$collection = $this->repo->load();
		$results = [];
		$errors = [];
		$has_success = false;

		$error_formatter = new Batch_Error_Formatter();

		foreach ( $operations as $index => $operation ) {
			try {
				$batch_result = $this->batch_processor->apply_operation( $collection, $operation );
				$has_success = true;

				if ( $lenient ) {
					$results[] = $this->format_lenient_success_result( $index, $batch_result );
				} else {
					$results[] = $batch_result;
				}
			} catch ( \Exception $e ) {
				if ( $lenient ) {
					$results[] = [
						'index' => $index,
						'status' => 'error',
						'action' => $operation['type'] ?? '',
						'id' => $operation['id'] ?? ( $operation['variable']['id'] ?? null ),
						'code' => $error_formatter->error_code_for( $e ),
						'message' => $e->getMessage(),
					];
				} else {
					$errors[ $this->batch_processor->operation_id( $operation, $index ) ] = [
						'status' => $error_formatter->status_for( $e ),
						'code' => $error_formatter->error_code_for( $e ),
						'message' => $e->getMessage(),
					];
				}
			}
		}

		if ( ! $lenient && ! empty( $errors ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new BatchOperationFailed( 'Batch failed', $errors );
		}

		if ( ! $has_success ) {
			return [
				'success' => false,
				'results' => $results,
				'watermark' => $collection->watermark(),
			];
		}

		$watermark = $this->repo->save( $collection );

		if ( false === $watermark ) {
			throw new FatalError( 'Failed to save batch operations' );
		}

		return [
			'success'   => true,
			'results'   => $results,
			'watermark' => $watermark,
		];
	}

	private function format_lenient_success_result( int $index, array $batch_result ): array {
		$result = [
			'index' => $index,
			'status' => 'ok',
			'action' => $batch_result['type'] ?? '',
			'id' => $batch_result['id'] ?? null,
		];

		if ( isset( $batch_result['variable']['label'] ) ) {
			$result['label'] = $batch_result['variable']['label'];
		}

		if ( isset( $batch_result['variable']['type'] ) ) {
			$result['type'] = $batch_result['variable']['type'];
		}

		return $result;
	}

	/**
	 * @throws FatalError If variable create fails or validation errors occur.
	 */
	public function create( array $data ): array {
		$collection = $this->repo->load();

		$collection->assert_limit_not_reached();
		$collection->assert_label_is_unique( $data['label'] );

		$id = $collection->next_id();
		$data['id'] = $id;

		// TODO: we need to look into this maybe we dont need order to be sent from client. Just implemented as it was
		if ( ! isset( $data['order'] ) ) {
			$data['order'] = $collection->get_next_order();
		}

		$variable = Variable::from_array( $data );
		$variable->validate();

		$collection->add_variable( $variable );

		$watermark = $this->repo->save( $collection );

		if ( false === $watermark ) {
			throw new FatalError( 'Failed to create variable' );
		}

		return [
			'variable' => array_merge( [ 'id' => $id ], $variable->to_array() ),
			'watermark' => $collection->watermark(),
		];
	}

	/**
	 * @throws FatalError If variable update fails.
	 */
	public function update( string $id, array $data ): array {
		$collection = $this->repo->load();
		$variable = $collection->find_or_fail( $id );

		if ( isset( $data['label'] ) ) {
			$collection->assert_label_is_unique( $data['label'], $id );
		}

		$variable->apply_changes( $data );
		$variable->validate();

		$watermark = $this->repo->save( $collection );

		if ( false === $watermark ) {
			throw new FatalError( 'Failed to update variable' );
		}

		return [
			'variable' => array_merge( [ 'id' => $id ], $variable->to_array() ),
			'watermark' => $watermark,
		];
	}

	/**
	 * @throws FatalError If variable delete fails.
	 */
	public function delete( string $id ) {
		$collection = $this->repo->load();
		$variable = $collection->find_or_fail( $id );

		$variable->soft_delete();

		$watermark = $this->repo->save( $collection );

		if ( false === $watermark ) {
			throw new FatalError( 'Failed to delete variable' );
		}

		return [
			'watermark' => $watermark,
			'variable' => array_merge( [
				'id' => $id,
				'deleted' => true,
			], $variable->to_array() ),
		];
	}

	/**
	 * @throws FatalError If variable restore fails.
	 */
	public function restore( string $id, $overrides = [] ) {
		$collection = $this->repo->load();
		$variable = $collection->find_or_fail( $id );

		$label = $variable->label();

		if ( isset( $overrides['label'] ) ) {
			$label = $overrides['label'];
		}

		$collection->assert_limit_not_reached();

		$collection->assert_label_is_unique( $label, $variable->id() );

		$variable->apply_changes( $overrides );
		$variable->validate();

		$variable->restore();

		$watermark = $this->repo->save( $collection );

		if ( false === $watermark ) {
			throw new FatalError( 'Failed to delete variable' );
		}

		return [
			'variable' => array_merge( [ 'id' => $id ], $variable->to_array() ),
			'watermark' => $watermark,
		];
	}
}

```
