759 lines
21 KiB
PHP
759 lines
21 KiB
PHP
<?php
|
|
/**
|
|
* Utility functions collection.
|
|
*
|
|
* Provides shared helper methods and reusable logic used across
|
|
* different components of the plugin.
|
|
*
|
|
* @package Head_Footer_Code
|
|
* @since 1.4.0
|
|
*/
|
|
|
|
namespace Techwebux\Hfc;
|
|
|
|
// If this file is called directly, abort.
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
class Common {
|
|
/** @var array Settings retrieved from the main controller. */
|
|
private static $settings = null;
|
|
|
|
/** @var Plugin_Info Plugin metadata object. */
|
|
protected static $plugin;
|
|
|
|
/** @var array Custom set of allowed HTML tags. */
|
|
private static $allowed_html = null;
|
|
|
|
/**
|
|
* Injects the plugin metadata object into the Common utility class.
|
|
*
|
|
* This allows static methods to access plugin properties like name,
|
|
* version, and directory without needing global constants.
|
|
*
|
|
* @param Plugin_Info $plugin The plugin metadata container.
|
|
* @param array $settings Optional settings array to initialize.
|
|
*/
|
|
public static function init( Plugin_Info $plugin, $settings = null ) {
|
|
self::$plugin = $plugin;
|
|
|
|
if ( null !== $settings ) {
|
|
self::$settings = $settings;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize settings if not already set.
|
|
*/
|
|
private static function init_settings() {
|
|
if ( null === self::$settings ) {
|
|
self::$settings = Main::get_settings();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the current user has any of the allowed roles.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function user_has_allowed_role() {
|
|
self::init_settings();
|
|
|
|
// Always allow Super Admin (Multisite).
|
|
$current_user = wp_get_current_user();
|
|
if ( is_super_admin( $current_user->ID ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Get current user roles.
|
|
$user_roles = (array) $current_user->roles;
|
|
|
|
// Merge fixed always-allowed and configurable allowed roles.
|
|
$allowed_roles = array_merge(
|
|
array( 'administrator', 'shop_manager' ),
|
|
self::$settings['article']['allowed_roles']
|
|
);
|
|
|
|
// Check if any of user's roles are in the allowed list.
|
|
return (bool) array_intersect( $user_roles, $allowed_roles );
|
|
}
|
|
|
|
/**
|
|
* Check if homepage uses Blog mode
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_homepage_blog_posts() {
|
|
return is_home() && 'posts' === get_option( 'show_on_front', false );
|
|
}
|
|
|
|
/**
|
|
* Check if the current singular post type is enabled in plugin settings.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_supported_singular_post_type() {
|
|
self::init_settings();
|
|
|
|
$singular_post_type = self::get_singular_post_type();
|
|
|
|
return $singular_post_type && in_array( $singular_post_type, self::$settings['article']['post_types'], true );
|
|
}
|
|
|
|
/**
|
|
* Check if current queried request is on supported taxonomy page
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_supported_taxonomy() {
|
|
self::init_settings();
|
|
|
|
$queried_object = get_queried_object();
|
|
|
|
return ( is_category() || is_tag() || is_tax() )
|
|
&& isset( $queried_object->taxonomy )
|
|
&& in_array( $queried_object->taxonomy, self::$settings['article']['taxonomies'], true );
|
|
}
|
|
|
|
/**
|
|
* Determine should we print site-wide code
|
|
* or it should be replaced with homepage/article/taxonomy code.
|
|
*
|
|
* @param string $behavior Behavior for article specific code (replace/append).
|
|
* @param string $code Article specific custom code.
|
|
* @param string $post_type Post type of current article.
|
|
* @param array $post_types Array of post types where article specific code is enabled.
|
|
* @param boolean $is_taxonomy Indicate if current displayed page is taxonomy or not.
|
|
* @return boolean Boolean that determine should site-wide code be printed (true) or not (false).
|
|
*/
|
|
public static function is_printable_sitewide_v1(
|
|
$behavior = 'append',
|
|
$code = '',
|
|
$post_type = null,
|
|
$post_types = array(),
|
|
$is_taxonomy = false
|
|
) {
|
|
// Always print if not replacing.
|
|
if ( 'replace' !== $behavior ) {
|
|
return true;
|
|
}
|
|
|
|
// If replacing but code is empty, still print sitewide.
|
|
if ( empty( $code ) ) {
|
|
return true;
|
|
}
|
|
|
|
// If replacing on non-supported post type, print sitewide.
|
|
if ( ! $is_taxonomy && ! in_array( $post_type, $post_types, true ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Otherwise, don't print sitewide (it's being replaced).
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Determine should we print site-wide code
|
|
* or it should be replaced with homepage/article/taxonomy code.
|
|
*
|
|
* @param string $behavior Behavior for article specific code (replace/append).
|
|
* @param string $code Article specific custom code.
|
|
* @param string $post_type Post type of current article.
|
|
* @param array $post_types Array of post types where article specific code is enabled.
|
|
* @param boolean $is_taxonomy Indicate if current displayed page is taxonomy or not.
|
|
* @return boolean Boolean that determine should site-wide code be printed (true) or not (false).
|
|
*/
|
|
public static function is_printable_sitewide(
|
|
$behavior = 'append',
|
|
$code = '',
|
|
$post_type = null,
|
|
$post_types = array(),
|
|
$is_taxonomy = false
|
|
) {
|
|
// Always print if not replacing.
|
|
if ( 'replace' !== $behavior ) {
|
|
return true;
|
|
}
|
|
|
|
// If replacing but code is empty, still print sitewide.
|
|
if ( empty( $code ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Check if we're on homepage in blog mode.
|
|
$is_homepage_blog_posts = self::is_homepage_blog_posts();
|
|
|
|
// On homepage with replace behavior and non-empty code, don't print sitewide.
|
|
if ( $is_homepage_blog_posts ) {
|
|
return false;
|
|
}
|
|
|
|
// On taxonomy with replace behavior and non-empty code, don't print sitewide.
|
|
if ( $is_taxonomy ) {
|
|
return false;
|
|
}
|
|
|
|
// If replacing on non-supported post type, print sitewide.
|
|
if ( ! in_array( $post_type, $post_types, true ) ) {
|
|
return true;
|
|
}
|
|
|
|
// We're on a supported post type with replace behavior and non-empty code.
|
|
// Don't print sitewide (it's being replaced).
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function to check if code should be added on paged homepage in Blog mode
|
|
*
|
|
* @param bool $is_homepage_blog_posts If current page is blog homepage.
|
|
* @param array $settings Plugin settings (optional, uses static if not provided).
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_addable_to_paged_homepage( $is_homepage_blog_posts, $settings = null ) {
|
|
// Use provided settings or fall back to static settings.
|
|
if ( null === $settings ) {
|
|
self::init_settings();
|
|
$settings = self::$settings;
|
|
}
|
|
|
|
if (
|
|
true === $is_homepage_blog_posts
|
|
&& is_paged()
|
|
&& ! empty( $settings['homepage']['paged'] )
|
|
&& 'no' === $settings['homepage']['paged']
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Sanitizes an HTML classnames to ensure it only contains valid characters.
|
|
*
|
|
* Strips the string down to A-Z,a-z,0-9,_,-, . If this results in an empty
|
|
* string then it will return the alternative value supplied.
|
|
*
|
|
* @param string $classes The classnames to be sanitized (multiple classnames separated by space).
|
|
* @param string $fallback Optional. The value to return if the sanitization ends up as an empty string.
|
|
* Defaults to an empty string.
|
|
*
|
|
* @return string The sanitized value.
|
|
*/
|
|
public static function sanitize_html_classes( $classes, $fallback = '' ) {
|
|
// Strip out any %-encoded octets.
|
|
$sanitized = preg_replace( '|%[a-fA-F0-9][a-fA-F0-9]|', '', $classes );
|
|
|
|
// Limit to A-Z, a-z, 0-9, '_', '-' and ' ' (for multiple classes).
|
|
$sanitized = trim( preg_replace( '/[^A-Za-z0-9\_\ \-]/', '', $sanitized ) );
|
|
|
|
if ( '' === $sanitized && $fallback ) {
|
|
return self::sanitize_html_classes( $fallback );
|
|
}
|
|
|
|
return $sanitized;
|
|
}
|
|
|
|
/**
|
|
* Defines the expanded schema of allowed HTML tags and attributes for KSES.
|
|
*
|
|
* Extends the default `post` global with specific attributes required for
|
|
* modern tracking scripts, preloading (fetchpriority, imagesrcset),
|
|
* and security (nonce, integrity).
|
|
*
|
|
* @return array Map of allowed tags and their permitted attributes.
|
|
*/
|
|
public static function allowed_html() {
|
|
// Return cached value if already initialized.
|
|
if ( null !== self::$allowed_html ) {
|
|
return self::$allowed_html;
|
|
}
|
|
|
|
// Allow safe HTML, JS, and CSS.
|
|
self::$allowed_html = array_replace_recursive(
|
|
wp_kses_allowed_html( 'post' ), // Allow safe HTML for posts.
|
|
array(
|
|
'noscript' => true,
|
|
// Allow <script> tags.
|
|
'script' => array(
|
|
'type' => true,
|
|
'async' => true,
|
|
'defer' => true,
|
|
'src' => true, // remote
|
|
'crossorigin' => true, // security
|
|
'nonce' => true, // security
|
|
'charset' => true,
|
|
// global
|
|
'id' => true,
|
|
'class' => true,
|
|
'dir' => true,
|
|
'data-*' => true,
|
|
),
|
|
// Allow <style> tags.
|
|
'style' => array(
|
|
'media' => true,
|
|
'type' => true,
|
|
'scoped' => true,
|
|
'nonce' => true,
|
|
'title' => true,
|
|
// global
|
|
'id' => true,
|
|
'class' => true,
|
|
'dir' => true,
|
|
'data-*' => true,
|
|
),
|
|
// Allow <link> tags for CSS and preloading.
|
|
'link' => array(
|
|
'href' => true,
|
|
'rel' => true,
|
|
'media' => true,
|
|
'hreflang' => true,
|
|
'type' => true,
|
|
'sizes' => true,
|
|
'title' => true,
|
|
'fetchpriority' => true, // preload
|
|
'as' => true, // preload
|
|
'imagesrcset' => true, // preload for images
|
|
'imagesizes' => true, // preload for images
|
|
'crossorigin' => true, // security
|
|
'nonce' => true, // security
|
|
'itemprop' => true, // for structured data
|
|
'referrerpolicy' => true, // security
|
|
'integrity' => true, // security
|
|
// global
|
|
'id' => true,
|
|
'class' => true,
|
|
'dir' => true,
|
|
'data-*' => true,
|
|
),
|
|
// Allow <meta> tags.
|
|
'meta' => array(
|
|
'name' => true,
|
|
'http-equiv' => true,
|
|
'content' => true,
|
|
'charset' => true,
|
|
'itemprop' => true,
|
|
'media' => true,
|
|
'property' => true,
|
|
// global
|
|
'id' => true,
|
|
'class' => true,
|
|
'dir' => true,
|
|
'data-*' => true,
|
|
),
|
|
// Allow <iframe> for GTag and custom embeds.
|
|
'iframe' => array(
|
|
// standard
|
|
'src' => true,
|
|
'srcdoc' => true,
|
|
'name' => true,
|
|
'sandbox' => true,
|
|
'seamless' => true,
|
|
'width' => true,
|
|
'height' => true,
|
|
// global
|
|
'class' => true,
|
|
'hidden' => true,
|
|
'id' => true,
|
|
'style' => true,
|
|
'loading' => true,
|
|
'dir' => true,
|
|
'data-*' => true,
|
|
),
|
|
)
|
|
);
|
|
|
|
return self::$allowed_html;
|
|
}
|
|
|
|
/**
|
|
* Define allowed FORM HTML for wp_kses
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function form_allowed_html() {
|
|
return array(
|
|
'fieldset' => array(),
|
|
'label' => array(
|
|
'for' => array(),
|
|
),
|
|
'input' => array(
|
|
'type' => array(),
|
|
'name' => array(),
|
|
'id' => array(),
|
|
'value' => array(),
|
|
'class' => array(),
|
|
'min' => array(), // number
|
|
'max' => array(), // number
|
|
'step' => array(), // number
|
|
'checked' => array(), // checkbox
|
|
'required' => true,
|
|
'minlength' => true,
|
|
'maxlength' => true,
|
|
'size' => true,
|
|
),
|
|
'select' => array(
|
|
'id' => array(),
|
|
'name' => array(),
|
|
'class' => array(),
|
|
),
|
|
'option' => array(
|
|
'value' => array(),
|
|
'selected' => array(),
|
|
),
|
|
'textarea' => array(
|
|
'name' => array(),
|
|
'id' => array(),
|
|
'rows' => array(),
|
|
'class' => array(),
|
|
'title' => array(),
|
|
'style' => array(),
|
|
),
|
|
'p' => array(
|
|
'class' => true,
|
|
),
|
|
'a' => array(
|
|
'href' => array(),
|
|
'target' => array( '_blank' ),
|
|
'class' => true,
|
|
'title' => true,
|
|
),
|
|
'code' => array(),
|
|
'br' => array(),
|
|
'strong' => array(),
|
|
'em' => array(),
|
|
'pre' => array(),
|
|
'span' => array(
|
|
'class' => true,
|
|
),
|
|
'i' => true,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Sanitizes HTML content while preserving script and style tag integrity.
|
|
*
|
|
* This method employs a placeholder strategy: it extracts `<script>` and `<style>`
|
|
* blocks, sanitizes their attributes, and hides them from `wp_kses()` to prevent
|
|
* the stripping of valid JS/CSS logic. After the remaining HTML is sanitized,
|
|
* the blocks are reinstated.
|
|
*
|
|
* @param string $content The raw HTML/JS/CSS content to sanitize.
|
|
* @return string Sanitized content with preserved safe scripts/styles.
|
|
*/
|
|
public static function sanitize_html_with_scripts( $content ) {
|
|
$allowed_html = self::allowed_html();
|
|
$placeholders = array();
|
|
|
|
// Extract <script> and <style> blocks.
|
|
$regex = '#<(script|style)\b[^>]*>.*?</\1>#is';
|
|
|
|
$content = preg_replace_callback(
|
|
$regex,
|
|
function ( $matches ) use ( &$placeholders, $allowed_html ) {
|
|
$full_tag = $matches[0];
|
|
$tag_name = strtolower( $matches[1] ); // script or style
|
|
|
|
// Extract opening tag for improved security, e.g. <script onload="…">
|
|
if ( preg_match( '/^<' . $tag_name . '[^>]*>/i', $full_tag, $tag_match ) ) {
|
|
$opening_tag = $tag_match[0];
|
|
$sanitized_opening_tag = wp_kses( $opening_tag, array( $tag_name => $allowed_html[ $tag_name ] ) );
|
|
if ( ! empty( $sanitized_opening_tag ) ) {
|
|
$full_tag = str_replace( $opening_tag, $sanitized_opening_tag, $full_tag );
|
|
}
|
|
}
|
|
|
|
$placeholder = '__TWU_' . strtoupper( $tag_name ) . '_PLACEHOLDER_' . count( $placeholders ) . '__';
|
|
$placeholders[ $placeholder ] = $full_tag;
|
|
|
|
return $placeholder;
|
|
},
|
|
$content
|
|
);
|
|
|
|
// Extract Google PageMap XML comment blocks before wp_kses strips comments.
|
|
$content = preg_replace_callback(
|
|
'/<!--\s*<PageMap\b[^>]*>.*?<\/PageMap>\s*-->/is',
|
|
function ( $matches ) use ( &$placeholders ) {
|
|
$placeholder = '__TWU_PAGEMAP_PLACEHOLDER_' . count( $placeholders ) . '__';
|
|
$placeholders[ $placeholder ] = self::sanitize_pagemap( $matches[0] );
|
|
return $placeholder;
|
|
},
|
|
$content
|
|
);
|
|
|
|
// Sanitize rest of content (outside scripts/styles).
|
|
$content = wp_kses( $content, $allowed_html );
|
|
|
|
// Reinstate all placeholders.
|
|
if ( ! empty( $placeholders ) ) {
|
|
$content = str_replace( array_keys( $placeholders ), array_values( $placeholders ), $content );
|
|
}
|
|
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Sanitize the whole HFC data array (for posts, terms, settings)
|
|
*
|
|
* @since 1.5.0
|
|
*
|
|
* @param array $input The raw $_POST['auhfc'] data.
|
|
* @return array Sanitized data.
|
|
*/
|
|
public static function sanitize_hfc_data( $input ) {
|
|
if ( ! is_array( $input ) ) {
|
|
return array();
|
|
}
|
|
|
|
// Temporarily remove Jetpack filter that may interfere with wp_kses.
|
|
$jetpack_filter = array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' );
|
|
$has_jetpack = is_callable( $jetpack_filter );
|
|
|
|
if ( $has_jetpack ) {
|
|
remove_filter( 'pre_kses', $jetpack_filter, 100 );
|
|
}
|
|
|
|
// Build sanitized data array.
|
|
$sanitized = array(
|
|
'behavior' => isset( $input['behavior'] ) ? sanitize_key( $input['behavior'] ) : 'append',
|
|
'head' => isset( $input['head'] ) ? self::sanitize_html_with_scripts( $input['head'] ) : '',
|
|
'body' => isset( $input['body'] ) ? self::sanitize_html_with_scripts( $input['body'] ) : '',
|
|
'footer' => isset( $input['footer'] ) ? self::sanitize_html_with_scripts( $input['footer'] ) : '',
|
|
);
|
|
|
|
// Reinstate Jetpack filter.
|
|
if ( $has_jetpack ) {
|
|
add_filter( 'pre_kses', $jetpack_filter, 100 );
|
|
}
|
|
|
|
return $sanitized;
|
|
}
|
|
|
|
/**
|
|
* Sanitize a Google PageMap XML comment block.
|
|
*
|
|
* Validates that only legal PageMap elements and attributes are present
|
|
* before reinserting into the output. Strips anything unexpected.
|
|
*
|
|
* Structure: <!-- <PageMap> <DataObject type="..."> <Attribute name="..." value="..."/> </DataObject> </PageMap> -->
|
|
*
|
|
* @see https://developers.google.com/custom-search/docs/structured_data#using-pagemaps
|
|
*
|
|
* @param string $raw Raw PageMap comment block.
|
|
* @return string Sanitized PageMap comment block, or empty string if invalid.
|
|
*/
|
|
private static function sanitize_pagemap( $raw ) {
|
|
// Strip the comment wrapper and work with the inner XML.
|
|
$inner = preg_replace( '/^<!--\s*(.*?)\s*-->$/is', '$1', trim( $raw ) );
|
|
|
|
if ( empty( $inner ) ) {
|
|
return '';
|
|
}
|
|
|
|
// Only allow known PageMap tags and attributes.
|
|
$allowed = array(
|
|
'pagemap' => array(),
|
|
'dataobject' => array(
|
|
'type' => true,
|
|
'id' => true,
|
|
),
|
|
'attribute' => array(
|
|
'name' => true,
|
|
'value' => true,
|
|
),
|
|
);
|
|
|
|
$sanitized_inner = wp_kses( $inner, $allowed );
|
|
|
|
if ( empty( trim( $sanitized_inner ) ) ) {
|
|
return '';
|
|
}
|
|
|
|
return '<!--' . "\n" . trim( $sanitized_inner ) . "\n" . '-->';
|
|
}
|
|
|
|
/**
|
|
* Get values of metabox fields for Posts or Terms.
|
|
*
|
|
* @param string $field_name Field key.
|
|
* @param int $id Post ID or Term ID.
|
|
* @param string $type `post` or `term`.
|
|
* @return mixed
|
|
*/
|
|
public static function get_meta( $field_name, $id, $type = 'post' ) {
|
|
if ( empty( $field_name ) || empty( $id ) ) {
|
|
return ( 'behavior' === $field_name ) ? 'append' : '';
|
|
}
|
|
|
|
$meta_key = '_auhfc';
|
|
|
|
// Get meta data based on type.
|
|
$data = ( 'post' === $type )
|
|
? get_post_meta( $id, $meta_key, true )
|
|
: get_term_meta( $id, $meta_key, true );
|
|
|
|
// Check if we got array and requested key exists.
|
|
if ( is_array( $data ) && isset( $data[ $field_name ] ) ) {
|
|
// Remove slashes from escaped value (make value ready to use).
|
|
return stripslashes_deep( $data[ $field_name ] );
|
|
}
|
|
|
|
// Default for behavior.
|
|
if ( 'behavior' === $field_name ) {
|
|
return 'append';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Helper: Get post meta values.
|
|
*
|
|
* @param string $field_name Field key.
|
|
* @param int $post_id Post ID.
|
|
* @return mixed
|
|
*/
|
|
public static function get_post_meta( $field_name, $post_id ) {
|
|
return self::get_meta( $field_name, $post_id, 'post' );
|
|
}
|
|
|
|
/**
|
|
* Helper: Get term meta values.
|
|
*
|
|
* @param string $field_name Field key.
|
|
* @param int $term_id Term ID.
|
|
* @return mixed
|
|
*/
|
|
public static function get_term_meta( $field_name, $term_id ) {
|
|
return self::get_meta( $field_name, $term_id, 'term' );
|
|
}
|
|
|
|
/**
|
|
* Smart wrapper: Get meta with auto-detected ID.
|
|
*
|
|
* @param string $field_name Field key.
|
|
* @param string $type `post` or `term`.
|
|
* @return mixed
|
|
*/
|
|
public static function get_meta_auto( $field_name, $type = 'post' ) {
|
|
return self::get_meta( $field_name, get_queried_object_id(), $type );
|
|
}
|
|
|
|
/**
|
|
* Get Post Type for singular requests.
|
|
*
|
|
* @return mixed Post type slug or `false` if not on a singular page.
|
|
*/
|
|
public static function get_singular_post_type() {
|
|
return is_singular() ? get_post_type() : false;
|
|
}
|
|
|
|
/**
|
|
* Return security risk notice title and message
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function get_security_risk_notice() {
|
|
return array(
|
|
'title' => __( 'WARNING!', 'head-footer-code' ),
|
|
'message' => __( 'Enter only safe, secure, and code from a trusted source. Unsafe or invalid code may break your site or pose security risks.', 'head-footer-code' ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Helper: Get scope label.
|
|
*
|
|
* @param string $scope Scope identifier.
|
|
* @return string
|
|
*/
|
|
private static function get_scope_label( $scope ) {
|
|
$labels = array(
|
|
'h' => 'Homepage',
|
|
's' => 'Site-wide',
|
|
'a' => 'Article specific',
|
|
'c' => 'Category specific',
|
|
't' => 'Taxonomy specific',
|
|
);
|
|
return isset( $labels[ $scope ] ) ? $labels[ $scope ] : 'Unknown';
|
|
}
|
|
|
|
/**
|
|
* Helper: Get location label.
|
|
*
|
|
* @param string $location Location identifier.
|
|
* @return string
|
|
*/
|
|
private static function get_location_label( $location ) {
|
|
$labels = array(
|
|
'h' => 'HEAD',
|
|
'b' => 'BODY',
|
|
'f' => 'FOOTER',
|
|
);
|
|
return isset( $labels[ $location ] ) ? $labels[ $location ] : 'UNKNOWN';
|
|
}
|
|
|
|
/**
|
|
* Wraps text in <code> tags and escapes HTML entities.
|
|
*
|
|
* @param string $text Text to format.
|
|
* @return string
|
|
*/
|
|
public static function format_as_code( $text ) {
|
|
return sprintf( '<code>%s</code>', esc_html( $text ) );
|
|
}
|
|
|
|
/**
|
|
* Wrap code block with debugging info when WP_DEBUG is true.
|
|
*
|
|
* @param string $scope Scope of output (s - SITE WIDE, a - ARTICLE SPECIFIC, h - HOMEPAGE).
|
|
* @param string $location Location of output (h - HEAD, b - BODY, f - FOOTER).
|
|
* @param string $message Output message.
|
|
* @param string $code Code for output.
|
|
* @return string Composed string.
|
|
*/
|
|
public static function annotate_code_block(
|
|
$scope = null,
|
|
$location = null,
|
|
$message = null,
|
|
$code = null
|
|
) {
|
|
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
|
|
return $code;
|
|
}
|
|
|
|
if ( null === $scope || null === $location || null === $message ) {
|
|
return '';
|
|
}
|
|
|
|
$scope_label = self::get_scope_label( $scope );
|
|
$location_label = self::get_location_label( $location );
|
|
|
|
return sprintf(
|
|
'<!-- %1$s: %2$s %3$s section start (%4$s) -->%6$s%5$s%6$s<!-- %1$s: %2$s %3$s section end (%4$s) -->%6$s',
|
|
self::$plugin->name, // 1
|
|
esc_html( $scope_label ), // 2
|
|
esc_html( $location_label ), // 3
|
|
esc_html( trim( $message ) ), // 4
|
|
trim( $code ), // 5 - RAW (Pre-sanitized)
|
|
"\n" // 6
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Print security risk notice
|
|
*/
|
|
public static function print_security_risk_notice() {
|
|
echo wp_kses(
|
|
self::get_security_risk_notice(),
|
|
array(
|
|
'p' => array( 'class' => true ),
|
|
'strong' => array(),
|
|
)
|
|
);
|
|
}
|
|
}
|