OwlCyberSecurity - MANAGER
Edit File: class-amp-validation-callback-wrapper.php
<?php /** * Class AMP_Validation_Callback_Wrapper * * @package AMP */ /** * Class AMP_Validation_Callback_Wrapper * * @since 1.2.1 * @internal */ class AMP_Validation_Callback_Wrapper implements ArrayAccess { /** * Callback data. * * @var array */ protected $callback; /** * Function to call before invoking the callback. * * @var callable|null */ protected $before_invoke; /** * AMP_Validation_Callback_Wrapper constructor. * * @param array $callback { * The callback data. * * @type callable $function * @type int $accepted_args * @type array $source * @type array $indirect_sources * } * @param callable|null $before_invoke Additional callback to run before invoking original callback. Optional. */ public function __construct( $callback, $before_invoke = null ) { $this->callback = $callback; $this->before_invoke = $before_invoke; } /** * Get callback function. * * @return callable */ public function get_callback_function() { return $this->callback['function']; } /** * Prepare for invocation. * * @since 1.5 * * @param mixed ...$args Arguments. * @return array Preparation data. * * @global WP_Scripts|null $wp_scripts * @global WP_Styles|null $wp_styles */ protected function prepare( ...$args ) { global $wp_scripts, $wp_styles; if ( isset( $wp_styles ) && $wp_styles instanceof WP_Styles ) { $styles = $wp_styles; } elseif ( isset( $args[0] ) && $args[0] instanceof WP_Styles ) { $styles = $args[0]; // This is a special case for wp_default_styles(). } else { $styles = null; } if ( isset( $wp_scripts ) && $wp_scripts instanceof WP_Scripts ) { $scripts = $wp_scripts; } elseif ( isset( $args[0] ) && $args[0] instanceof WP_Scripts ) { $scripts = $args[0]; // This is a special case for wp_default_scripts(). } else { $scripts = null; } if ( isset( $styles ) ) { $before_styles_enqueued = $styles->queue; $before_styles_registered = array_keys( $styles->registered ); $before_styles_extras = wp_list_pluck( $styles->registered, 'extra' ); } else { $before_styles_registered = []; $before_styles_enqueued = []; $before_styles_extras = []; } if ( isset( $scripts ) ) { $before_scripts_enqueued = $scripts->queue; $before_scripts_registered = array_keys( $scripts->registered ); $before_scripts_extras = wp_list_pluck( $scripts->registered, 'extra' ); } else { $before_scripts_registered = []; $before_scripts_enqueued = []; $before_scripts_extras = []; } $is_filter = isset( $this->callback['source']['hook'] ) && ! did_action( $this->callback['source']['hook'] ); // Wrap the markup output of (action) hooks in source comments. AMP_Validation_Manager::$hook_source_stack[] = $this->callback['source']; if ( ! $is_filter && AMP_Validation_Manager::can_output_buffer() ) { $has_buffer_started = ob_start( [ AMP_Validation_Manager::class, 'wrap_buffer_with_source_comments' ] ); } else { $has_buffer_started = false; } return compact( 'styles', 'before_styles_registered', 'before_styles_enqueued', 'before_styles_extras', 'scripts', 'before_scripts_registered', 'before_scripts_enqueued', 'before_scripts_extras', 'is_filter', 'has_buffer_started' ); } /** * Invoke wrapped callback. * * @param array ...$args Args. * @return mixed Response. */ public function __invoke( ...$args ) { if ( $this->before_invoke ) { call_user_func( $this->before_invoke ); } $preparation = $this->prepare( ...$args ); $result = call_user_func_array( $this->callback['function'], array_slice( $args, 0, (int) $this->callback['accepted_args'] ) ); $this->finalize( $preparation ); return $result; } /** * Invoke wrapped callback with first argument passed by reference. * * @since 1.5 * * @param object $first_arg First argument. * @param array ...$other_args Other arguments. * @return mixed */ public function invoke_with_first_ref_arg( &$first_arg, ...$other_args ) { if ( $this->before_invoke ) { call_user_func( $this->before_invoke ); } $preparation = $this->prepare( $first_arg, ...$other_args ); $function = $this->callback['function']; $other_accepted_args = array_slice( $other_args, 0, (int) $this->callback['accepted_args'] - 1 ); if ( $function instanceof self ) { $result = $function->invoke_with_first_ref_arg( $first_arg, ...$other_accepted_args ); } else { $result = $function( $first_arg, ...$other_accepted_args ); } $this->finalize( $preparation ); return $result; } /** * Finalize invocation. * * @since 1.5 * * @param array $preparation Preparation data. * * @global WP_Scripts|null $wp_scripts * @global WP_Styles|null $wp_styles */ protected function finalize( array $preparation ) { // If a script/style was registered or enqueued in the callback, these should now be defined if not defined already. global $wp_scripts, $wp_styles; if ( $preparation['has_buffer_started'] ) { ob_end_flush(); } array_pop( AMP_Validation_Manager::$hook_source_stack ); if ( isset( $wp_styles ) && $wp_styles instanceof WP_Styles ) { $styles = $wp_styles; } elseif ( isset( $preparation['styles'] ) && $preparation['styles'] instanceof WP_Styles ) { $styles = $preparation['styles']; } if ( isset( $styles ) ) { $this->finalize_styles( $styles, $preparation['before_styles_registered'], $preparation['before_styles_enqueued'], $preparation['before_styles_extras'] ); } if ( isset( $wp_scripts ) && $wp_scripts instanceof WP_Scripts ) { $scripts = $wp_scripts; } elseif ( isset( $preparation['scripts'] ) && $preparation['scripts'] instanceof WP_Scripts ) { $scripts = $preparation['scripts']; } if ( isset( $scripts ) ) { $this->finalize_scripts( $scripts, $preparation['before_scripts_registered'], $preparation['before_scripts_enqueued'], $preparation['before_scripts_extras'] ); } } /** * Finalize styles after invocation. * * @since 1.5 * * @param WP_Styles $wp_styles Styles registry. * @param string[] $before_registered Style handles registered before invocation. * @param string[] $before_enqueued Style handles enqueued before invocation. * @param array[] $before_extras Style extras before invocation. */ protected function finalize_styles( WP_Styles $wp_styles, array $before_registered, array $before_enqueued, array $before_extras ) { $sources = [ $this->callback['source'] ]; if ( ! empty( $this->callback['indirect_sources'] ) ) { $sources = array_merge( $sources, $this->callback['indirect_sources'] ); } // Keep track of which source enqueued the styles. // Note: Only the first time a style is registered/enqueued will be detected. $added_handles = array_unique( array_merge( array_diff( $wp_styles->queue, $before_enqueued ), array_diff( array_keys( $wp_styles->registered ), $before_registered ) ) ); foreach ( $added_handles as $handle ) { foreach ( $sources as $source ) { AMP_Validation_Manager::$enqueued_style_sources[ $handle ][] = array_merge( $source, [ 'dependency_type' => 'style' ], compact( 'handle' ) ); } } // Keep track of which source added an inline style. foreach ( $wp_styles->registered as $handle => $dependency ) { if ( empty( $dependency->extra['after'] ) ) { continue; } $additions = array_diff( array_filter( $dependency->extra['after'] ), array_filter( isset( $before_extras[ $handle ]['after'] ) ? (array) $before_extras[ $handle ]['after'] : [] ) ); foreach ( $additions as $addition ) { foreach ( $sources as $source ) { AMP_Validation_Manager::$extra_style_sources[ $handle ][ $addition ][] = array_merge( $source, [ 'dependency_type' => 'style', 'extra_key' => 'after', 'text' => $addition, ], compact( 'handle' ) ); } } } } /** * Finalize scripts after invocation. * * @since 1.5 * * @param WP_Scripts $wp_scripts Scripts registry. * @param string[] $before_registered Script handles registered before invocation. * @param string[] $before_enqueued Script handles enqueued before invocation. * @param array[] $before_extras Script extras before invocation. */ protected function finalize_scripts( WP_Scripts $wp_scripts, array $before_registered, array $before_enqueued, array $before_extras ) { $sources = [ $this->callback['source'] ]; if ( ! empty( $this->callback['indirect_sources'] ) ) { $sources = array_merge( $sources, $this->callback['indirect_sources'] ); } // Keep track of which source enqueued the scripts. // Note: Only the first time a script is registered/enqueued will be detected. $added_handles = array_unique( array_merge( array_diff( $wp_scripts->queue, $before_enqueued ), array_diff( array_keys( $wp_scripts->registered ), $before_registered ) ) ); foreach ( $added_handles as $added_handle ) { $handles = [ $added_handle ]; // Account for case where registered script is a placeholder for a set of scripts (e.g. jquery). if ( isset( $wp_scripts->registered[ $added_handle ] ) && empty( $wp_scripts->registered[ $added_handle ]->src ) ) { $handles = array_merge( $handles, $wp_scripts->registered[ $added_handle ]->deps ); } foreach ( $handles as $handle ) { foreach ( $sources as $source ) { AMP_Validation_Manager::$enqueued_script_sources[ $handle ][] = array_merge( $source, [ 'dependency_type' => 'script' ], compact( 'handle' ) ); } } } // Keep track of which source added inline scripts. foreach ( $wp_scripts->registered as $handle => $dependency ) { if ( empty( $dependency->extra ) ) { continue; } foreach ( [ 'data', 'before', 'after' ] as $key ) { if ( empty( $dependency->extra[ $key ] ) ) { continue; } if ( empty( $before_extras[ $handle ][ $key ] ) ) { $before = []; } elseif ( 'data' === $key ) { // Undo concatenation done by \WP_Scripts::localize(). $before = explode( "\n", $before_extras[ $handle ][ $key ] ); } else { $before = $before_extras[ $handle ][ $key ]; } if ( empty( $dependency->extra[ $key ] ) ) { $after = []; } elseif ( 'data' === $key ) { // Undo concatenation done by \WP_Scripts::localize(). $after = explode( "\n", $dependency->extra[ $key ] ); } else { $after = $dependency->extra[ $key ]; } $additions = array_diff( array_filter( $after ), array_filter( $before ) ); foreach ( $additions as $addition ) { foreach ( $sources as $source ) { AMP_Validation_Manager::$extra_script_sources[ $addition ][] = array_merge( $source, [ 'dependency_type' => 'script', 'extra_key' => $key, 'text' => $addition, ], compact( 'handle' ) ); } } } } } /** * Offset set. * * @param mixed $offset Offset. * @param mixed $value Value. */ #[\ReturnTypeWillChange] public function offsetSet( $offset, $value ) { if ( ! is_array( $this->callback['function'] ) ) { return; } if ( is_null( $offset ) ) { $this->callback['function'][] = $value; } else { $this->callback['function'][ $offset ] = $value; } } /** * Offset exists. * * @param mixed $offset Offset. * @return bool Exists. */ #[\ReturnTypeWillChange] public function offsetExists( $offset ) { if ( ! is_array( $this->callback['function'] ) ) { return false; } return isset( $this->callback['function'][ $offset ] ); } /** * Offset unset. * * @param mixed $offset Offset. */ #[\ReturnTypeWillChange] public function offsetUnset( $offset ) { if ( ! is_array( $this->callback['function'] ) ) { return; } unset( $this->callback['function'][ $offset ] ); } /** * Offset get. * * @param mixed $offset Offset. * @return mixed|null Value. */ #[\ReturnTypeWillChange] public function offsetGet( $offset ) { if ( is_array( $this->callback['function'] ) && isset( $this->callback['function'][ $offset ] ) ) { return $this->callback['function'][ $offset ]; } return null; } }