AlkantarClanX12

Your IP : 216.73.217.24


Current Path : /www/capitalgmcbuickregina_830/public/wp-content/plugins/wp-cerber/admin/includes/
Upload File :
Current File : /www/capitalgmcbuickregina_830/public/wp-content/plugins/wp-cerber/admin/includes/CRB_Widgets.php

<?php

/**
 * WP Cerber Dashboard Widget Manager
 *
 * Provides functionality to register, render, and manage WP Cerber dashboard widgets,
 * including user-specific settings such as widget display order.
 *
 * @since 9.6.4.2
 */
final class CRB_Widgets {

	// All widgets are here
	private static array $widgets = array();

	// If a widget loaded from the cache
	static bool $from_cache = false;

	/**
	 * A key indicating that there is nothing to cache and show placeholder
	 */
	public const NO_DATA = 'no_data';

	/**
	 * Registers a new dashboard widget.
	 *
	 * @param string $id Unique identifier for the widget.
	 * @param string $title The title of the widget displayed in the heading of the widget
	 * @param string $sub_title Subtitle displayed next to the title
	 * @param string $controls HTML content for the widget's control area, if any.
	 *
	 * @param callable $callback Renders the widget body.
	 *                             Expected return value:
	 *                             - string: Widget body HTML.
	 *                             - array{0: string, 1?: bool, 2?: bool}:
	 *                               [0] Widget body HTML.
	 *                               [1] Whether to display the controls area (default: true).
	 *                               [2] Whether the widget body should be loaded via AJAX (default: false).
	 * @param array{0?: string, 1?: int} $cache_config Optional caching configuration.
	 *                             If not empty and a persistent object cache is available, widget content may be cached.
	 *                             [0] Cache key for the data source.
	 *                             [1] Allowed **lag** behind the data source, in seconds (default: 60).
	 * @param array{no_heading?: bool, hideable?: bool} $flags Miscellaneous flags.
	 *                             - no_heading: Hide the widget UI heading (default: false).
	 *                             - hideable: Allow hiding from the Dashboard by the admin (default: true).
	 *
	 * @return void
	 */
	public static function register( string $id, string $title, string $sub_title, string $controls, callable $callback, array $cache_config = [], array $flags = [] ) {
		$flag_defaults = array(
			'no_heading' => false,
			'hideable'   => true
		);

		$flags = array_merge( $flag_defaults, array_intersect_key( $flags, $flag_defaults ) );

		$configuration = array_merge( array( $title, $controls, $callback, $cache_config, 'sub_title' => $sub_title ), $flags );

		self::$widgets[ crb_sanitize_id( $id ) ] = $configuration;
	}

	/**
	 * Returns a list of all registered widget IDs and their titles.
	 *
	 * @param bool $sort Optional. Whether to sort the widgets based on the saved user order of widgets.
	 * @param bool $active_only Optional. Whether to filter out the widgets based on the saved user list of active widgets.
	 *
	 * @return array An associative array where the keys are widget IDs and the values are widget titles.
	 */
	public static function get_titles( bool $sort = false, bool $active_only = true ): array {
		if ( ! self::$widgets ) {
			return array();
		}

		$result = array();

		foreach ( self::$widgets as $id => $widget ) {
			$result[ $id ] = array( $widget[0], $widget['sub_title'] );
		}

		if ( $active_only
		     && $list = self::get_active_list() ) {
			$result = array_intersect_key( $result, array_filter( $list ) );
		}

		if ( $sort
		     && ( $order = self::get_screen_parameter( 'widget_order' ) )
		     && ! crb_is_wp_error( $order ) ) {

			$order = array_filter( $order );
			$order_indices = array_flip( $order );

			uksort( $result, function ( $a, $b ) use ( $order_indices ) {
				return ( $order_indices[ $a ] ?? 0 ) <=> ( $order_indices[ $b ] ?? 0 );
			} );
		}

		return $result;
	}

	/**
	 * Returns the HTML content for a widget's control area.
	 *
	 * @param string $widget_id The ID of the widget.
	 *
	 * @return string The HTML content of the widget controls, or an empty string if no controls are defined.
	 */
	public static function get_controls( string $widget_id ): string {
		return self::$widgets[ $widget_id ][1] ?? '';
	}

	/**
	 * Determines whether the widget header will be shown or hidden
	 * when displaying the given widget on admin pages
	 *
	 * @param string $widget_id
	 *
	 * @return bool If true, the widget header must be hidden
	 */
	public static function hide_header( string $widget_id ): bool {
		return ! empty( self::$widgets[ $widget_id ]['no_heading'] );
	}

	/**
	 * Determines whether the widget can be hidden on admin pages.
	 *
	 * @param string $widget_id
	 *
	 * @return bool True if the widget is hideable.
	 */
	public static function is_hideable( string $widget_id ): bool {
		return (bool) ( self::$widgets[ $widget_id ]['hideable'] ?? true );
	}

	/**
	 * Renders a dashboard widget by its ID.
	 *
	 * @param string $widget_id The ID of the widget to render.
	 * @param bool $is_ajax Optional. Whether the rendering is triggered in an AJAX context. Default false.
	 *
	 * @return string|array|WP_Error The rendered widget content as a string or an array,
	 *                               or a WP_Error object if the widget cannot be rendered.
	 */
	public static function render_widget( string $widget_id, bool $is_ajax = false ) {
		if ( ! $widget = self::$widgets[ $widget_id ] ?? false ) {
			return new WP_Error( 'cerber_widget_not_found', 'Widget not found:' . $widget_id );
		}

		if ( $cached = self::get_cache( $widget_id ) ) {
			self::$from_cache = true;

			return $cached;
		}

		self::$from_cache = false;

		$callback = $widget[2];

		if ( ! is_callable( $callback ) ) {
			return new WP_Error( 'cerber_not_callable', 'Widget callback is not callable (Widget ID ' . $widget_id . ').' );
		}

		try {
			$result = call_user_func( $callback, $is_ajax );
		} catch ( Exception $e ) {
			return new WP_Error(
				'cerber_callback_error',
				'An exception occurred during widget callback execution (Widget ID ' . $widget_id . '). ERROR: ' . $e->getMessage(),
				array( 'exception' => $e->getMessage() )
			);
		}

		if ( crb_is_wp_error( $result ) ) {
			return $result;
		}

		if ( $placeholder = crb_array_get( $result, self::NO_DATA ) ) {
			// There is nothing to display, we show a placeholder
			return array( '<div class="crb-dash-padding crb-dash-placeholder">' . $placeholder . '</div>', false );
		}

		self::set_cache( $widget_id, $result );

		if ( $is_ajax
		     || ! is_array( $result ) ) {
			return $result;
		}

		// Check if AJAX loading is required - based on the returned value from the callback

		$ajax = $result[2] ?? false;

		if ( ! $ajax ) {
			return $result;
		}

		return self::get_ajax_area( $widget_id );
	}

	/**
	 * Retrieves a widget's content from the WordPress persistent object cache.
	 * Note: If no persistent object cache is available, the content will be lost between HTTP requests.
	 *
	 * @param string $widget_id The ID of the widget.
	 *
	 * @return mixed|false The cached widget content if available and valid. Returns false if:
	 *                     - The cache is unavailable.
	 *                     - The cache has expired.
	 *                     - The widget does not have a valid cache configuration.
	 */
	private static function get_cache( string $widget_id ) {
		list ( $source_key, $lag ) = self::get_cache_params( $widget_id );

		if ( ! $source_key
		     || ! ( $source = cerber_cache_get( $source_key, false ) )
		     || ! ( $modified = $source['data_modified'] ?? false )
		     || ! ( $cached = cerber_cache_get( 'dash_widget_' . $widget_id, false ) )
		     || empty( $cached['widget'] ) ) {

			return false;
		}

		$saved = $cached['saved'];

		// Check if the cache has expired
		if ( ( $saved + $lag ) < $modified ) {
			return false;
		}

		// Check if the cache is stale
		if ( $saved < $modified
		     && $saved < ( time() - 600 ) ) {
			return false;
		}

		return $cached['widget'];
	}


	/**
	 * Saves a widget's rendered content to the WordPress persistent object cache.
	 * Note: If no persistent object cache is available, the content will be lost between HTTP requests.
	 *
	 * @param string $widget_id The unique identifier of the widget.
	 * @param array|string $contents The content of the widget to be cached.
	 *
	 * @return bool True if the cache entry was successfully saved, false otherwise.
	 *
	 */
	private static function set_cache( string $widget_id, $contents ) {
		list ( $source_key, $lag ) = self::get_cache_params( $widget_id );

		if ( ! $source_key ) {
			return false;
		}

		return cerber_cache_set( 'dash_widget_' . $widget_id, array( 'widget' => $contents, 'saved' => time(), 'lag' => $lag ) );
	}

	/**
	 * Purges all cached widgets
	 *
	 * @param string $widget_id
	 *
	 * @return void
	 */
	public static function purge_cache( string $widget_id = '' ) {
		if ( $widget_id ) {
			cerber_cache_set( 'dash_widget_' . $widget_id, array( 'purged' => time() ) );

			return;
		}

		foreach ( array_keys( self::$widgets ) as $widget_id ) {
			cerber_cache_set( 'dash_widget_' . $widget_id, array( 'purged' => time() ) );
		}
	}

	/**
	 * Returns cache parameters if specified for a widget. Parameters are defined when registering widgets.
	 *
	 * @param string $widget_id Widget ID.
	 *
	 * @return array Contains 1) key to get the last modification time of the data source and 2) Allowed lag behind the data source
	 */
	private static function get_cache_params( string $widget_id ): array {
		$key = self::$widgets[ $widget_id ][3][0] ?? '';
		$lag = self::$widgets[ $widget_id ][3][1] ?? 120; // Default value is 2 minutes

		return array( $key, $lag );
	}

	/**
	 * Forcefully update widget cache elements that will expire soon
	 *
	 * @return void
	 */
	public static function update_cache() {
		if ( ! self::$widgets
		     || ! CRB_Cache::checker()
		     || ! is_super_admin() ) {
			return;
		}

		foreach ( array_keys( self::$widgets ) as $widget_id ) {
			list ( $source_key, $lag ) = self::get_cache_params( $widget_id );

			if ( ! $source_key ) { // Meaning cache not in use for this widget
				continue;
			}

			// Do we have valid data source modification time?

			if ( ! ( $source = cerber_cache_get( $source_key, false ) )
			     || ! ( $modified = $source['data_modified'] ?? false ) ) {
				continue;
			}

			// Try to get widget from cache

			if ( ! ( $cached = cerber_cache_get( 'dash_widget_' . $widget_id, false ) )
			     || ! ( $saved = $cached['saved'] ?? false ) ) {

				self::render_widget( $widget_id );
				continue;
			}

			// If cache will expire soon (less than in 30 sec) we update it preliminary

			if ( ( $saved + $lag - 30 ) < $modified ) {
				self::purge_cache( $widget_id );
				self::render_widget( $widget_id );
			}
		}
	}

	/**
	 * Updates the list of active widgets for the current user on a specific admin screen.
	 *
	 * @param array $post_fields Array containing $_POST fields that represent enabled widgets as array keys
	 * @param string $screen
	 *
	 * @return true|WP_Error
	 */
	public static function save_list( $post_fields, string $screen = 'main' ) {
		if ( empty( self::$widgets ) ) {
			return new WP_Error( 'cerber_no_widgets', 'No widgets are registered yet. Did you forget to call ' . __CLASS__ . '::register();?' );
		}

		// Make sure we're saving existing widget IDs only

		$widgets = array_fill_keys( array_keys( self::$widgets ), 0 );
		$list = array_merge( $widgets, array_intersect_key( $post_fields, $widgets ) );

		// Sanitize values

		$list = array_map( function ( $val ) {
			return absint( $val );
		}, $list );

		return self::save_screen_parameter( 'widget_list', $list, $screen );
	}

	/**
	 * Returns the list of active widgets for the current user on a specific admin screen.
	 *
	 * @param string $screen
	 *
	 * @return array The list of active widgets, including those that were registered after the list was saved.
	 */
	public static function get_active_list( string $screen = 'main' ) {
		if ( empty( self::$widgets ) ) {
			return array();
		}

		$list = self::get_screen_parameter( 'widget_list', $screen );

		if ( crb_is_wp_error( $list ) ) {
			return self::$widgets;
		}

		$disabled = array_filter( $list, function ( $value ) {
			return empty( $value );
		} );

		foreach ( $disabled as $widget_id => $value ) {
			if ( ! self::is_hideable( $widget_id ) ) {
				unset( $disabled[ $widget_id ] );
			}
		}

		return array_diff_key( self::$widgets, $disabled );
	}

	/**
	 * Check if the widget is active for the current user on a specific admin screen.
	 *
	 * @param string $widget_id The ID of the widget to check.
	 * @param string $screen The target screen ID.
	 *
	 * @return bool True if the widget is active.
	 */
	public static function is_active( string $widget_id, string $screen = 'main' ) {
		$list = self::get_active_list( $screen );

		return isset( $list[ $widget_id ] );
	}

	/**
	 * Updates the display order of widgets for the current user on a specific admin screen.
	 *
	 * @param array $order An array of widget IDs in the desired display order.
	 * @param string $screen Optional. The admin screen ID where the order applies. Default 'main'.
	 *
	 * @return true|WP_Error True on success, or a WP_Error object on failure.
	 */
	public static function save_order( array $order, string $screen = 'main' ) {

		$order = array_filter( $order );

		return self::save_screen_parameter( 'widget_order', $order, $screen );
	}

	/**
	 * Save a specific configuration parameter for the current user and a given screen (admin page)
	 *
	 * @param string $key The screen meta key to save/retrieve the parameter.
	 * @param array $value The parameter value.
	 * @param string $screen Optional. The admin screen ID where the $value saved for. Default 'main'.
	 *
	 * @return true|WP_Error True on success, or a WP_Error object on failure.
	 */
	private static function save_screen_parameter( string $key, array $value, string $screen = 'main' ) {
		if ( ! $user_id = get_current_user_id() ) {
			return new WP_Error( 'cerber_non_user', 'User is not authenticated.' );
		}

		$meta = get_user_meta( $user_id, 'cerber_dashboard_config', true );

		if ( ! is_array( $meta ) ) {
			$meta = array();
		}

		$meta[ $screen ][ $key ] = $value;

		if ( ! update_user_meta( $user_id, 'cerber_dashboard_config', $meta ) ) {
			return new WP_Error( 'cerber_not_updated', 'User meta not updated. Possibly duplicate value.' );
		}

		return true;
	}

	/**
	 * Retrieve a configuration parameter specified by $key for the current user and a given screen (admin page)
	 *
	 * @param string $key The screen meta key to save/retrieve the parameter
	 * @param string $screen Optional. The admin screen ID where the $value saved for. Default 'main'.
	 *
	 * @return array|WP_Error The parameter value, or a WP_Error object on failure.
	 */
	public static function get_screen_parameter( string $key, string $screen = 'main' ) {
		if ( ! $user_id = get_current_user_id() ) {
			return new WP_Error( 'cerber_non_user', 'User is not authenticated.' );
		}

		if ( ( $meta = get_user_meta( $user_id, 'cerber_dashboard_config', true ) )
		     && ( $value = $meta[ $screen ][ $key ] ?? false )
		     && is_array( $value ) ) {

			return $value;
		}

		return array();
	}

	/**
	 * Generates an HTML skeleton loader for a table-like structure.
	 *
	 * @param int $rows Optional. The number of rows to generate.
	 * @param int $cols Optional. The number of columns to generate.
	 *
	 * @return string The generated HTML for the skeleton loader.
	 */
	static function get_skeleton( int $rows = 5, int $cols = 5 ): string {

		$html = '<div class="crb-skeleton-table">';

		for ( $i = 0; $i < $rows; $i ++ ) {
			$html .= '<div class="crb-skeleton-row">';

			$html .= str_repeat( '<div class="crb-skeleton-cell"></div>', $cols );

			$html .= '</div>' . PHP_EOL;
		}

		$html .= '</div>';

		return $html;
	}

	/**
	 * Generates an HTML container for asynchronously loading a widget via AJAX.
	 *
	 * @param string $widget_id The unique ID of the widget to load via AJAX.
	 *
	 * @return string The generated HTML container with AJAX-related attributes.
	 */
	static function get_ajax_area( string $widget_id ): string {

		return '<div class="crb_async_content" data-ajax_route="dashboard_analytics" data-ds_widget="' . crb_escape_html( $widget_id ) . '">' . self::get_skeleton() . '</div>';

	}
}

Home - Capital GMC Buick Regina

No data

Welcome to Capital GMC BUICK – REGINA

Thank you for choosing Capital GMC Buick | Regina, your premier certified Buick and GMC dealership proudly serving drivers in Regina and the surrounding communities. Whether you’re searching for a brand-new Buick or GMC vehicle or a meticulously inspected pre-owned model, we have a diverse selection to match your needs and lifestyle.

Beyond our impressive inventory, we offer a seamless and stress-free financing experience through our well-connected finance centre, where our team of experts is dedicated to securing the best loan or lease options for you, quickly, transparently, and hassle-free.

But our commitment to you doesn’t stop at the sale. Our state-of-the-art service centre is staffed with skilled Buick and GMC technicians who use the latest equipment and genuine OEM parts to keep your vehicle running at its best. From routine maintenance to complex repairs, we’ve got you covered.

Experience top-tier customer service, quality vehicles, and expert care, all in one place. Visit Capital GMC Buick | Regina today or call us at 306-205-8072 with any questions. We’re here to help!

Ask a Question