File "class-slim.php"

Full Path: /home/theinspectionboy/public_html/suffolk/includes/class-slim.php
File size: 50.28 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * Class and methods to eliminate unused JS/CSS.
 *
 * @link https://ewww.io/swis/
 * @package SWIS_Performance
 */

namespace SWIS;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Enables plugin to Lazy Load images.
 */
final class Slim extends Base {

	/**
	 * The list of JS/CSS assets and associated information.
	 *
	 * @var array
	 */
	private $assets = array();

	/**
	 * The type of the current page.
	 *
	 * @var array
	 */
	private $content_type = '';

	/**
	 * A list of registered content types.
	 *
	 * @var array
	 */
	private $content_types = array();

	/**
	 * The URL path to the home page.
	 *
	 * @var string
	 */
	private $home_path = '';

	/**
	 * Store asset dependencies.
	 *
	 * @var array
	 */
	private $deps = array();

	/**
	 * A list of user-defined exclusions, populated by validate_user_exclusions().
	 *
	 * @access protected
	 * @var array $user_exclusions
	 */
	public $user_exclusions = array();

	/**
	 * CSS/JS that should not ever be excluded.
	 *
	 * @var array
	 */
	private $whitelist = array( 'admin-bar', 'dashicons', 'swis-performance-slim' );

	/**
	 * Register actions and filters for JS/CSS Slim.
	 */
	function __construct() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		parent::__construct();
		if ( ! is_admin() ) {
			$permissions = apply_filters( 'swis_performance_admin_permissions', 'manage_options' );
			add_action( 'admin_bar_init', array( $this, 'admin_bar_init' ) );
			if ( current_user_can( $permissions ) && ( ! defined( 'SWIS_SLIM_DISABLE_FRONTEND_MENU' ) || ! SWIS_SLIM_DISABLE_FRONTEND_MENU ) ) {
				add_action( 'wp_head', array( $this, 'dash_css' ) );
				add_action( 'wp_head', array( $this, 'find_assets' ), 9999 );
				add_action( 'wp_enqueue_scripts', array( $this, 'frontend_script' ) );
				add_action( 'wp_footer', array( $this, 'find_assets' ), 9999 );
				add_action( 'wp_footer', array( $this, 'dash_script' ), 9999 );
				add_action( 'wp_footer', array( $this, 'display_assets' ), 10000 );
			}
			if ( $this->get_option( 'slim_js_css' ) || $this->get_option( 'optimize_fonts_list' ) ) {
				add_action( 'template_redirect', array( $this, 'get_content_type' ) );
				add_action( 'template_redirect', array( $this, 'maybe_remove_emoji' ), 11 );
				add_filter( 'script_loader_src', array( $this, 'disable_assets' ), 10, 2 );
				add_filter( 'style_loader_src', array( $this, 'disable_assets' ), 10, 2 );
				$this->validate_user_exclusions();
			}
		}
		add_action( 'wp_ajax_swis_slim_rule_edit', array( $this, 'edit_rule' ) );
	}

	/**
	 * Checks if admin bar is visible, then adds an action to add our menu item.
	 */
	function admin_bar_init() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		if (
			! current_user_can( apply_filters( 'swis_admin_permissions', 'edit_others_posts' ) ) ||
			! is_admin_bar_showing() ||
			! $this->is_frontend()
		) {
			return;
		}
		add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_menu_item' ), 100 );
	}

	/**
	 * Adds a resize detection button to the wp admin bar.
	 *
	 * @param object $wp_admin_bar The WP Admin Bar object, passed by reference.
	 */
	function add_admin_bar_menu_item( $wp_admin_bar ) {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		$wp_admin_bar->add_menu(
			array(
				'id'     => 'swis',
				'parent' => null,
				'title'  => '<span id="swis-slim-show-top"><span class="ab-icon"></span><span class="ab-label">' . __( 'SWIS', 'swis-performance' ) . '</span></span>',
			)
		);
		if ( defined( 'SWIS_SLIM_DISABLE_FRONTEND_MENU' ) && SWIS_SLIM_DISABLE_FRONTEND_MENU ) {
			return;
		}
		$wp_admin_bar->add_menu(
			array(
				'id'     => 'swis-slim',
				'parent' => 'swis',
				'title'  => '<span id="swis-slim-show"><span class="ab-item">' . __( 'Manage JS/CSS', 'swis-performance' ) . '</span></span>',
			)
		);
	}

	/**
	 * Enqueue JS needed for the front-end assets pane.
	 */
	function frontend_script() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		wp_enqueue_script( 'swis-performance-slim', plugins_url( '/assets/slim.js', SWIS_PLUGIN_FILE ), array( 'jquery-core' ), SWIS_PLUGIN_VERSION, true );
		wp_localize_script(
			'swis-performance-slim',
			'swisperformance_vars',
			array(
				'ajaxurl'          => admin_url( 'admin-ajax.php' ),
				'_wpnonce'         => wp_create_nonce( 'swis-performance-settings' ),
				'invalid_response' => esc_html__( 'Received an invalid response from your website, please check for errors in the Developer Tools console of your browser.', 'swis-performance' ),
				'remove_rule'      => esc_html__( 'Are you sure you want to remove this rule?', 'swis-performance' ),
				'removing_message' => esc_html__( 'Deleting...', 'swis-performance' ),
				'saving_message'   => esc_html__( 'Saving...', 'swis-performance' ),
			)
		);
	}

	/**
	 * Adds some dashicon CSS for our admin bar item.
	 */
	function dash_css() {
		if ( ! $this->is_frontend() ) {
			return;
		}
		$slim_css = file_get_contents( SWIS_PLUGIN_PATH . 'assets/swis.css' );
		?>
		<style>
		<?php echo $slim_css; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
		#wpadminbar #swis-slim-show-top, #wpadminbar #swis-slim-show {
			cursor: pointer;
		}
		#wpadminbar #wp-admin-bar-swis .ab-icon:before {
			content: '\f198';
			top: 2px;
		}
		#swis-slim-close-pane {
			/*border: 1px solid #aaa;
			color: #6d6d6d;
			cursor: pointer;*/
			float: right;
			font-size: 16px;
			/*padding: 5px;*/
		}
		#swis-slim-close-pane:hover {
			/*border: 1px solid #000;
			color: #000;*/
		}
		#swis-slim-assets-pane {
			background-color: #fff;
			color: #000;
			font-family: sans-serif;
			padding: 15px;
		}
		#swis-slim-assets-pane h1 {
			font-family: sans-serif;
			font-size: 36px;
		}
		#swis-slim-assets-pane h2 {
			font-family: sans-serif;
			font-size: 30px;
		}
		.swis-slim-unscroll {
			overflow: hidden;
		}
		.swis-slim-visible {
			display: block;
			position: fixed;
			top: 32px;
			left: 0;
			bottom: 0;
			overflow: scroll;
			width: 100%;
			height: calc(100% - 32px);
			z-index: 99999;
		}
		.swis-slim-assets {
			border: 1px solid #ddd;
			border-collapse: collapse;
			font-family: sans-serif;
			width: 100%;
		}
		.swis-slim-assets th {
			font-weight: 700;
		}
		.swis-slim-assets th, .swis-slim-assets td {
			border: 1px solid #ddd;
			font-family: sans-serif;
			font-size: 16px;
			padding: 8px;
		}
		.swis-slim-asset-active {
			width: 75px;
		}
		.swis-slim-asset-size {
			width: 100px;
		}
		.swis-slim-active-yes {
			font-weight: bolder;
			color: green;
		}
		.swis-slim-active-no {
			font-weight: bolder;
			color: red;
		}
		@media screen and (max-width: 782px) {
			#wpadminbar li#wp-admin-bar-swis-slim{
				display: block!important;
			}
		}
		</style>
		<?php
	}

	/**
	 * Adds the script for our admin bar action.
	 */
	function dash_script() {
		if ( ! $this->is_frontend() ) {
			return;
		}
		?>
		<script>
		function toggleSWISPane() {
			var SWISPane = document.getElementById('swis-slim-assets-pane');
			SWISPane.classList.toggle('swis-slim-hidden');
			SWISPane.classList.toggle('swis-slim-visible');
			document.body.classList.toggle('swis-slim-unscroll');
		}
		function addSWISClickers() {
			document.getElementById('swis-slim-show-top').addEventListener('click', toggleSWISPane);
			document.getElementById('swis-slim-show').addEventListener('click', toggleSWISPane);
			document.getElementById('swis-slim-close-pane').addEventListener('click', toggleSWISPane);
		}
		if (document.readyState === 'loading') {
			document.addEventListener('DOMContentLoaded', addSWISClickers);
		} else {
			addSWISClickers();
		}
		</script>
		<?php
	}

	/**
	 * Handle a rule update via AJAX. Possible actions are "create", "update", and "delete".
	 *
	 * On success, returns the updated HTML for the rule to display, an error message otherwise.
	 */
	function edit_rule() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		if ( empty( $_REQUEST['swis_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['swis_wpnonce'] ), 'swis-performance-settings' ) ) {
			die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'swis-performance' ) ) ) );
		}
		if ( empty( $_POST['swis_slim_action'] ) ) {
			die( wp_json_encode( array( 'error' => esc_html__( 'Invalid operation requested.', 'swis-performance' ) ) ) );
		}
		if ( empty( $_POST['swis_slim_handle'] ) ) {
			die( wp_json_encode( array( 'error' => esc_html__( 'No handle provided.', 'swis-performance' ) ) ) );
		}
		$output = '';
		$status = '';
		$action = sanitize_text_field( wp_unslash( $_POST['swis_slim_action'] ) );
		$mode   = '';
		if ( ! empty( $_POST['swis_slim_exclusions'] ) && ! empty( $_POST['swis_slim_mode'] ) && 'all' === $_POST['swis_slim_mode'] && empty( $_POST['swis_slim_frontend'] ) ) {
			die( wp_json_encode( array( 'error' => esc_html__( 'Please select an option.', 'swis-performance' ) ) ) );
		}
		if ( ! empty( $_POST['swis_slim_exclusions'] ) && empty( $_POST['swis_slim_mode'] ) && ! empty( $_POST['swis_slim_frontend'] ) ) {
			die( wp_json_encode( array( 'error' => esc_html__( 'Please select an option.', 'swis-performance' ) ) ) );
		}
		if ( ! empty( $_POST['swis_slim_current_page'] ) ) {
			$this->current_page = trim( sanitize_text_field( wp_unslash( $_POST['swis_slim_current_page'] ) ) );
		}
		if ( ! empty( $_POST['swis_slim_exclusions'] ) && ! empty( $_POST['swis_slim_mode'] ) ) {
			if ( 'include' === $_POST['swis_slim_mode'] ) {
				$mode = '+';
			}
			if ( 'exclude' === $_POST['swis_slim_mode'] ) {
				$mode = '-';
			}
		}
		$this->validate_user_exclusions();
		$user_exclusions = $this->get_option( 'slim_js_css' );
		switch ( $action ) {
			case 'create':
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
				$exclusions = ! empty( $_POST['swis_slim_exclusions'] ) && $mode ? swis()->settings->sanitize_textarea_exclusions( wp_unslash( $_POST['swis_slim_exclusions'] ), false ) : false;
				$handle     = sanitize_text_field( wp_unslash( $_POST['swis_slim_handle'] ) );
				$new_rule   = ( $exclusions && ! empty( $exclusions[0] ) ? $mode . $exclusions[0] . ':' : '' ) . $handle;
				if ( $this->is_iterable( $this->user_exclusions ) && isset( $this->user_exclusions[ $handle ] ) ) {
					die( wp_json_encode( array( 'error' => esc_html__( 'A rule already exists for that handle, edit the existing rule or remove it before adding a new rule.', 'swis-performance' ) ) ) );
				}
				$this->debug_message( "adding $new_rule to:" );
				if ( $this->function_exists( 'print_r' ) ) {
					$this->debug_message( print_r( $user_exclusions, true ) );
				}
				if ( empty( $user_exclusions ) ) {
					$this->debug_message( 'adding as only rule' );
					$user_exclusions = array( $new_rule );
				} elseif ( is_array( $user_exclusions ) && 1 === count( $user_exclusions ) && empty( $user_exclusions[0] ) ) {
					$this->debug_message( 'adding as only rule (because the existing one is empty)' );
					$user_exclusions = array( $new_rule );
				} else {
					$this->debug_message( 'adding to existing rules' );
					$user_exclusions[] = $new_rule;
				}
				$this->debug_message( 'now slim exclusions are:' );
				if ( $this->function_exists( 'print_r' ) ) {
					$this->debug_message( print_r( $user_exclusions, true ) );
				}
				$result = $this->set_option( 'slim_js_css', $user_exclusions );
				if ( ! $result ) {
					die( wp_json_encode( array( 'error' => esc_html__( 'Unable to save rule.', 'swis-performance' ) ) ) );
				}
				$output = $this->get_rule_html( $handle, $this->parse_slim_rule( $new_rule ) );
				$status = $this->asset_disabled( '', $handle ) ? "<span class='swis-slim-active-no'>" . esc_html__( 'No', 'swis-performance' ) . '</span>' : "<span class='swis-slim-active-yes'>" . esc_html__( 'Yes', 'swis-performance' ) . '</span>';
				break;
			case 'update':
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
				$exclusions = ! empty( $_POST['swis_slim_exclusions'] ) ? swis()->settings->sanitize_textarea_exclusions( wp_unslash( $_POST['swis_slim_exclusions'] ), false ) : false;
				$handle     = sanitize_text_field( wp_unslash( $_POST['swis_slim_handle'] ) );
				$new_rule   = ( $exclusions && ! empty( $exclusions[0] ) ? $mode . $exclusions[0] . ':' : '' ) . $handle;
				if ( ! $this->is_iterable( $this->user_exclusions ) || ! isset( $this->user_exclusions[ $handle ] ) ) {
					die(
						wp_json_encode(
							array(
								'error' => sprintf(
									/* translators: %s: registered handle for a JS/CSS resource */
									esc_html__( 'Could not find a match for %s to update.', 'swis-performance' ),
									esc_html( $handle )
								),
							)
						)
					);
				}
				foreach ( $user_exclusions as $index => $user_exclusion ) {
					$parsed_rule = $this->parse_slim_rule( $user_exclusion );
					if ( ! empty( $parsed_rule['handle'] ) && $handle === $parsed_rule['handle'] ) {
						$user_exclusions[ $index ] = $new_rule;
					}
				}
				$this->debug_message( print_r( $user_exclusions, true ) );
				$this->set_option( 'slim_js_css', $user_exclusions );
				$output = $this->get_rule_html( $handle, $this->parse_slim_rule( $new_rule ) );
				$status = $this->asset_disabled( '', $handle ) ? "<span class='swis-slim-active-no'>" . esc_html__( 'No', 'swis-performance' ) . '</span>' : "<span class='swis-slim-active-yes'>" . esc_html__( 'Yes', 'swis-performance' ) . '</span>';
				break;
			case 'delete':
				$handle = sanitize_text_field( wp_unslash( $_POST['swis_slim_handle'] ) );
				if ( ! $this->is_iterable( $this->user_exclusions ) || ! isset( $this->user_exclusions[ $handle ] ) ) {
					die(
						wp_json_encode(
							array(
								'error' => sprintf(
									/* translators: %s: registered handle for a JS/CSS resource */
									esc_html__( 'Could not find a match for %s to remove.', 'swis-performance' ),
									esc_html( $handle )
								),
							)
						)
					);
				}
				foreach ( $user_exclusions as $index => $user_exclusion ) {
					$parsed_rule = $this->parse_slim_rule( $user_exclusion );
					if ( ! empty( $parsed_rule['handle'] ) && $handle === $parsed_rule['handle'] ) {
						unset( $user_exclusions[ $index ] );
					}
				}
				$this->set_option( 'slim_js_css', $user_exclusions );
				$output = $this->get_rule_html( $handle, array() );
				$status = "<span class='swis-slim-active-yes'>" . esc_html__( 'Yes', 'swis-performance' ) . '</span>';
				break;
			default:
				die( wp_json_encode( array( 'error' => esc_html__( 'Unknown operation requested.', 'swis-performance' ) ) ) );
		}
		die(
			wp_json_encode(
				array(
					'success' => 1,
					'message' => $output,
					'status'  => $status,
				)
			)
		);
	}

	/**
	 * Retrieve the HTML for a given rule.
	 *
	 * @param string $handle The CSS/JS handle.
	 * @param array  $rule Exclusions and inclusions for the given $handle.
	 * @return string The HTML produced for Slim rule.
	 */
	private function get_rule_html( $handle, $rule ) {
		ob_start();
		// Nonce verification has already happened before we get here.
		if ( empty( $_POST['swis_slim_frontend'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			if ( empty( $rule ) ) {
				return '';
			}
			$this->display_backend_rule( $handle, $rule );
		} else {
			$this->display_frontend_rule_form( $handle, $rule );
		}
		return trim( ob_get_clean() );
	}

	/**
	 * Display the HTML for a given rule on the settings.
	 *
	 * @param string $handle The CSS/JS handle.
	 * @param array  $rule Exclusions and inclusions for the given $handle.
	 */
	private function display_backend_rule( $handle, $rule ) {
		$rule_id = preg_replace( '/[\W_]/', '', uniqid( '', true ) );
		?>
		<div id="swis-slim-rule-<?php echo esc_attr( $rule_id ); ?>" class="swis-slim-rule" data-slim-handle="<?php echo esc_attr( $handle ); ?>" data-slim-rule-id="<?php echo esc_attr( $rule_id ); ?>">
		<?php if ( $rule['include'] ) : ?>
			<?php
			$includes = array();
			foreach ( $rule['include'] as $include ) {
				if ( 0 === strpos( $include, 'T>' ) ) {
					$includes[] = '<i>' . substr( $include, 2 ) . '</i> ' . esc_html__( 'content type', 'swis-performance' );
				} elseif ( '<home_page>' === $include ) {
					$includes[] = esc_html__( 'home page', 'swis-performance' );
				} else {
					$includes[] = $include;
				}
			}
			$raw_rule_parts = explode( ':', $rule['raw'] );
			$raw_rule_html  = ltrim( $raw_rule_parts[0], '+-' );
			?>
			<div class="swis-slim-rule-description">
				<?php /* translators: %s: registered handle for a JS/CSS resource */ ?>
				<?php printf( esc_html__( '%s disabled everywhere except:', 'swis-performance' ), '<strong>' . esc_html( $handle ) . '</strong>' ); ?>
				<input style="display:none;" type="radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="include" checked />
				<div class="swis-slim-pretty-rule">
					<?php echo wp_kses_post( implode( ', ', $includes ) ); ?>
				</div>
				<div class="swis-slim-error-message"></div>
				<div class="swis-slim-hidden">
					<div class="swis-slim-raw-rule">
						<input type="text" name="swis-slim-rule-exclusions-<?php echo esc_attr( $rule_id ); ?>" value="<?php echo esc_attr( $raw_rule_html ); ?>" />
						<button type="button" class="button-primary swis-slim-rule-save"><?php esc_html_e( 'Save', 'swis-performance' ); ?></button>
					</div>
					<p class="swis-slim-edit-rule-description description">
						<?php esc_html_e( 'Enter a comma-separated list of pages, URL patterns (use * as wildcard), or content types in the form T>post or T>page.', 'swis-performance' ); ?>
					</p>
				</div>
			</div>
			<div class="swis-slim-rule-actions">
				<button type="button" class="button-link button-link-edit"><?php esc_html_e( 'Edit', 'swis-performance' ); ?></button>
				|
				<button type="button" class="button-link button-link-delete"><?php esc_html_e( 'Delete', 'swis-performance' ); ?></button>
			</div>
		<?php elseif ( $rule['exclude'] ) : ?>
			<?php
			$excludes = array();
			foreach ( $rule['exclude'] as $exclude ) {
				if ( 0 === strpos( $exclude, 'T>' ) ) {
					$excludes[] = '<i>' . substr( $exclude, 2 ) . '</i> ' . esc_html__( 'content type', 'swis-performance' );
				} elseif ( '<home_page>' === $exclude ) {
					$excludes[] = esc_html__( 'home page', 'swis-performance' );
				} else {
					$excludes[] = $exclude;
				}
			}
			$raw_rule_parts = explode( ':', $rule['raw'] );
			$raw_rule_html  = ltrim( $raw_rule_parts[0], '+-' );
			?>
			<div class="swis-slim-rule-description">
				<?php /* translators: %s: A JS/CSS handle, like 'jquery-form' */ ?>
				<?php printf( esc_html__( '%s disabled on:', 'swis-performance' ), '<strong>' . esc_html( $handle ) . '</strong>' ); ?><br>
				<input style="display:none;" type="radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="exclude" checked />
				<div class="swis-slim-pretty-rule">
					<?php echo wp_kses_post( implode( ', ', $excludes ) ); ?>
				</div>
				<div class="swis-slim-error-message"></div>
				<div class="swis-slim-hidden">
					<div class="swis-slim-raw-rule">
						<input type="text" name="swis-slim-rule-exclusions-<?php echo esc_attr( $rule_id ); ?>" value="<?php echo esc_attr( $raw_rule_html ); ?>" />
						<button type="button" class="button-primary swis-slim-rule-save"><?php esc_html_e( 'Save', 'swis-performance' ); ?></button>
					</div>
					<p class="swis-slim-edit-rule-description description">
						<?php esc_html_e( 'Enter a comma-separated list of pages, URL patterns (use * as wildcard), or content types in the form T>post or T>page.', 'swis-performance' ); ?>
					</p>
				</div>
			</div>
			<div class="swis-slim-rule-actions">
				<button type="button" class="button-link button-link-edit"><?php esc_html_e( 'Edit', 'swis-performance' ); ?></button>
				|
				<button type="button" class="button-link button-link-delete"><?php esc_html_e( 'Delete', 'swis-performance' ); ?></button>
			</div>
		<?php else : ?>
			<div class="swis-slim-rule-description">
				<?php /* translators: %s: A JS/CSS handle, like 'jquery-form' */ ?>
				<?php printf( esc_html__( '%s disabled everywhere', 'swis-performance' ), '<strong>' . esc_html( $handle ) . '</strong>' ); ?>
				<input style="display:none;" type="radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="all" checked />
				<div class="swis-slim-error-message"></div>
				<div class="swis-slim-hidden">
					<div class="swis-slim-column">
						<div class="swis-slim-row">
							<input type="radio" id="swis_slim_mode_include_<?php echo esc_attr( $rule_id ); ?>" class="swis-slim-radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="include" />
							<strong><label for="swis_slim_mode_include_<?php echo esc_attr( $rule_id ); ?>"><?php esc_html_e( 'disable everywhere except:', 'swis-performance' ); ?></label></strong>
						</div>
						<div class="swis-slim-row">
							<input type="radio" id="swis_slim_mode_exclude_<?php echo esc_attr( $rule_id ); ?>" class="swis-slim-radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="exclude" />
							<strong><label for="swis_slim_mode_exclude_<?php echo esc_attr( $rule_id ); ?>"><?php esc_html_e( 'disable on:', 'swis-performance' ); ?></label></strong>
						</div>
						<div class="swis-slim-raw-rule">
							<input type="text" name="swis-slim-rule-exclusions-<?php echo esc_attr( $rule_id ); ?>" value="" />
							<button type="button" class="button-primary swis-slim-rule-save"><?php esc_html_e( 'Save', 'swis-performance' ); ?></button>
						</div>
						<p class="swis-slim-edit-rule-description description">
							<?php esc_html_e( 'Enter a comma-separated list of pages, URL patterns (use * as wildcard), or content types in the form T>post or T>page.', 'swis-performance' ); ?>
						</p>
					</div>
				</div>
			</div>
			<div class="swis-slim-rule-actions">
				<button type="button" class="button-link button-link-edit"><?php esc_html_e( 'Add Exclusion', 'swis-performance' ); ?></button>
				|
				<button type="button" class="button-link button-link-delete"><?php esc_html_e( 'Delete', 'swis-performance' ); ?></button>
			</div>
		<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Display existing rules on the settings.
	 */
	public function display_backend_rules() {
		$this->validate_user_exclusions();
		if ( empty( $this->user_exclusions ) ) {
			return;
		}
		foreach ( $this->user_exclusions as $handle => $rule ) {
			$this->display_backend_rule( $handle, $rule );
		}
	}

	/**
	 * Add more exclusions from third-party code.
	 *
	 * @param string $rule A handle or rule using our SLIM syntax.
	 */
	public function add_exclusion( $rule ) {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		if ( is_string( $rule ) ) {
			$this->parse_slim_rule( $rule );
		}
	}

	/**
	 * Validate the user-defined rules.
	 */
	function validate_user_exclusions() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		$user_exclusions = $this->get_option( 'slim_js_css' );
		if ( ! empty( $user_exclusions ) ) {
			if ( is_string( $user_exclusions ) ) {
				$user_exclusions = array( $user_exclusions );
			}
			if ( is_array( $user_exclusions ) ) {
				foreach ( $user_exclusions as $exclusion ) {
					if ( ! is_string( $exclusion ) ) {
						continue;
					}
					$this->parse_slim_rule( $exclusion );
				}
			}
		}
	}

	/**
	 * Parse a user-supplied slim rule into an array and append to $this->user_exclusions.
	 *
	 * @param string $rule The user-supplied rule.
	 * @return array The parsed array-style version of the rule.
	 */
	function parse_slim_rule( $rule ) {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		if ( ! $this->home_path ) {
			$this->home_path = $this->parse_url( trailingslashit( get_home_url() ), PHP_URL_PATH );
			$this->debug_message( 'the home path to match is ' . $this->home_path );
		}
		$rule = trim( str_replace( '\\', '/', $rule ) );
		$raw  = $rule;
		if ( 0 === strpos( $rule, '+' ) || 0 === strpos( $rule, '-' ) ) {
			$type = substr( $rule, 0, 1 );
			$rule = ltrim( $rule, '+' );
			$rule = ltrim( $rule, '-' );
			if ( strpos( $rule, ':' ) ) {
				$parts = explode( ':', $rule );
				if ( empty( $parts[0] ) || empty( $parts[1] ) ) {
					return;
				}
				$handle = $parts[1];
				$except = explode( ',', $parts[0] );
				if ( $this->is_iterable( $except ) ) {
					foreach ( $except as $key => $page ) {
						$this->debug_message( "comparing $page to home_path" );
						if ( $page === $this->home_path ) {
							$except[ $key ] = '<home_page>';
						}
					}
				}

				$this->user_exclusions[ $handle ] = array(
					'handle'  => $handle,
					'include' => '-' !== $type ? $except : array(),
					'exclude' => '-' === $type ? $except : array(),
					'raw'     => $raw,
				);
				return $this->user_exclusions[ $handle ];
			}
		} elseif ( false === strpos( $rule, ':' ) ) {
			// Found an "exclude everywhere" rule.
			$this->user_exclusions[ $rule ] = array(
				'handle'  => $rule,
				'include' => array(),
				'exclude' => array(),
				/* translators: %s: A JS/CSS handle, like 'jquery-form' */
				'raw'     => sprintf( __( '%s disabled everywhere', 'swis-performance' ), $rule ),
			);
			return $this->user_exclusions[ $rule ];
		}
	}

	/**
	 * Check if an asset is from an external site.
	 *
	 * @param string $url The asset URL.
	 * @return bool True for external asset, false for local asset.
	 */
	function is_external( $url ) {
		if ( 0 === strpos( $url, '/' ) && 0 !== strpos( $url, '//' ) ) {
			return false;
		}
		$asset_url_parts = $this->parse_url( $url );
		$local_url_parts = $this->parse_url( get_site_url() );
		if ( ! empty( $asset_url_parts['host'] ) && ! empty( $local_url_parts['host'] ) && 0 === strcasecmp( $asset_url_parts['host'], $local_url_parts['host'] ) ) {
			return false;
		}
		return true;
	}

	/**
	 * Check size of asset.
	 *
	 * @param string $url The asset URL.
	 * @return string A human-readable size.
	 */
	function get_asset_size( $url ) {
		$size     = '';
		$url_bits = explode( '?', $url );

		$asset_path = ABSPATH . str_replace( get_site_url(), '', $this->prepend_url_scheme( $url_bits[0] ) );

		if ( $url !== $asset_path && is_file( $asset_path ) ) {
			$size = size_format( filesize( $asset_path ), 1 );
		}
		return $size;
	}

	/**
	 * Check to see which JS/CSS files have been registered for the current page.
	 */
	function find_assets() {
		if ( ! $this->is_frontend() ) {
			return;
		}
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		$assets = array(
			'js'  => wp_scripts(),
			'css' => wp_styles(),
		);

		$core_url    = ! empty( $assets['js']->default_dirs[1] ) ? dirname( $assets['js']->default_dirs[1] ) : dirname( $assets['js']->default_dirs[0] );
		$plugins_url = plugins_url();
		$theme_url   = get_theme_root_uri();
		$this->debug_message( $core_url );
		$this->debug_message( $plugins_url );
		$this->debug_message( $theme_url );

		foreach ( $assets as $type => $data ) {
			foreach ( $data->done as $handle ) {
				if ( ! in_array( $handle, $this->whitelist, true ) && ! empty( $data->registered[ $handle ] ) ) {
					$url = $this->prepend_url_scheme( $data->registered[ $handle ]->src );
					if ( false !== strpos( $url, $plugins_url ) ) {
						$asset_source_type = 'plugins';

						// Get the plugin folder name.
						$plugin_path = ltrim( str_replace( $plugins_url, '', $url ), '/' );
						$plugin_path = explode( '/', $plugin_path );
						$plugin_dir  = $plugin_path[0];
					} elseif ( false !== strpos( $url, $theme_url ) ) {
						$asset_source_type = 'theme';
					} elseif ( false !== strpos( $url, $core_url ) || 'jquery' === $handle ) {
						$asset_source_type = 'core';
					} else {
						$asset_source_type = 'misc';
					}

					$url_info = pathinfo( $url );
					$asset    = array(
						'url'      => $url,
						'external' => (int) $this->is_external( $url ),
						'filename' => ! empty( $url_info['basename'] ) ? $url_info['basename'] : $url,
						'size'     => $this->get_asset_size( $url ),
						'disabled' => (int) $this->asset_disabled( $type, $handle ),
						'deps'     => isset( $data->registered[ $handle ]->deps ) ? $data->registered[ $handle ]->deps : array(),
					);
					if ( 'plugins' === $asset_source_type ) {
						$this->assets[ $asset_source_type ][ $plugin_dir ][ $type ][ $handle ] = $asset;
					} else {
						$this->assets[ $asset_source_type ][ $type ][ $handle ] = $asset;
					}
					$this->deps[] = array(
						'name' => $handle,
						'deps' => $asset['deps'],
						'type' => $type,
					);
				}
			}
		}
		global $wp_version;
		if ( version_compare( $wp_version, '4.2', '>=' ) ) {
			$url = '/wp-includes/js/wp-emoji-release.min.js';

			$this->assets['core']['js']['wp-emoji'] = array(
				'url'      => $url,
				'external' => false,
				'filename' => 'wp-emoji-release.min.js',
				'size'     => $this->get_asset_size( $url ),
				'disabled' => (int) $this->asset_disabled( 'js', 'wp-emoji' ),
				'deps'     => array(),
			);
		}
	}

	/**
	 * Make sure protocol-relative URLs like //www.example.com/wp-includes/script.js get a scheme added.
	 *
	 * @param string $url The URL to potentially fix.
	 * @return string The properly-schemed URL.
	 */
	function prepend_url_scheme( $url ) {
		if ( 0 === strpos( $url, '//' ) ) {
			return ( is_ssl() ? 'https:' : 'http' ) . $url;
		}
		return $url;
	}

	/**
	 * Get registered content types.
	 */
	function get_content_types() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		$this->content_types = get_post_types( array( 'public' => true ) );
	}

	/**
	 * Check the content type of the current page.
	 */
	function get_content_type() {
		if ( is_singular() ) {
			$this->content_type = get_post_type();
		}
	}

	/**
	 * See if the current content type matches a content type rule.
	 *
	 * @param string $rule A content-type rule (prefixed with T>).
	 * @return bool True if the current type matches the rule, false otherwise.
	 */
	function check_content_type( $rule ) {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		if ( 0 === strpos( $rule, 'T>' ) ) {
			$rule_content_type = substr( $rule, 2 );
			$this->debug_message( "found rule content type: $rule_content_type" );
			if ( $rule_content_type === $this->content_type ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Check if the user has disabled an asset for this particular page.
	 *
	 * @param string $type The type of asset: 'js' or 'css'.
	 * @param string $handle The handle/slug of the asset.
	 * @return bool True to suppress the asset for the current page, false otherwise.
	 */
	function asset_disabled( $type, $handle ) {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		$uri = $this->parse_url( add_query_arg( null, null ), PHP_URL_PATH );
		if ( wp_doing_ajax() && ! empty( $_POST['swis_slim_frontend'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			if ( $this->current_page !== $uri ) {
				$uri = $this->current_page;
			}
		}
		$this->debug_message( "request uri is $uri" );
		if ( 'jquery-migrate' === $handle && ! isset( $this->user_exclusions[ $handle ] ) && isset( $this->user_exclusions['jquery-core'] ) ) {
			$this->debug_message( "using jquery-core exclusions for $handle" );
			return $this->asset_disabled( $type, 'jquery-core' );
		}
		if ( 'jquery-core' === $handle && ! isset( $this->user_exclusions[ $handle ] ) && isset( $this->user_exclusions['jquery'] ) ) {
			$this->debug_message( "using jquery exclusions for $handle" );
			return $this->asset_disabled( $type, 'jquery' );
		}
		if ( isset( $this->user_exclusions[ $handle ] ) ) {
			if ( empty( $this->user_exclusions[ $handle ]['include'] ) && empty( $this->user_exclusions[ $handle ]['exclude'] ) ) {
				$this->debug_message( "site-wide rule triggered for $handle" );
				return true;
			}
			if ( ! empty( $this->user_exclusions[ $handle ]['include'] ) ) {
				foreach ( $this->user_exclusions[ $handle ]['include'] as $include ) {
					if ( $this->check_content_type( $include ) ) {
						$this->debug_message( "content-include rule triggered for $handle" );
						return false;
					}
					if ( '<home_page>' === $include && $uri === $this->home_path ) {
						$this->debug_message( "home page include rule triggered for $handle" );
						return false;
					}
					if ( false !== strpos( $include, '*' ) && false === strpos( $include, '#' ) && preg_match( "#$include#", $uri ) ) {
						$this->debug_message( "pattern-include ($include) rule triggered for $handle" );
						return false;
					} elseif ( $uri === $include ) {
						$this->debug_message( "page-include ($include) rule triggered for $handle" );
						return false;
					}
				}
				return true;
			}
			if ( ! empty( $this->user_exclusions[ $handle ]['exclude'] ) ) {
				foreach ( $this->user_exclusions[ $handle ]['exclude'] as $exclude ) {
					if ( $this->check_content_type( $exclude ) ) {
						$this->debug_message( "content-exclude rule triggered for $handle" );
						return true;
					}
					if ( '<home_page>' === $exclude && $uri === $this->home_path ) {
						$this->debug_message( "home page exclude rule triggered for $handle" );
						return true;
					}
					if ( false !== strpos( $exclude, '*' ) && false === strpos( $exclude, '#' ) && preg_match( "#$exclude#", $uri ) ) {
						$this->debug_message( "pattern-exclude ($exclude) rule triggered for $handle" );
						return true;
					} elseif ( $uri === $exclude ) {
						$this->debug_message( "page-exclude ($exclude) rule triggered for $handle" );
						return true;
					}
				}
			}
		}
		$this->debug_message( "no rules matched for $handle" );
		return false;
	}

	/**
	 * Remove JS/CSS files if the user has disabled them.
	 *
	 * @param string $url The address of the resource.
	 * @param string $handle The registered handle for the resource.
	 */
	function disable_assets( $url, $handle ) {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		$this->debug_message( "checking $url" );
		$type = current_filter() === 'script_loader_src' ? 'js' : 'css';
		if (
			'jquery-core' === $handle &&
			$this->is_frontend() &&
			is_user_logged_in() &&
			current_user_can( 'manage_options' ) &&
			! defined( 'SWIS_SLIM_DISABLE_FRONTEND_MENU' )
		) {
			return $url;
		}
		return $this->asset_disabled( $type, $handle ) ? false : $url;
	}

	/**
	 * Disable emoji JS/CSS based on user preference.
	 */
	function maybe_remove_emoji() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		if ( $this->asset_disabled( 'js', 'wp-emoji' ) ) {
			remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
			remove_action( 'wp_print_styles', 'print_emoji_styles' );
		}
	}

	/**
	 * Check to see if Emoji is enqueued.
	 *
	 * @return bool True if it is, false if it ain't.
	 */
	function is_emoji_active() {
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		return (bool) has_action( 'wp_head', 'print_emoji_detection_script' );
	}

	/**
	 * Get a list of dependent assets for any given asset.
	 *
	 * @param string $handle The asset handle/slug.
	 * @param string $type The asset type (js/css).
	 * @return array A list assets that depend on the $handle asset.
	 */
	function get_dependents( $handle, $type ) {
		$dependents = array();
		foreach ( $this->deps as $asset ) {
			if ( in_array( $handle, $asset['deps'], true ) && $type === $asset['type'] && 'jquery' !== $asset['name'] ) {
				$dependents[] = $asset['name'];
			}
		}
		if ( 'jquery-core' === $handle && empty( $dependents ) ) {
			return $this->get_dependents( 'jquery', 'js' );
		}
		if ( 'jquery-migrate' === $handle && empty( $dependents ) ) {
			return $this->get_dependents( 'jquery', 'js' );
		}
		return $dependents;
	}

	/**
	 * Display a list of discovered JS/CSS files for the current page.
	 */
	function display_assets() {
		if ( ! $this->is_frontend() ) {
			return;
		}
		$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
		echo "<div id='swis-slim-assets-pane' class='swis-slim-hidden'>\n";

		$this->get_content_types();
		$this->sample_type  = $this->get_content_type();
		$this->current_page = $this->parse_url( add_query_arg( null, null ), PHP_URL_PATH );
		$this->sample_page  = '/example-page/';

		$posts = get_posts( 'post_type=page&numberposts=1&fields=ids' );
		if ( ! empty( $posts[0] ) ) {
			$potential_sample = str_replace( get_home_url(), '', get_permalink( $posts[0] ) );
			if ( ! empty( $potential_sample ) && false === strpos( $potential_sample, 'http' ) && $this->current_page !== $potential_sample ) {
				$this->sample_page = $potential_sample;
			}
		}

		if ( ! empty( $this->assets['core'] ) ) {
			?>
			<button id='swis-slim-close-pane' class="button-secondary">Hide JS/CSS</button>
			<h1>
				SWIS Performance
				<?php $this->help_link( 'https://docs.ewww.io/article/97-disabling-unused-css-and-js' ); ?>
			</h1>
			<div style="display:none;" id="swis-slim-current-page"><?php echo esc_html( $this->current_page ); ?></div>
			<ul>
				<li><?php esc_html_e( 'Note that the list of CSS/JS file may be different on each page.', 'swis-performance' ); ?></li>
				<li><?php esc_html_e( 'Always test your pages after each change.', 'swis-performance' ); ?></li>
				<li><?php esc_html_e( 'Then, if something breaks, undo it by removing the last rule you added.', 'swis-performance' ); ?></li>
			</ul>
			<h2>
				<?php esc_html_e( 'Core', 'swis-performance' ); ?>
			</h2>
			<table class='swis-slim-assets'>
				<tr>
					<th class='swis-slim-asset-active'><?php esc_html_e( 'Active', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-details'><?php esc_html_e( 'Asset Details', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-size'><?php esc_html_e( 'Size', 'swis-performance' ); ?></th>
				</tr>
			<?php
			foreach ( $this->assets['core'] as $asset_type => $data ) {
				foreach ( $data as $handle => $asset ) {
					$this->display_asset_info( $handle, $asset, $asset_type );
				}
			}
			?>
			</table>
			<?php
		}
		if ( ! empty( $this->assets['plugins'] ) ) {
			?>
			<h2>
				<?php esc_html_e( 'Plugins', 'swis-performance' ); ?>
			</h2>
			<table class='swis-slim-assets'>
				<tr>
					<th class='swis-slim-asset-active'><?php esc_html_e( 'Active', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-details'><?php esc_html_e( 'Asset Details', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-size'><?php esc_html_e( 'Size', 'swis-performance' ); ?></th>
				</tr>
			<?php
			foreach ( $this->assets['plugins'] as $plugin => $asset_types ) {
				foreach ( $asset_types as $asset_type => $data ) {
					foreach ( $data as $handle => $asset ) {
						$this->display_asset_info( $handle, $asset, $asset_type );
					}
				}
			}
			?>
			</table>
			<?php
		}
		if ( ! empty( $this->assets['theme'] ) ) {
			?>
			<h2>
				<?php esc_html_e( 'Theme', 'swis-performance' ); ?>
			</h2>
			<table class='swis-slim-assets'>
				<tr>
					<th class='swis-slim-asset-active'><?php esc_html_e( 'Active', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-details'><?php esc_html_e( 'Asset Details', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-size'><?php esc_html_e( 'Size', 'swis-performance' ); ?></th>
				</tr>
			<?php
			foreach ( $this->assets['theme'] as $asset_type => $data ) {
				foreach ( $data as $handle => $asset ) {
					$this->display_asset_info( $handle, $asset, $asset_type );
				}
			}
			?>
			</table>
			<?php
		}
		if ( ! empty( $this->assets['misc'] ) ) {
			?>
			<h2>
				<?php esc_html_e( 'Miscellaneous', 'swis-performance' ); ?>
			</h2>
			<table class='swis-slim-assets'>
				<tr>
					<th class='swis-slim-asset-active'><?php esc_html_e( 'Active', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-details'><?php esc_html_e( 'Asset Details', 'swis-performance' ); ?></th>
					<th class='swis-slim-asset-size'><?php esc_html_e( 'Size', 'swis-performance' ); ?></th>
				</tr>
			<?php
			foreach ( $this->assets['misc'] as $asset_type => $data ) {
				foreach ( $data as $handle => $asset ) {
					$this->display_asset_info( $handle, $asset, $asset_type );
				}
			}
			?>
			</table>
			<?php
		}
		echo "</div>\n";
	}

	/**
	 * Display the table row for a particular asset.
	 *
	 * @param string $handle The asset handle.
	 * @param array  $asset The asset information.
	 * @param string $type The asset type (js/css).
	 */
	function display_asset_info( $handle, $asset, $type ) {
		$dependents = $this->get_dependents( $handle, $type );
		if ( 'yoast-seo-adminbar' === $handle ) {
			return;
		}
		if ( 'jquery-core' === $handle && empty( $dependents ) ) {
			return;
		}
		if ( 'jquery-migrate' === $handle && empty( $dependents ) ) {
			$jquery_dependents = $this->get_dependents( 'jquery-core', 'js' );
			if ( empty( $dependents ) ) {
				return;
			}
		}
		if ( 'jquery' === $handle ) {
			return;
		}
		if ( 0 === strpos( $asset['url'], '/' ) && 0 !== strpos( $asset['url'], '//' ) ) {
			$asset['url'] = get_site_url() . $asset['url'];
		}
		$rule = isset( $this->user_exclusions[ $handle ] ) ? $this->user_exclusions[ $handle ] : array();
		?>
				<tr>
					<td class="swis-slim-asset-status">
						<?php echo $asset['disabled'] ? "<span class='swis-slim-active-no'>" . esc_html__( 'No', 'swis-performance' ) . '</span>' : "<span class='swis-slim-active-yes'>" . esc_html__( 'Yes', 'swis-performance' ) . '</span>'; ?>
					</td>
					<td>
						<a class='swis-slim-link' href='<?php echo esc_url( $asset['url'] ); ?>' target='_blank'>
							<?php echo $asset['external'] ? esc_html( $asset['url'] ) : esc_html( $asset['filename'] ); ?>
						</a>
						<div class='swis-slim-info'>
							<div><?php echo '<strong>' . esc_html__( 'Handle:', 'swis-performance' ) . '</strong> ' . esc_html( $handle ); ?></div>
					<?php if ( ! empty( $asset['deps'] ) ) : ?>
							<div><?php echo '<strong>' . esc_html__( 'Requires:', 'swis-performance' ) . '</strong> ' . esc_html( implode( ', ', $asset['deps'] ) ); ?></div>
					<?php endif; ?>
					<?php if ( ! empty( $dependents ) ) : ?>
							<div><?php echo '<strong>' . esc_html__( 'Required by:', 'swis-performance' ) . '</strong> ' . esc_html( implode( ', ', $dependents ) ); ?></div>
					<?php endif; ?>
					<?php $this->display_frontend_rule_form( $handle, $rule, $asset ); ?>
					<?php if ( isset( $this->user_exclusions[ $handle ]['raw'] ) ) : ?>
							<!-- <div>
								<strong><?php echo esc_html__( 'Active rule:', 'swis-performance' ); ?></strong>
								<?php echo esc_html( $this->user_exclusions[ $handle ]['raw'] ); ?>
							</div> -->
					<?php endif; ?>
							<!-- <div class='swis-sample-rules'>
								<strong><?php echo esc_html_e( 'Sample Rules:', 'swis-performance' ); ?></strong><br>
								<?php echo esc_html__( 'Load on current page only:', 'swis-performance' ) . ' +' . esc_html( $this->current_page ) . ':' . esc_html( $handle ); ?><br>
								<?php echo esc_html__( 'Disable on current page only:', 'swis-performance' ) . ' -' . esc_html( $this->current_page ) . ':' . esc_html( $handle ); ?><br>
								<?php echo esc_html__( 'Disable everywhere:', 'swis-performance' ) . ' ' . esc_html( $handle ); ?><br>
								<?php echo esc_html__( 'Separate multiple pages with commas:', 'swis-performance' ) . ' +' . esc_html( $this->current_page ) . ',' . esc_html( $this->sample_page ) . ':' . esc_html( $handle ); ?><br>
							</div> -->
						</div>
					</td>
					<td>
						<?php echo esc_html( $asset['size'] ); ?>
					</td>
				</tr>
		<?php
	}

	/**
	 * Display the HTML for a given rule on the settings.
	 *
	 * @param string $handle The CSS/JS handle.
	 * @param array  $rule Parsed rule for the given $handle.
	 * @param array  $asset Asset info for the given $handle.
	 */
	private function display_frontend_rule_form( $handle, $rule, $asset = array() ) {
		$rule_id = preg_replace( '/[\W_]/', '', uniqid( '', true ) );
		if ( empty( $asset ) ) {
			$asset['disabled'] = $this->asset_disabled( '', $handle );
		}
		?>
		<form class="swis-slim-rule" data-slim-handle="<?php echo esc_attr( $handle ); ?>" data-slim-rule-id="<?php echo esc_attr( $rule_id ); ?>">
		<?php if ( ! empty( $rule['include'] ) ) : ?>
			<?php
			$includes = array();
			foreach ( $rule['include'] as $include ) {
				if ( 0 === strpos( $include, 'T>' ) ) {
					$includes[] = '<i>' . substr( $include, 2 ) . '</i> ' . esc_html__( 'content type', 'swis-performance' );
				} elseif ( '<home_page>' === $include ) {
					$includes[] = esc_html__( 'home page', 'swis-performance' );
				} else {
					$includes[] = $include;
				}
			}
			$raw_rule_parts = explode( ':', $rule['raw'] );
			$raw_rule_html  = ltrim( $raw_rule_parts[0], '+-' );
			?>
			<div class="swis-slim-rule-description">
				<div class="swis-slim-rule-prefix">
					<?php esc_html_e( 'Disabled everywhere except:', 'swis-performance' ); ?>
				</div>
				<input style="display:none;" type="radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="include" checked />
				<div class="swis-slim-pretty-rule">
					<?php echo wp_kses_post( implode( ', ', $includes ) ); ?>
				</div>
				<div class="swis-slim-error-message"></div>
				<div class="swis-slim-hidden">
					<div class="swis-slim-raw-rule">
						<input type="text" name="swis-slim-rule-exclusions-<?php echo esc_attr( $rule_id ); ?>" value="<?php echo esc_attr( $raw_rule_html . ( $asset['disabled'] ? ',' . $this->current_page : '' ) ); ?>" />
					</div>
					<p class="swis-slim-edit-rule-description description">
						<?php esc_html_e( 'Enter a comma-separated list of pages, URL patterns (use * as wildcard), or content types in the form T>post or T>page.', 'swis-performance' ); ?>
						<button type="button" class="button-primary swis-slim-rule-save"><?php esc_html_e( 'Save', 'swis-performance' ); ?></button>
					</p>
				</div>
			</div>
			<div class="swis-slim-rule-actions">
				<button type="button" class="button-secondary button-link-edit"><?php ( $asset['disabled'] ? esc_html_e( 'Add', 'swis-performance' ) : esc_html_e( 'Edit', 'swis-performance' ) ); ?></button>
				&nbsp;&nbsp;
				<button type="button" class="button-danger button-link-delete"><?php esc_html_e( 'Delete', 'swis-performance' ); ?></button>
			</div>
		<?php elseif ( ! empty( $rule['exclude'] ) ) : ?>
			<?php
			$excludes = array();
			foreach ( $rule['exclude'] as $exclude ) {
				if ( 0 === strpos( $exclude, 'T>' ) ) {
					$excludes[] = '<i>' . substr( $exclude, 2 ) . '</i> ' . esc_html__( 'content type', 'swis-performance' );
				} elseif ( '<home_page>' === $exclude ) {
					$excludes[] = esc_html__( 'home page', 'swis-performance' );
				} else {
					$excludes[] = $exclude;
				}
			}
			$raw_rule_parts = explode( ':', $rule['raw'] );
			$raw_rule_html  = ltrim( $raw_rule_parts[0], '+-' );
			?>
			<div class="swis-slim-rule-description">
				<div class="swis-slim-rule-prefix">
					<?php esc_html_e( 'Disabled on:', 'swis-performance' ); ?>
				</div>
				<input style="display:none;" type="radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="exclude" checked />
				<div class="swis-slim-pretty-rule">
					<?php echo wp_kses_post( implode( ', ', $excludes ) ); ?>
				</div>
				<div class="swis-slim-error-message"></div>
				<div class="swis-slim-hidden">
					<div class="swis-slim-raw-rule">
						<input type="text" name="swis-slim-rule-exclusions-<?php echo esc_attr( $rule_id ); ?>" value="<?php echo esc_attr( $raw_rule_html . ( $asset['disabled'] ? '' : ',' . $this->current_page ) ); ?>" />
					</div>
					<p class="swis-slim-edit-rule-description description">
						<?php esc_html_e( 'Enter a comma-separated list of pages, URL patterns (use * as wildcard), or content types in the form T>post or T>page.', 'swis-performance' ); ?>
						<button type="button" class="button-primary swis-slim-rule-save"><?php esc_html_e( 'Save', 'swis-performance' ); ?></button>
					</p>
				</div>
			</div>
			<div class="swis-slim-rule-actions">
				<button type="button" class="button-secondary button-link-edit"><?php ( $asset['disabled'] ? esc_html_e( 'Edit', 'swis-performance' ) : esc_html_e( 'Add', 'swis-performance' ) ); ?></button>
				&nbsp;&nbsp;
				<button type="button" class="button-danger button-link-delete"><?php esc_html_e( 'Delete', 'swis-performance' ); ?></button>
			</div>
		<?php elseif ( ! empty( $rule['raw'] ) ) : ?>
			<div class="swis-slim-rule-description">
				<div class="swis-slim-rule-prefix">
					<?php esc_html_e( 'Disabled everywhere', 'swis-performance' ); ?>
				</div>
				<input style="display:none;" type="radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="all" checked />
				<div class="swis-slim-error-message"></div>
			</div>
			<div class="swis-slim-rule-actions">
				<button type="button" class="button-danger button-link-delete"><?php esc_html_e( 'Delete', 'swis-performance' ); ?></button>
			</div>
		<?php else : ?>
			<div class="swis-slim-rule-description swis-slim-column">
				<?php if ( 'jquery-migrate' === $handle && ! empty( $this->user_exclusions['jquery-core'] ) ) : ?>
					<?php esc_html_e( 'Rules for jquery/jquery-core will automatically apply to jquery-migrate.', 'swis-performance' ); ?>
				<?php endif; ?>
				<div class="swis-slim-error-message"></div>
				<div class="swis-slim-row">
					<div class="swis-slim-reversible">
						<div class="swis-slim-row">
							<input type="radio" id="swis_slim_mode_exclude_<?php echo esc_attr( $rule_id ); ?>" class="swis-slim-radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="exclude" />
							<strong><label for="swis_slim_mode_exclude_<?php echo esc_attr( $rule_id ); ?>"><?php esc_html_e( 'disable on this page', 'swis-performance' ); ?></label></strong>
						</div>
						<div class="swis-slim-row">
							<input type="radio" id="swis_slim_mode_include_<?php echo esc_attr( $rule_id ); ?>" class="swis-slim-radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="include" />
							<strong><label for="swis_slim_mode_include_<?php echo esc_attr( $rule_id ); ?>"><?php esc_html_e( 'disable everywhere except this page', 'swis-performance' ); ?></label></strong>
						</div>
						<div class="swis-slim-row">
							<input type="radio" id="swis_slim_mode_all_<?php echo esc_attr( $rule_id ); ?>" class="swis-slim-radio" name="swis_slim_mode_<?php echo esc_attr( $rule_id ); ?>" value="all" />
							<strong><label for="swis_slim_mode_all_<?php echo esc_attr( $rule_id ); ?>"><?php esc_html_e( 'disable everywhere', 'swis-performance' ); ?></label></strong>
						</div>
					</div>
					<div class="swis-slim-rule-actions">
						<button type="button" class="button-secondary swis-slim-rule-customize"><?php esc_html_e( 'Customize Rule', 'swis-performance' ); ?></button>
						&nbsp;&nbsp;
						<button type="button" class="button-primary swis-slim-rule-add"><?php esc_html_e( 'Add Rule', 'swis-performance' ); ?></button>
					</div>
				</div>
				<div class="swis-slim-column swis-slim-raw-rule">
					<input style="display:none;" type="text" name="swis-slim-rule-exclusions-<?php echo esc_attr( $rule_id ); ?>" value="<?php echo esc_attr( $this->current_page ); ?>" />
					<label style="display:none;" for="swis-slim-rule-exclusions-<?php echo esc_attr( $rule_id ); ?>">
						<?php esc_html_e( 'Comma-separated list of pages, URL patterns (use * as wildcard), or content types in the form T>post or T>page.', 'swis-performance' ); ?>
					</label>
				</div>
			</div>
		<?php endif; ?>
		</form>
		<?php
	}

}