<?php
/**
 * Dynamic stylesheets functions.
 *
 * @package The7
 */

defined( 'ABSPATH' ) || exit;

if ( ! function_exists( 'presscore_get_dynamic_stylesheets_list' ) ) :

	/**
	 * Return list of dynamic stylesheets.
	 *
	 * @return array
	 */
	function presscore_get_dynamic_stylesheets_list() {
		$dynamic_stylesheets = [];

		/**
		 * CSS vars is generated dynamically based on registered less vars.
		 *
		 * There is no actual css-vars.less file.
		 *
		 * @see presscore_regenerate_dynamic_css
		 */
		$dynamic_stylesheets['the7-css-vars'] = [
			'src' => 'css-vars.less',
		];

		$dynamic_import_top = [];

		$dynamic_import_top['gutenberg'] = 'dynamic-less/plugins/gutenberg.less';
		if ( The7_Admin_Dashboard_Settings::get( 'disable-gutenberg-styles' ) ) {
			unset( $dynamic_import_top['gutenberg'] );
		}
		if ( the7_elementor_is_active() ) {
			if ( the7_is_elementor_schemes_disabled() || the7_is_elementor_buttons_integration_enabled() ) {
				$dynamic_import_top[] = 'dynamic-less/elementor/global.less';
			}

			if (!the7_is_elementor_theme_style_enabled()){
				$dynamic_import_top[] = 'dynamic-less/elementor/kit-css-vars.less';
			}
			if ( the7_is_elementor_buttons_integration_enabled() ) {
				$dynamic_import_top[] = 'dynamic-less/elementor/buttons.less';
			}
			if ( The7_Admin_Dashboard_Settings::get( 'elementor-zero-paragraph-last-spacing' ) ) {
				$dynamic_import_top[] = 'dynamic-less/elementor/last-spacing.less';
			}
		}

		$dynamic_import_bottom = [];

		if ( The7_Admin_Dashboard_Settings::get( 'overlapping-headers' ) ) {
			$dynamic_import_bottom[] = 'legacy/overlap-header.less';
		}
		switch ( of_get_option( 'header-layout' ) ) {
			case 'classic':
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_horizontal-headers.less';
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_classic-header.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_horizontal-headers.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_classic-header.less';
				break;
			case 'inline':
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_horizontal-headers.less';
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_inline-header.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_horizontal-headers.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_inline-header.less';
				break;
			case 'split':
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_horizontal-headers.less';
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_split-header.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_horizontal-headers.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_split-header.less';
				break;
			case 'side':
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_vertical-headers.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_vertical-headers.less';
				break;
			case 'top_line':
			case 'side_line':
			case 'menu_icon':
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_mixed-headers.less';
				$dynamic_import_top[]    = 'dynamic-less/header/header-layouts/static/_vertical-headers.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_mixed-headers.less';
				$dynamic_import_bottom[] = 'dynamic-less/header/header-layouts/_vertical-headers.less';
				break;
			case 'disabled':
				break;
		}

		$dynamic_import_bottom[] = 'dynamic-less/plugins/wpbakery.less';

		if (the7_is_elementor_theme_style_enabled()){
			$dynamic_import_bottom[] = 'dynamic-less/elementor/elementor-theme-styles.less';
		}

		$dynamic_stylesheets['dt-custom'] = [
			'src'     => 'custom.less',
			'imports' => compact( 'dynamic_import_top', 'dynamic_import_bottom' ),
		];

		if ( the7_is_woocommerce_enabled() ) {
			$dynamic_stylesheets['wc-dt-custom'] = [
				'src' => 'compatibility/wc-dt-custom.less',
			];
		}

		if ( presscore_responsive() ) {
			$dynamic_stylesheets['dt-media'] = [
				'src' => 'media.less',
			];
		}

		if ( The7_Admin_Dashboard_Settings::get( 'mega-menu' ) ) {
			$dynamic_stylesheets['the7-mega-menu'] = [
				'src' => 'mega-menu.less',
			];
		}

		if ( The7_Admin_Dashboard_Settings::get( 'rows' ) ) {
			$dynamic_stylesheets['the7-stripes'] = [
				'src'          => 'legacy/stripes.less',
				'auto_enqueue' => false,
			];
		}

		$dynamic_stylesheets = apply_filters( 'presscore_get_dynamic_stylesheets_list', $dynamic_stylesheets );

		// Backward compatibility.
		foreach ( $dynamic_stylesheets as &$stylesheet ) {
			$stylesheet['src'] = str_replace( PRESSCORE_THEME_URI . '/css/', '', $stylesheet['src'] );
		}

		return $dynamic_stylesheets;
	}

endif;

if ( ! function_exists( 'presscore_get_admin_dynamic_stylesheets_list' ) ) {

	/**
	 * Return array of admin dynamic css.
	 *
	 * @since 7.2.0
	 *
	 * @return array
	 */
	function presscore_get_admin_dynamic_stylesheets_list() {
		return array(
			'the7-admin-custom' => array(
				'src' => 'admin-custom.less',
			),
		);
	}
}

if ( ! function_exists( 'presscore_enqueue_dynamic_stylesheets' ) ) :

	/**
	 * Enqueue *.less files
	 */
	function presscore_enqueue_dynamic_stylesheets() {
		$dynamic_stylesheets = presscore_get_dynamic_stylesheets_list();
		$css_cache           = presscore_get_dynamic_css_cache();
		$css_version         = presscore_get_dynamic_css_version();

		foreach ( $dynamic_stylesheets as $handle => $stylesheet ) {
			$stylesheet_obj = new The7_Dynamic_Stylesheet( $handle, $stylesheet['src'] );
			$stylesheet_obj->setup_with_array( $stylesheet );
			$stylesheet_obj->set_version( $css_version );

			if ( is_array( $css_cache ) && array_key_exists( $handle, $css_cache ) ) {
				$stylesheet_obj->set_css_body( $css_cache[ $handle ] );
			}

			$stylesheet_obj->register();

			if ( ! isset( $stylesheet['auto_enqueue'] ) || $stylesheet['auto_enqueue'] === true ) {
				$stylesheet_obj->enqueue();
			}
		}

		do_action( 'presscore_enqueue_dynamic_stylesheets' );
	}

endif;

if ( ! function_exists( 'presscore_regenerate_dynamic_css' ) ) :

	/**
	 * Generate css from dynamic stylesheets list.
	 *
	 * @param array $dynamic_css Dynamic stylesheets list.
	 *
	 * @throws Exception If any stylesheet cannot be compiled or written. The
	 *                   previously published version is left in place.
	 */
	function presscore_regenerate_dynamic_css( $dynamic_css ) {
		include_once PRESSCORE_DIR . '/less-vars.php';

		$wp_upload = wp_get_upload_dir();
		$less_vars_manager = the7_get_new_less_vars_manager();
		$less_vars = presscore_compile_less_vars( $less_vars_manager );
		$lessc     = new The7_Less_Compiler( $less_vars );

		// Compile beautiful loading css.
		$beautiful_loading_css = $lessc->compile_file( The7_Dynamic_Stylesheet::get_theme_css_dir() . '/beautiful-loading.less' );
		presscore_cache_loader_inline_css( $beautiful_loading_css );
		unset( $beautiful_loading_css );

		/**
		 * Css vars file.
		 *
		 * It is written below, together with the rest of the stylesheets, so that
		 * a failure to write it also stops the new version from being published.
		 *
		 * @see presscore_get_dynamic_stylesheets_list
		 */
		$css_vars_file = null;
		if ( isset( $dynamic_css['the7-css-vars']['src'] ) ) {
			$css_vars_stylesheet = new The7_Dynamic_Stylesheet( 'the7-css-vars', $dynamic_css['the7-css-vars']['src'] );
			unset( $dynamic_css['the7-css-vars'] );

			$css_vars_file = new The7_CSS_Vars_File( $css_vars_stylesheet->get_css_file() );
		}

		if ( $lessc->is_writable( $wp_upload['basedir'] ) ) {
			update_option( 'presscore_less_css_is_writable', 1 );

			if ( $css_vars_file ) {
				$css_vars_file->generate_based_on_less_vars( $less_vars_manager->storage()->get_css_vars(), $lessc );
			}

			// Compile less.
			foreach ( $dynamic_css as $handle => $stylesheet ) {
				$stylesheet_obj = new The7_Dynamic_Stylesheet( $handle, $stylesheet['src'] );

				if ( ! empty( $stylesheet['path'] ) ) {
					$stylesheet_obj->set_less_file( $stylesheet['path'] );
				}

				$imports = empty( $stylesheet['imports'] ) ? array() : $stylesheet['imports'];
				$lessc->compile_to_file(
					$stylesheet_obj->get_less_file(),
					$stylesheet_obj->get_css_file(),
					$imports
				);
			}

			/**
			 * Publish the new version only once every file is on disk.
			 *
			 * The version becomes the ?ver= of the enqueued url. Publishing it
			 * before the files exist lets concurrent requests - and any cache
			 * plugin behind them - reference a stylesheet that is missing or
			 * half written. If the loop above throws, the previous version stays
			 * published and the previous, complete files keep being served.
			 */
			presscore_set_dynamic_css_cache( array() );
			presscore_set_dynamic_css_version( substr( md5( PRESSCORE_STYLESHEETS_VERSION . '-' . time() ), 20 ) );
		} else {
			update_option( 'presscore_less_css_is_writable', 0 );

			// Save css body in db.
			$dynamic_css_cache = array();
			foreach ( $dynamic_css as $handle => $stylesheet ) {
				$stylesheet_obj = new The7_Dynamic_Stylesheet( $handle, $stylesheet['src'] );

				if ( ! empty( $stylesheet['path'] ) ) {
					$stylesheet_obj->set_less_file( $stylesheet['path'] );
				}

				$dynamic_css_cache[ $handle ] = $lessc->compile_file( $stylesheet_obj->get_less_file() );
			}
			presscore_set_dynamic_css_cache( $dynamic_css_cache );
		}
	}

endif;

function the7_generate_dynamic_css_as_text( $dynamic_css ) {
	include_once PRESSCORE_DIR . '/less-vars.php';

	$less_vars = presscore_compile_less_vars();
	$lessc     = new The7_Less_Compiler( $less_vars );

	$dynamic_css_cache = array();
	foreach ( $dynamic_css as $handle => $stylesheet ) {
		$stylesheet_obj = new The7_Dynamic_Stylesheet( $handle, $stylesheet['src'] );

		if ( ! empty( $stylesheet['path'] ) ) {
			$stylesheet_obj->set_less_file( $stylesheet['path'] );
		}

		$imports = empty( $stylesheet['imports'] ) ? array() : $stylesheet['imports'];
		$dynamic_css_cache[ $handle ] = $lessc->compile_file( $stylesheet_obj->get_less_file(), $imports );
	}

	return $dynamic_css_cache;
}

/**
 * Store CSS code of each stylesheet to be enqueued inline.
 *
 * @param array $dynamic_css Array of compiled dynamic stylesheets.
 */
function presscore_set_dynamic_css_cache( $dynamic_css ) {
	update_option( 'the7_dynamic_css_cache', $dynamic_css );
}

/**
 * Return an array of compiled CSS code of each dynamic stylesheet.
 *
 * @return array
 */
function presscore_get_dynamic_css_cache() {
	return (array) get_option( 'the7_dynamic_css_cache', array() );
}

/**
 * Set dynamic css version.
 *
 * @param string $version Dynamic css version.
 */
function presscore_set_dynamic_css_version( $version ) {
	update_option( 'the7_dynamic_css_version', $version );
}

/**
 * Return dynamic css version.
 *
 * @return string|bool
 */
function presscore_get_dynamic_css_version() {
	return get_option( 'the7_dynamic_css_version' );
}

if ( ! function_exists( 'the7_maybe_regenerate_dynamic_css' ) ) :

	/**
	 * Regenerate dynamic css by force if needed.
	 *
	 * This function used mostly for after theme update stylesheets refresh.
	 *
	 * @since 5.5.0
	 */
	function the7_maybe_regenerate_dynamic_css() {
		$force_regenerate = presscore_force_regenerate_css();

		// Regenerate dynamic stylesheets if their definitions are changed.
		$dynamic_stylesheets      = presscore_get_dynamic_stylesheets_list();
		$dynamic_stylesheets_hash = md5( wp_json_encode( $dynamic_stylesheets ) );
		$hash_changed             = $dynamic_stylesheets_hash !== get_option( 'the7_last_dynamic_stylesheets_hash' );
		if ( $hash_changed ) {
			$force_regenerate = true;
		}

		if ( ! $force_regenerate ) {
			return;
		}

		/**
		 * Back off after a failed attempt.
		 *
		 * This runs on wp_head on every front end request, so without a cooldown
		 * a permanently failing compile would be retried on every page view.
		 */
		if ( get_transient( THE7_CSS_REGEN_BACKOFF_TRANSIENT ) ) {
			return;
		}

		// Only one process regenerates at a time; the rest keep serving the current css.
		if ( ! the7_claim_dynamic_css_lock() ) {
			return;
		}

		/*
		 * Take the decision again, now that the lock is held.
		 *
		 * The checks above ran before the lock. A process that read the force
		 * flag while the winner was still compiling, and got the lock right after
		 * the winner released it, would otherwise compile the whole stylesheet set
		 * a second time and publish a second version - a new ?ver= on every url,
		 * for work that is already done.
		 *
		 * The triggers are read straight from the database, as the lock is. Both
		 * are autoloaded, so with a persistent object cache they arrive inside the
		 * alloptions blob this request already holds; get_option() would hand back
		 * the very values that are stale here and the re-check would do nothing.
		 */
		$triggers     = the7_read_dynamic_css_triggers();
		$hash_changed = $dynamic_stylesheets_hash !== $triggers['hash'];
		if ( ! $hash_changed && ! $triggers['force'] ) {
			the7_release_dynamic_css_lock();

			return;
		}

		/*
		 * Arm the cooldown before the work, not after a caught failure.
		 *
		 * Compiling the full stylesheet set is the kind of work that dies without
		 * ever reaching a catch block: exhausting memory_limit or max_execution_time
		 * raises an uncatchable fatal, not a Throwable. Arming the cooldown up front
		 * and clearing it on success means such a death still throttles the retries,
		 * instead of every subsequent page view starting the same doomed compile.
		 */
		set_transient( THE7_CSS_REGEN_BACKOFF_TRANSIENT, 1, the7_dynamic_css_regeneration_backoff() );

		$admin_dynamic_css = presscore_get_admin_dynamic_stylesheets_list();

		try {
			presscore_regenerate_dynamic_css( array_merge( $dynamic_stylesheets, $admin_dynamic_css ) );

			/*
			 * Publish the result while the lock is still held.
			 *
			 * Clearing the triggers after the release would leave a window in
			 * which a waiting process claims the lock and still reads work to do,
			 * which is exactly what the re-check above exists to prevent.
			 *
			 * The cached copies are dropped first. update_option() compares the
			 * new value against the cache and writes nothing when they match, so
			 * a stale cache - the reason the triggers were read past it - would
			 * leave the rows set and make the next request repeat this work.
			 */
			the7_forget_cached_dynamic_css_triggers();
			delete_transient( THE7_CSS_REGEN_BACKOFF_TRANSIENT );
			presscore_set_force_regenerate_css( false );
			if ( $hash_changed ) {
				update_option( 'the7_last_dynamic_stylesheets_hash', $dynamic_stylesheets_hash );
			}
		} catch ( Throwable $e ) {
			/*
			 * Keep the force flag set so the next request retries.
			 *
			 * Clearing it here - as this function used to - meant a single failed
			 * compile left the site with a bumped version, partially written files
			 * and nothing to trigger a repair.
			 */
			error_log( 'The7: dynamic css regeneration failed. ' . $e->getMessage() );

			return;
		} finally {
			the7_release_dynamic_css_lock();
		}

		do_action( 'the7_maybe_regenerate_dynamic_css_done' );
	}

endif;

/**
 * Option holding the dynamic css regeneration lock.
 */
const THE7_CSS_REGEN_LOCK_OPTION = 'the7_css_regen_lock';

/**
 * Transient holding the cooldown between dynamic css regeneration attempts.
 */
const THE7_CSS_REGEN_BACKOFF_TRANSIENT = 'the7_css_regen_backoff';

/**
 * Cooldown between dynamic css regeneration attempts, in seconds.
 *
 * @since 15.0.2
 *
 * @return int
 */
function the7_dynamic_css_regeneration_backoff() {
	return (int) apply_filters( 'the7_dynamic_css_regeneration_backoff', 5 * MINUTE_IN_SECONDS );
}

/**
 * Age at which a dynamic css regeneration lock is considered abandoned, in seconds.
 *
 * @since 15.0.2
 *
 * @return int
 */
function the7_dynamic_css_lock_timeout() {
	return (int) apply_filters( 'the7_dynamic_css_lock_timeout', 2 * MINUTE_IN_SECONDS );
}

/**
 * Try to become the single process regenerating dynamic css.
 *
 * Uses INSERT IGNORE so the claim is atomic even without an object cache - the
 * same approach core uses in WP_Upgrader::create_lock(). A lock left behind by a
 * process that died before releasing it is stolen once it goes stale.
 *
 * @since 15.0.2
 *
 * @return bool True if the lock was claimed, false if another process holds it.
 */
function the7_claim_dynamic_css_lock() {
	if ( the7_insert_dynamic_css_lock_row() ) {
		return true;
	}

	if ( the7_read_dynamic_css_lock() > ( time() - the7_dynamic_css_lock_timeout() ) ) {
		return false;
	}

	// The holder died without releasing. Clear the stale lock and try once more.
	the7_release_dynamic_css_lock();

	return the7_insert_dynamic_css_lock_row();
}

/**
 * Read the timestamp of the currently held lock.
 *
 * Reads the row directly rather than through get_option(). A lock is written by
 * a raw insert in another process, so the local options cache may still hold a
 * "notoptions" entry from an earlier release; trusting it would report a live
 * lock as absent, and the caller would steal a lock that is still in use.
 *
 * @since 15.0.2
 *
 * @global wpdb $wpdb
 *
 * @return int Unix timestamp, or 0 if no lock is held.
 */
function the7_read_dynamic_css_lock() {
	global $wpdb;

	// phpcs:ignore WordPress.DB.DirectDatabaseQuery -- deliberately bypasses the options cache, see above.
	return (int) $wpdb->get_var(
		$wpdb->prepare( "SELECT option_value FROM `$wpdb->options` WHERE option_name = %s LIMIT 1", THE7_CSS_REGEN_LOCK_OPTION )
	);
}

/**
 * Read what makes a regeneration necessary, straight from the database.
 *
 * Both options are autoloaded, so with a persistent object cache they reach this
 * request inside the alloptions blob, read once and kept for the whole request.
 * A caller that holds the lock has to know what another process wrote a moment
 * ago, so it reads the rows instead of the cache - the same reason
 * the7_read_dynamic_css_lock() does.
 *
 * @since 15.0.2
 *
 * @global wpdb $wpdb
 *
 * @return array {
 *     @type bool         $force Whether a regeneration is forced.
 *     @type string|false $hash  Hash of the stylesheets list the current css was
 *                              built from, or false if none was ever recorded.
 * }
 */
function the7_read_dynamic_css_triggers() {
	global $wpdb;

	// phpcs:ignore WordPress.DB.DirectDatabaseQuery -- deliberately bypasses the options cache, see above.
	$rows = $wpdb->get_results(
		$wpdb->prepare(
			"SELECT option_name, option_value FROM `$wpdb->options` WHERE option_name IN ( %s, %s )",
			'the7_force_regen_css',
			'the7_last_dynamic_stylesheets_hash'
		),
		OBJECT_K
	);

	return array(
		'force' => isset( $rows['the7_force_regen_css'] ) && (bool) maybe_unserialize( $rows['the7_force_regen_css']->option_value ),
		'hash'  => isset( $rows['the7_last_dynamic_stylesheets_hash'] ) ? maybe_unserialize( $rows['the7_last_dynamic_stylesheets_hash']->option_value ) : false,
	);
}

/**
 * Drop the cached copies of the regeneration triggers.
 *
 * update_option() decides whether to write by comparing against get_option(),
 * so a cached value that no longer matches the row makes the write a silent
 * no-op. Forgetting the cache first means the comparison is made against what
 * is actually stored.
 *
 * @since 15.0.2
 */
function the7_forget_cached_dynamic_css_triggers() {
	wp_cache_delete( 'alloptions', 'options' );
	wp_cache_delete( 'the7_force_regen_css', 'options' );
	wp_cache_delete( 'the7_last_dynamic_stylesheets_hash', 'options' );
}

/**
 * Insert the lock row, ignoring the insert if another process got there first.
 *
 * @since 15.0.2
 *
 * @global wpdb $wpdb
 *
 * @return bool True if this process inserted the row.
 */
function the7_insert_dynamic_css_lock_row() {
	global $wpdb;

	$now = time();

	// phpcs:ignore WordPress.DB.DirectDatabaseQuery -- add_option() reads then upserts, which is not race free.
	$inserted = $wpdb->query(
		$wpdb->prepare(
			"INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no')",
			THE7_CSS_REGEN_LOCK_OPTION,
			$now
		)
	);

	if ( ! $inserted ) {
		return false;
	}

	// The raw insert bypasses the options cache; sync it so reads see the lock.
	wp_cache_delete( 'notoptions', 'options' );
	wp_cache_set( THE7_CSS_REGEN_LOCK_OPTION, (string) $now, 'options' );

	return true;
}

/**
 * Release the dynamic css regeneration lock.
 *
 * @since 15.0.2
 */
function the7_release_dynamic_css_lock() {
	delete_option( THE7_CSS_REGEN_LOCK_OPTION );
}

if ( ! function_exists( 'presscore_compile_loader_css' ) ) :

	/**
	 * Compile inline loader css from .less files.
	 *
	 * Compiled css will be cached in db. Lunches after theme options save.
	 *
	 * @since  3.3.2
	 * @return string
	 */
	function presscore_compile_loader_css() {
		include_once PRESSCORE_DIR . '/less-vars.php';

		try {
			$less_vars = presscore_compile_less_vars();
			$lessc     = new The7_Less_Compiler( $less_vars );
			$css       = $lessc->compile_file( The7_Dynamic_Stylesheet::get_theme_css_dir() . '/beautiful-loading.less' );
		} catch ( Exception $e ) {
			return '';
		}

		return $css;
	}

endif;

if ( ! function_exists( 'presscore_cache_loader_inline_css' ) ) :

	/**
	 * Store beautiful loader css.
	 *
	 * @since 3.3.2
	 *
	 * @param  string $css CSS code.
	 *
	 * @return string
	 */
	function presscore_cache_loader_inline_css( $css ) {
		update_option( 'the7_beautiful_loader_inline_css', $css );

		return $css;
	}

endif;

if ( ! function_exists( 'presscore_get_loader_inline_css' ) ) :

	/**
	 * This function returns compiled loader css.
	 *
	 * First of all function attempts to read css from cache, if false then regenerate it manually.
	 *
	 * @since 3.3.2
	 *
	 * @return string
	 */
	function presscore_get_loader_inline_css() {
		$css = apply_filters( 'presscore_pre_get_loader_inline_css', '' );
		if ( $css ) {
			return $css;
		}

		$css = get_option( 'the7_beautiful_loader_inline_css' );

		return apply_filters( 'presscore_get_loader_inline_css', $css );
	}

endif;

if ( ! function_exists( 'presscore_force_regenerate_css' ) ) :

	/**
	 * Get regenerate css from less flag.
	 *
	 * @return boolean
	 */
	function presscore_force_regenerate_css() {
		return get_option( 'the7_force_regen_css' );
	}

endif;

if ( ! function_exists( 'presscore_set_force_regenerate_css' ) ) :

	/**
	 * Set force regenerate css from less flag.
	 *
	 * @param  boolean $force Force regenerate dunamic css.
	 *
	 * @return boolean
	 */
	function presscore_set_force_regenerate_css( $force = false ) {
		return update_option( 'the7_force_regen_css', $force );
	}

endif;

if ( ! function_exists( 'presscore_refresh_dynamic_css' ) ) :

	/**
	 * Setup theme to regen dynamic stylesheets on next page load.
	 *
	 * @since 3.7.0
	 */
	function presscore_refresh_dynamic_css() {
		presscore_set_force_regenerate_css( true );
		presscore_cache_loader_inline_css( '' );
	}

endif;
