HEX
Server: nginx
System: Linux pool195-106-36.bur.atomicsites.net 6.12.57+deb12-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.57-1~bpo12+1 (2025-11-17) x86_64
User: (0)
PHP: 8.3.32
Disabled: pcntl_fork
Upload Files
File: //srv/htdocs/wp-content/plugins/host-webfonts-local/src/Admin/Settings.php
<?php
/* * * * * * * * * * * * * * * * * * * * *
*
*  ██████╗ ███╗   ███╗ ██████╗ ███████╗
* ██╔═══██╗████╗ ████║██╔════╝ ██╔════╝
* ██║   ██║██╔████╔██║██║  ███╗█████╗
* ██║   ██║██║╚██╔╝██║██║   ██║██╔══╝
* ╚██████╔╝██║ ╚═╝ ██║╚██████╔╝██║
*  ╚═════╝ ╚═╝     ╚═╝ ╚═════╝ ╚═╝
*
* @package  : OMGF
* @author   : Daan van den Bergh
* @copyright: © 2025 Daan van den Bergh
* @url      : https://daan.dev
* * * * * * * * * * * * * * * * * * * */

namespace OMGF\Admin;

use OMGF\Admin;

/**
 * @codeCoverageIgnore
 */
class Settings extends Admin {
	const OMGF_ADMIN_PAGE = 'optimize-webfonts';

	/**
	 * Transients
	 */
	const OMGF_AVAILABLE_USED_SUBSETS       = 'omgf_available_used_subsets';

	const OMGF_NEWS_REEL                    = 'omgf_news_reel';

	const OMGF_OPTIMIZE_HAS_RUN             = 'omgf_optimize_has_run';

	const OMGF_CACHE_IS_STALE               = 'omgf_cache_is_stale';

	const OMGF_CURRENT_DB_VERSION           = 'omgf_current_db_version';

	const OMGF_CACHE_TIMESTAMP              = 'omgf_cache_timestamp';

	const OMGF_FOUND_IFRAMES                = 'omgf_found_iframes';

	const OMGF_GOOGLE_FONTS_CHECKER_RESULTS = 'omgf_google_fonts_checker_results';

	const OMGF_HIDDEN_NOTICES               = 'omgf_hidden_notices';

	/**
	 * Settings Fields
	 */
	const OMGF_SETTINGS_FIELD_OPTIMIZE = 'omgf-optimize-settings';

	const OMGF_SETTINGS_FIELD_ADVANCED = 'omgf-advanced-settings';

	const OMGF_SETTINGS_FIELD_HELP     = 'omgf-help';

	/**
	 * Option values for (multi)selects.
	 */
	const OMGF_FONT_DISPLAY_OPTIONS         = [
		'swap'     => 'Swap',
		'auto'     => 'Auto',
		'block'    => 'Block',
		'fallback' => 'Fallback',
		'optional' => 'Optional',
	];

	const OMGF_SUBSETS                      = [
		'arabic'              => 'Arabic',
		'bengali'             => 'Bengali',
		'chinese-hongkong'    => 'Chinese (Hong Kong)',
		'chinese-simplified'  => 'Chinese (Simplified)',
		'chinese-traditional' => 'Chinese (Traditional)',
		'cyrillic'            => 'Cyrillic',
		'cyrillic-ext'        => 'Cyrillic Extended',
		'devanagari'          => 'Devanagari',
		'greek'               => 'Greek',
		'greek-ext'           => 'Greek Extended',
		'gujarati'            => 'Gujarati',
		'gurmukhi'            => 'Gurmukhi',
		'hebrew'              => 'Hebrew',
		'japanese'            => 'Japanese',
		'kannada'             => 'Kannada',
		'khmer'               => 'Khmer',
		'korean'              => 'Korean',
		'latin'               => 'Latin',
		'latin-ext'           => 'Latin Extended',
		'malayalam'           => 'Malayalam',
		'math'                => 'Math',
		'myanmar'             => 'Myanmar',
		'oriya'               => 'Oriya',
		'sinhala'             => 'Sinhala',
		'symbols'             => 'Symbols',
		'tamil'               => 'Tamil',
		'telugu'              => 'Telugu',
		'thai'                => 'Thai',
		'tibetan'             => 'Tibetan',
		'vietnamese'          => 'Vietnamese',
	];

	const OMGF_FALLBACK_FONT_STACKS_OPTIONS = [
		'arial'              => 'Arial',
		'baskerville'        => 'Baskerville',
		'bodoni-mt'          => 'Bodoni MT',
		'calibri'            => 'Calibri',
		'calisto-mt'         => 'Calisto MT',
		'cambria'            => 'Cambria',
		'candara'            => 'Candara',
		'century-gothic'     => 'Century Gothic',
		'consolas'           => 'Consolas',
		'copperplate-gothic' => 'Copperplate Gothic',
		'courier-new'        => 'Courier New',
		'dejavu-sans'        => 'Dejavu Sans',
		'didot'              => 'Didot',
		'franklin-gothic'    => 'Franklin Gothic',
		'garamond'           => 'Garamond',
		'georgia'            => 'Georgia',
		'gill-sans'          => 'Gill Sans',
		'goudy-old-style'    => 'Goudy Old Style',
		'helvetica'          => 'Helvetica',
		'impact'             => 'Impact',
		'lucida-bright'      => 'Lucida Bright',
		'lucida-sans'        => 'Lucida Sans',
		'ms-sans-serif'      => 'Microsoft Sans Serif',
		'optima'             => 'Optima',
		'palatino'           => 'Palatino',
		'perpetua'           => 'Perpetua',
		'rockwell'           => 'Rockwell',
		'segoe-ui'           => 'Segoe UI',
		'tahoma'             => 'Tahoma',
		'trebuchet-ms'       => 'Trebuchet MS',
		'verdana'            => 'Verdana',
	];

	/**
	 * Optimize Fonts
	 */

	const OMGF_OPTIMIZE_SETTING_DISPLAY_OPTION     = 'display_option';

	const OMGF_OPTIMIZE_SETTING_TEST_MODE          = 'test_mode';

	const OMGF_OPTIMIZE_SETTING_UNLOAD_STYLESHEETS = 'unload_stylesheets';

	const OMGF_OPTIMIZE_SETTING_CACHE_KEYS         = 'cache_keys';

	/**
	 * Optimize Fonts (Hidden Settings)
	 */
	const OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS          = 'omgf_optimized_fonts';

	const OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS_FRONTEND = 'omgf_optimized_fonts_frontend';

	const OMGF_OPTIMIZE_SETTING_PRELOAD_FONTS            = 'omgf_preload_fonts';

	const OMGF_OPTIMIZE_SETTING_UNLOAD_FONTS             = 'omgf_unload_fonts';

	/**
	 * Advanced Settings
	 */
	const OMGF_ADV_SETTING_LEGACY_MODE            = 'legacy';

	const OMGF_ADV_SETTING_COMPATIBILITY          = 'compatibility';

	const OMGF_ADV_SETTING_AUTO_SUBSETS           = 'auto_subsets';

	const OMGF_ADV_SETTING_SUBSETS                = 'subsets';

	const OMGF_ADV_SETTING_DISABLE_ADMIN_BAR_MENU = 'disable_quick_access';

	const OMGF_ADV_SETTING_DEBUG_MODE             = 'debug';

	const OMGF_ADV_SETTING_UNINSTALL              = 'uninstall';

	/**
	 * Miscellaneous
	 */
	const OMGF_OPTIONS_GENERAL_PAGE_OPTIMIZE_WEBFONTS = 'options-general.php?page=optimize-webfonts';

	const OMGF_PLUGINS_INSTALL_CHANGELOG_SECTION      = 'plugin-install.php?tab=plugin-information&plugin=host-webfonts-local&TB_iframe=true&width=772&height=1015&section=changelog';

	const DAAN_WORDPRESS_OMGF_PRO                     = 'https://daan.dev/wordpress/omgf-pro/';

	const DAAN_DOCS_OMGF_PRO_KNOWN_ISSUES             = 'https://daan.dev/docs/omgf-pro/known-issues/';

	/** @var string $active_tab */
	private $active_tab;

	/** @var string $page */
	private $page;

	/** @var string|null */
	private $submit_button_text = null;

	/**
	 * OMGF_Admin_Settings constructor.
	 */
	public function __construct() {
		parent::__construct();

		$this->active_tab = $_GET[ 'tab' ] ?? self::OMGF_SETTINGS_FIELD_OPTIMIZE;
		$this->page       = $_GET[ 'page' ] ?? '';

		add_action( 'admin_menu', [ $this, 'create_menu' ] );
		add_filter( 'plugin_action_links_' . plugin_basename( OMGF_PLUGIN_FILE ), [ $this, 'create_settings_link' ] );

		if ( $this->page !== self::OMGF_ADMIN_PAGE ) {
			return;
		}

		if ( $this->active_tab === self::OMGF_SETTINGS_FIELD_OPTIMIZE ) {
			$this->submit_button_text = __( 'Save & Optimize', 'host-webfonts-local' );
		}

		// Footer Text
		add_filter( 'admin_footer_text', [ $this, 'footer_text_left' ], 99 );
		add_filter( 'update_footer', [ $this, 'footer_text_right' ], 11 );

		// Tabs
		add_action( 'omgf_settings_tab', [ $this, 'optimize_fonts_tab' ], 0 );
		add_action( 'omgf_settings_tab', [ $this, 'advanced_settings_tab' ], 2 );
		// The Manage License tab is inserted at position 3.
		add_action( 'omgf_settings_tab', [ $this, 'help_tab' ], 4 );

		// Content
		add_action( 'omgf_settings_content', [ $this, 'optimize_fonts_content' ], 0 );
		add_action( 'omgf_settings_content', [ $this, 'advanced_settings_content' ], 2 );
		add_action( 'omgf_settings_content', [ $this, 'help_content' ], 3 );
	}

	/**
	 * Creates the menu item.
	 */
	public function create_menu() {
		$title = apply_filters( 'omgf_settings_page_title', 'OMGF' );
		add_options_page(
			$title,
			$title,
			'manage_options',
			self::OMGF_ADMIN_PAGE,
			[ $this, 'create_settings_page' ]
		);

		add_action( 'admin_init', [ $this, 'register_settings' ] );
	}

	/**
	 * Display the settings page.
	 */
	public function create_settings_page() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( __( "You're not cool enough to access this page.", 'host-webfonts-local' ) );
		}
		?>
		<div class="wrap omgf">
			<h1>
				<?php echo apply_filters( 'omgf_settings_page_title', __( 'OMGF | Optimize My Google Fonts', 'host-webfonts-local' ) ); ?>
			</h1>
			<div class="settings-column">
				<h2 class="omgf-nav nav-tab-wrapper">
					<?php do_action( 'omgf_settings_tab' ); ?>
				</h2>
				<?php do_action( 'omgf_settings_content' ); ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Register all settings.
	 *
	 * @throws ReflectionException
	 */
	public function register_settings() {
		if ( $this->active_tab !== self::OMGF_SETTINGS_FIELD_OPTIMIZE && $this->active_tab !== self::OMGF_SETTINGS_FIELD_ADVANCED && $this->active_tab !== self::OMGF_SETTINGS_FIELD_HELP ) {
			$this->active_tab = apply_filters( 'omgf_admin_settings_active_tab', self::OMGF_SETTINGS_FIELD_OPTIMIZE );
		}

		foreach ( $this->get_settings() as $constant => $value ) {
			register_setting(
				$this->active_tab,
				$value
			);
		}
	}

	/**
	 * Get all settings using the constants in this class.
	 *
	 * @return array
	 * @throws ReflectionException
	 */
	public function get_settings() {
		$reflection = new \ReflectionClass( $this );
		$constants  = apply_filters( 'omgf_settings_constants', $reflection->getConstants() );

		switch ( $this->active_tab ) {
			case ( self::OMGF_SETTINGS_FIELD_ADVANCED ):
				$needle = 'OMGF_ADV_SETTING_';
				break;
			case ( self::OMGF_SETTINGS_FIELD_HELP ):
				$needle = 'OMGF_HELP_SETTING_';
				break;
			default:
				$needle = apply_filters( 'omgf_settings_needle', 'OMGF_OPTIMIZE_SETTING_' );
		}

		$settings = array_filter(
			$constants,
			function ( $key ) use ( $needle ) {
				return str_contains( $key, $needle );
			},
			ARRAY_FILTER_USE_KEY
		);

		foreach ( $settings as &$setting ) {
			$setting = apply_filters(
				'omgf_settings_option_name',
				"omgf_settings[$setting]",
				$setting,
				$settings,
				$needle
			);
		}

		return $settings;
	}

	/**
	 * Add Local Fonts tab to Settings Screen.
	 *
	 * @return void
	 */
	public function optimize_fonts_tab() {
		$this->generate_tab(
			self::OMGF_SETTINGS_FIELD_OPTIMIZE,
			'dashicons-performance',
			__( 'Local Fonts', 'host-webfonts-local' )
		);
	}

	/**
	 * @param      $id
	 * @param null $icon
	 * @param null $label
	 */
	private function generate_tab( $id, $icon = null, $label = null ) {
		?>
		<a class="nav-tab dashicons-before <?php echo $icon; ?> <?php echo $this->active_tab == $id ? 'nav-tab-active' : ''; ?>"
		   href="<?php echo $this->generate_tab_link( $id ); ?>">
			<?php echo $label; ?>
		</a>
		<?php
	}

	/**
	 * @param $tab
	 *
	 * @return string
	 */
	private function generate_tab_link( $tab ) {
		return admin_url( self::OMGF_OPTIONS_GENERAL_PAGE_OPTIMIZE_WEBFONTS . "&tab=$tab" );
	}

	/**
	 * Add Advanced Settings Tab to Settings Screen.
	 */
	public function advanced_settings_tab() {
		$this->generate_tab(
			self::OMGF_SETTINGS_FIELD_ADVANCED,
			'dashicons-admin-settings',
			__( 'Advanced', 'host-webfonts-local' )
		);
	}

	/**
	 * Add Help Tab to Settings Screen.
	 *
	 * @return void
	 */
	public function help_tab() {
		$this->generate_tab(
			self::OMGF_SETTINGS_FIELD_HELP,
			'dashicons-editor-help',
			__( 'Help', 'host-webfonts-local' )
		);
	}

	/**
	 *
	 */
	public function optimize_fonts_content() {
		$this->do_settings_content( self::OMGF_SETTINGS_FIELD_OPTIMIZE );
	}

	/**
	 * @param $field
	 */
	private function do_settings_content( $field ) {
		if ( $this->active_tab !== $field ) {
			return;
		}
		?>
		<form id="<?php echo esc_attr( $field ); ?>-form" name="omgf-settings-form" method="post"
			  action="<?php echo apply_filters(
				  'omgf_form_action',
				  admin_url( 'options.php?tab=' . $this->active_tab ),
				  $this->page,
				  $this->active_tab
			  ); ?>" autocomplete="off">
			<?php
			ob_start();
			settings_fields( $field );
			/**
			 * We use a custom update action, so we can group all settings in one DB row upon form submit.
			 *
			 * @see \OMGF\Helper update_options()
			 */
			$settings_fields = ob_get_clean();
			$settings_fields = str_replace( 'value="update"', 'value="omgf-update"', $settings_fields );
			echo $settings_fields;
			do_settings_sections( $field );

			do_action( 'omgf_before_settings_form_settings' );

			echo do_action( str_replace( '-', '_', $field ) . '_content', '' );

			do_action( 'omgf_after_settings_form_settings' );

			?>
			<?php if ( $this->active_tab !== self::OMGF_SETTINGS_FIELD_HELP ) : ?>
				<?php submit_button(
					$this->submit_button_text,
					'primary',
					'submit',
					false,
					empty( $this->get_settings() ) ? 'disabled' : null
				); ?>
			<?php endif; ?>
		</form>
		<?php
	}

	/**
	 * Render Advanced Settings content
	 */
	public function advanced_settings_content() {
		$this->do_settings_content( self::OMGF_SETTINGS_FIELD_ADVANCED );
	}

	/**
	 * Render Help content
	 *
	 * @return void
	 */
	public function help_content() {
		$this->do_settings_content( self::OMGF_SETTINGS_FIELD_HELP );
	}

	/**
	 * @param $links
	 *
	 * @return mixed
	 */
	public function create_settings_link( $links ) {
		$adminUrl     = admin_url() . self::OMGF_OPTIONS_GENERAL_PAGE_OPTIMIZE_WEBFONTS;
		$settingsLink = "<a href='$adminUrl'>" . __( 'Settings' ) . '</a>';
		array_push( $links, $settingsLink );

		return $links;
	}

	/**
	 * Changes footer text.
	 *
	 * @return string
	 */
	public function footer_text_left() {
		$text = sprintf(
			__( 'Coded with %s in The Netherlands @ <strong>Daan.dev</strong>.', 'host-webfonts-local' ),
			'❤️'
		);

		return '<span id="footer-thankyou">' . $text . '</span>';
	}

	/**
	 * All logic to generate the news reel in the bottom right of the footer on all of OMGF's settings pages.
	 * Includes multiple checks to make sure the reel is only shown if a recent post is available.
	 *
	 * @param mixed $text
	 *
	 * @return mixed
	 */
	public function footer_text_right( $text ) {
		if ( ! extension_loaded( 'simplexml' ) ) {
			return $text;
		}

		/**
		 * If a WordPress update is available, show the original text.
		 */
		if ( str_contains( $text, 'Get Version' ) ) {
			return $text;
		}

		// Prevents bashing the API.
		$xml = get_transient( self::OMGF_NEWS_REEL );

		if ( ! $xml ) {
			$response = wp_remote_get( 'https://daan.dev/blog/tag/omgf/feed' );

			if ( ! is_wp_error( $response ) ) {
				$xml = wp_remote_retrieve_body( $response );

				// Refresh the feed once a day to prevent bashing of the API.
				set_transient( self::OMGF_NEWS_REEL, $xml, DAY_IN_SECONDS );
			}
		}

		if ( ! $xml ) {
			return $text;
		}

		/**
		 * Make sure the XML is properly encoded.
		 */
		libxml_use_internal_errors( true );
		$xml = html_entity_decode( $xml );
		$xml = simplexml_load_string( $xml );

		if ( ! $xml ) {
			return $text;
		}

		$items = $xml->channel->item ?? [];

		if ( empty( $items ) ) {
			return $text;
		}

		$text = sprintf(
				__(
					'Recently tagged <a target="_blank" href="%s"><strong>#OMGF</strong></a> on my blog:',
					'host-webfonts-local'
				),
				'https://daan.dev/blog/tag/omgf'
			) . ' ';
		$text .= '<span id="omgf-ticker-wrap">';
		$i    = 0;

		foreach ( $items as $item ) {
			$hide = $i > 0 ? 'style="display: none;"' : '';
			$text .= "<span class='ticker-item' $hide>" . sprintf( '<a target="_blank" href="%s"><em>%s</em></a>', esc_url( $item->link ), esc_html( $item->title ) ) . '</span>';
			++ $i;
		}

		$text .= '</span>';

		return $text;
	}
}