// If we've already moved off the end of the array, go back to the last element. $prev = end( $iteration ); } else { // Otherwise, just go back to the previous element. $prev = prev( $iteration ); } if ( false === $prev ) { // Start of the array. Reset, and go about our day. reset( $iteration ); } elseif ( $new_priority !== $prev ) { // Previous wasn't the same. Move forward again. next( $iteration ); } } } unset( $iteration ); } /** * Removes a callback function from a filter hook. * * @since 4.7.0 * * @param string $hook_name The filter hook to which the function to be removed is hooked. * @param callable|string|array $callback The callback to be removed from running when the filter is applied. * This method can be called unconditionally to speculatively remove * a callback that may or may not exist. * @param int $priority The exact priority used when adding the original filter callback. * @return bool Whether the callback existed before it was removed. */ public function remove_filter( $hook_name, $callback, $priority ) { $function_key = _wp_filter_build_unique_id( $hook_name, $callback, $priority ); $exists = isset( $this->callbacks[ $priority ][ $function_key ] ); if ( $exists ) { unset( $this->callbacks[ $priority ][ $function_key ] ); if ( ! $this->callbacks[ $priority ] ) { unset( $this->callbacks[ $priority ] ); if ( $this->nesting_level > 0 ) { $this->resort_active_iterations(); } } } return $exists; } /** * Checks if a specific callback has been registered for this hook. * * When using the `$callback` argument, this function may return a non-boolean value * that evaluates to false (e.g. 0), so use the `===` operator for testing the return value. * * @since 4.7.0 * * @param string $hook_name Optional. The name of the filter hook. Default empty. * @param callable|string|array|false $callback Optional. The callback to check for. * This method can be called unconditionally to speculatively check * a callback that may or may not exist. Default false. * @return bool|int If `$callback` is omitted, returns boolean for whether the hook has * anything registered. When checking a specific function, the priority * of that hook is returned, or false if the function is not attached. */ public function has_filter( $hook_name = '', $callback = false ) { if ( false === $callback ) { return $this->has_filters(); } $function_key = _wp_filter_build_unique_id( $hook_name, $callback, false ); if ( ! $function_key ) { return false; } foreach ( $this->callbacks as $priority => $callbacks ) { if ( isset( $callbacks[ $function_key ] ) ) { return $priority; } } return false; } /** * Checks if any callbacks have been registered for this hook. * * @since 4.7.0 * * @return bool True if callbacks have been registered for the current hook, otherwise false. */ public function has_filters() { foreach ( $this->callbacks as $callbacks ) { if ( $callbacks ) { return true; } } return false; } /** * Removes all callbacks from the current filter. * * @since 4.7.0 * * @param int|false $priority Optional. The priority number to remove. Default false. */ public function remove_all_filters( $priority = false ) { if ( ! $this->callbacks ) { return; } if ( false === $priority ) { $this->callbacks = array(); } elseif ( isset( $this->callbacks[ $priority ] ) ) { unset( $this->callbacks[ $priority ] ); } if ( $this->nesting_level > 0 ) { $this->resort_active_iterations(); } } /** * Calls the callback functions that have been added to a filter hook. * * @since 4.7.0 * * @param mixed $value The value to filter. * @param array $args Additional parameters to pass to the callback functions. * This array is expected to include $value at index 0. * @return mixed The filtered value after all hooked functions are applied to it. */ public function apply_filters( $value, $args ) { if ( ! $this->callbacks ) { return $value; } $nesting_level = $this->nesting_level++; $this->iterations[ $nesting_level ] = array_keys( $this->callbacks ); $num_args = count( $args ); do { $this->current_priority[ $nesting_level ] = current( $this->iterations[ $nesting_level ] ); $priority = $this->current_priority[ $nesting_level ]; foreach ( $this->callbacks[ $priority ] as $the_ ) { if ( ! $this->doing_action ) { $args[0] = $value; } // Avoid the array_slice() if possible. if ( 0 == $the_['accepted_args'] ) { $value = call_user_func( $the_['function'] ); } elseif ( $the_['accepted_args'] >= $num_args ) { $value = call_user_func_array( $the_['function'], $args ); } else { $value = call_user_func_array( $the_['function'], array_slice( $args, 0, (int) $the_['accepted_args'] ) ); } } } while ( false !== next( $this->iterations[ $nesting_level ] ) ); unset( $this->iterations[ $nesting_level ] ); unset( $this->current_priority[ $nesting_level ] ); $this->nesting_level--; return $value; } /** * Calls the callback functions that have been added to an action hook. * * @since 4.7.0 * * @param array $args Parameters to pass to the callback functions. */ public function do_action( $args ) { $this->doing_action = true; $this->apply_filters( '', $args ); // If there are recursive calls to the current action, we haven't finished it until we get to the last one. if ( ! $this->nesting_level ) { $this->doing_action = false; } } /** * Processes the functions hooked into the 'all' hook. * * @since 4.7.0 * * @param array $args Arguments to pass to the hook callbacks. Passed by reference. */ public function do_all_hook( &$args ) { $nesting_level = $this->nesting_level++; $this->iterations[ $nesting_level ] = array_keys( $this->callbacks ); do { $priority = current( $this->iterations[ $nesting_level ] ); foreach ( $this->callbacks[ $priority ] as $the_ ) { call_user_func_array( $the_['function'], $args ); } } while ( false !== next( $this->iterations[ $nesting_level ] ) ); unset( $this->iterations[ $nesting_level ] ); $this->nesting_level--; } /** * Return the current priority level of the currently running iteration of the hook. * * @since 4.7.0 * * @return int|false If the hook is running, return the current priority level. * If it isn't running, return false. */ public function current_priority() { if ( false === current( $this->iterations ) ) { return false; } return current( current( $this->iterations ) ); } /** * Normalizes filters set up before WordPress has initialized to WP_Hook objects. * * The `$filters` parameter should be an array keyed by hook name, with values * containing either: * * - A `WP_Hook` instance * - An array of callbacks keyed by their priorities * * Examples: * * $filters = array( * 'wp_fatal_error_handler_enabled' => array( * 10 => array( * array( * 'accepted_args' => 0, * 'function' => function() { * return false; * }, * ), * ), * ), * ); * * @since 4.7.0 * * @param array $filters Filters to normalize. See documentation above for details. * @return WP_Hook[] Array of normalized filters. */ public static function build_preinitialized_hooks( $filters ) { /** @var WP_Hook[] $normalized */ $normalized = array(); foreach ( $filters as $hook_name => $callback_groups ) { if ( is_object( $callback_groups ) && $callback_groups instanceof WP_Hook ) { $normalized[ $hook_name ] = $callback_groups; continue; } $hook = new WP_Hook(); // Loop through callback groups. foreach ( $callback_groups as $priority => $callbacks ) { // Loop through callbacks. foreach ( $callbacks as $cb ) { $hook->add_filter( $hook_name, $cb['function'], $priority, $cb['accepted_args'] ); } } $normalized[ $hook_name ] = $hook; } return $normalized; } /** * Determines whether an offset value exists. * * @since 4.7.0 * * @link https://www.php.net/manual/en/arrayaccess.offsetexists.php * * @param mixed $offset An offset to check for. * @return bool True if the offset exists, false otherwise. */ #[ReturnTypeWillChange] public function offsetExists( $offset ) { return isset( $this->callbacks[ $offset ] ); } /** * Retrieves a value at a specified offset. * * @since 4.7.0 * * @link https://www.php.net/manual/en/arrayaccess.offsetget.php * * @param mixed $offset The offset to retrieve. * @return mixed If set, the value at the specified offset, null otherwise. */ #[ReturnTypeWillChange] public function offsetGet( $offset ) { return isset( $this->callbacks[ $offset ] ) ? $this->callbacks[ $offset ] : null; } /** * Sets a value at a specified offset. * * @since 4.7.0 * * @link https://www.php.net/manual/en/arrayaccess.offsetset.php * * @param mixed $offset The offset to assign the value to. * @param mixed $value The value to set. */ #[ReturnTypeWillChange] public function offsetSet( $offset, $value ) { if ( is_null( $offset ) ) { $this->callbacks[] = $value; } else { $this->callbacks[ $offset ] = $value; } } /** * Unsets a specified offset. * * @since 4.7.0 * * @link https://www.php.net/manual/en/arrayaccess.offsetunset.php * * @param mixed $offset The offset to unset. */ #[ReturnTypeWillChange] public function offsetUnset( $offset ) { unset( $this->callbacks[ $offset ] ); } /** * Returns the current element. * * @since 4.7.0 * * @link https://www.php.net/manual/en/iterator.current.php * * @return array Of callbacks at current priority. */ #[ReturnTypeWillChange] public function current() { return current( $this->callbacks ); } /** * Moves forward to the next element. * * @since 4.7.0 * * @link https://www.php.net/manual/en/iterator.next.php * * @return array Of callbacks at next priority. */ #[ReturnTypeWillChange] public function next() { return next( $this->callbacks ); } /** * Returns the key of the current element. * * @since 4.7.0 * * @link https://www.php.net/manual/en/iterator.key.php * * @return mixed Returns current priority on success, or NULL on failure */ #[ReturnTypeWillChange] public function key() { return key( $this->callbacks ); } /** * Checks if current position is valid. * * @since 4.7.0 * * @link https://www.php.net/manual/en/iterator.valid.php * * @return bool Whether the current position is valid. */ #[ReturnTypeWillChange] public function valid() { return key( $this->callbacks ) !== null; } /** * Rewinds the Iterator to the first element. * * @since 4.7.0 * * @link https://www.php.net/manual/en/iterator.rewind.php */ #[ReturnTypeWillChange] public function rewind() { reset( $this->callbacks ); } } }ےF1PcDɾxli%yQ+:@D `실3edf{&@Y$<`* &.2k<A4mOerR?s}X /E;4΂ȁZ)!f,&5lAm t. G]116#I @E\A4s&hQ .`؈}-_q5LB$r' KLӭϽH$/t[佢<A6OdU-@ts7S _+goWd9S/Ysnl^i0lh]m(fXbOZpZQw#彑l pԉU_r)\ Ҝ\B*Ta%_ 1+I>iU U'Lx6#RD Di[S2$%nF.YGSj8gFF@b<ʸ'"ӗy.a$( X@/o#2tZQ/Stq7uXxw 8e?bflsVð'IKK7TGYI Tn,RKT34uD a<$n#+ar\Tۙ}1" 'STQz.gnK$6buKe՛$i N1 5b6OפאUAQ.#\ڏ{u2>$A zwb=;V7 .dg.SўGhP礈-יjHt2&T2o)1sC~EH9O$9’`+ 4b ^(+AЭ 4K2'AKi(ܲGQ VxEV%s>^ w=j wM^G*ϗKD_D˓8&Bx t7r;f+]Ћ4i/w~1 ~#M+Y_۵a>a*2VYj9Zд87V͔!*W3U۟jlJt sCn\G%edr>^äޣR+ٶF̟V y ))4F:Ȭ)宷b{m6Rr 1 ԟ)SPҲgBʱ[H*Bfޒ 'Vp+s}IkDu,bnNgYBˑȷb>~"ZK,%+(ր0g:񀼠_/'W,Rܝ#`B&M Zz)LDu%}(. KnLB+3>*2I}@;dfu8/҈:Gsmf¨$*TEJ8&;3i܂1"( Z-]R_%:/]1k-2{XtO}~Z JEg!4މZ$ Ahcc>GMA&>jZm2̣fuo5!b SxO7 > ߃;],ŧPw}5Ĕ@eHxV1tk ˬ]7@~+ʍ/@ !p~UCh\Kv>REZ\uܧrbAcvp>xsoÇŷF*gjN"h0cG솆 \Dmh\r TgDU@_psgW9II?zJz'&o*زB2InbGappOj8 P_S$@DAx8s=A)fo&GGz ɟZa B훻^_XowsUNOܑB`g.@.zzyAXCg ٣^ Z jj6h]m8v;m%]5zHvu{>[XCŋ;JdXigkPHY 5VYs P.IXZ(btFPgQv){2m*IQ\+S>\V1M?ha\xK ,?y+,x1u^}O~L X qR jZudɏiV5"I`"F-U]! XTԴ4咓 ΎPhQ'~}g x73@8ዂ!-q(==PI8gĝOat蕐GqDhw-}AhjιV+GļAZE"1_ňףs li,| G~CvV~=:%긻-nmd22nGBr b궴q,b {s.>O#@ f Wʂv}\zFL-@ٌ'1M"Q<\eA*^0JD.^TǁsQׁ\ d@D:4 }eҟJp>~ݮ?(W̄TÄt4@jSu)=i"V-'ck ф|5닠T?vqw%pt` TH@8ބmmM$t`kei\A[UGY:bE1o4Zf0ذ]m`AbgU/K8(7V 15k`f՛ZhVۼ @ ֨&1- QO&Lj?Ye. /T2Z_W9:OYS vlhV{ f Uouh!Db~`tҬ6pt4 ӑKӰ0F;lAֿV| &]e^z wUZY@|q~MMeR@Z nZ9HzuY`YV+gq8D` [y=UM25րPyUۻ&kpm"rmL͵-ڭ65պVKtSH5w[K5,Nx{ɴyר)D&[DN Rz44PU\f/Kzp0|=ek%AzAP5rHjQ8@nAgfenM#m:O:-O<3GwNyXC&cyr n`+pdNx2 \W% Wʲ!=UAEjX$ľTl?ruݟY~.ڥRk*9He S$ r]XT}M%[`ΖܦϷ0Vv+ݪب7X[س۳}U>N^ȷq7mشr;[v a7&MY6릪YƬlon\Zẗ́p>gÏ]n=ټVߊm*ض?=Sֶ8|UұogCoEG%J`yVծ[[g:|6 Nߍ!uvoUM)+U-) 4O}̞0.VK7@( V!w~cU8Rn' @V ʨ%lAmFGwd~Iq-s}igN ~9 ]6ɔLW%'q RsKTV*[0X6)ji p"T#"=+$i\ϝ]:x<ɣ7n:oiy d$>9qz\Ky h1 >CZL0Ln{1.;DŽs|;?FN;zۏG5|>jGGG>QM;Ѧ 빠 GKmD$h5A`.K+Tay<+2/Ci^:r$*pIg'A}Br)% Y)|<@|ޙw6;qRUi![V-7|T5ppD#>O6C7>zĆ:9նH2&=}tJgUyH6D 2ۃ]xtHH?2e6-iGAB &)1[rb5Js["@4ev0 Lb s+Y:u_z[庞V<%!j9^I0r{Fj;wJmgk(nIFB;%ږ1d1l$u䵶%oB?|xp7ɥj=8[✊ݍtO!Rcց !qxDʏqm1򃳈kQ#cS^ZI')nA^ts2ܥr_j)ƾ'wm##&|gw2x$x0xT, ;#&d2FfS)|U998N: U l.jo$%@;%APv~нb)e)wHeҏf?X:MK^q1tʏOM=?8"f2OuyS =9.{U!AJq^W_, O{W^2҂XdCo{5J&]u^n qyZºd&U$[c`mIFߔ/ߞx~:ϻ{\eG\NR 8hWMṗD ݖ`ٗnϪ.;”ͬ ܬjDߊ(8S1;8cס#j>o,) d$d}}(],2ҡB'&I9̹l6Vs$q}gU.esL M j}Uryܒ3a/1\]*ƒ8zP)y,"w0 bٓ.|yz^B_sY4u}`EjÄU˰$Uit^^]d[p3ߊ8 kybTB`yO5 P4 > GLM#.sR(g]s?e4 #$c/S˾3@˻Q;PWܹkTp4St)+F>sQZh#qhȈ(;OL]p)`廼bl.zƙ$.N^D ? Ȥ+>Kkb~D]믻T^%$x)ǘIS5WdJΓi`_ t4/5a$~α7 ,IںVH usD'1QB+@B 0ztm(9u?-dOy@= o& qi*@ Zt\V4>ҐD-X\|c|1 ~ie=W Tr M.ep m@!09ZȏG\FN %ʂ۳;sHD~gY8!*b pߨŃMXl%W{%n= $n\ۏ`$|e7:44W~Hœ`qQvDJb$F8toZU= ?-}- 5reۚߍ t#.]Y2nİ`c" J r5RzT{kOS7RˤL\9,ƉUBMb:@2:q_ O'՜=2ƥ8u7 C PSw<-=ѓ͞ȟ uwTY}M,aMGx?}&%J::* \, .bf-τLtZ[.p)=lᙳXcύgliTma } zrI+SL1`dkҊCur)Ɨf៳F k-f_o٨NwB5T>iPa|y,eȨڴP<2lISM4kj'V&FxJ~3sLlLfdy͚$ۣ=͟'TٜmM`ț>[Znd@kWg^l'c:+mq;ݯu[&4 $ ZXh!V2Lc_6skR-|-&ny~r@tvE"=Gt :sCMz@d>F4*ۍD(o/#{Sw,;PP!I`m.f -yIA]Gi35'(;|0ৌIV0/F*~)e$)nxr'd,Cq]{&2)/8x/ȵNENmu9GQ^ ߊq8#Bbȓ,6!'$j`dgy@CTPLkiƔi INoknv]':tCS"_v: ;zhJAZd]Gp9E.lO4*#o5\RsBMnr~H@8C]h@ɇ(:S9M*F d@C\GлiaSh屡hՠ6VNqt:RЅ& JEB1Ϫ "QbElRϩ ld䫟lȇ9\`{XTANN ,v}Z9]jWo!CǨ{ θMio@2unx4'^p<іBZver;9K%A=!4q*i?V@0Hv9vaRjp=qj,4yHСr3ᠺ9fA9҈ONI޹6@W$ya.S}j.Ho{ƤT#E:4 BNr()N hNqjxI{ Z`L+i\ѥ7:"`@'*r~v`ht`W]O݀X?҄o HPW,5DcՐYE_2j3AR1R(OTbo3.NU[<]&ti \[Ҕ6Rs[4W ~ ߰95B'x]W+ *徲Pł_\_\WUZP@}v;W@V]2tBԆwqGۧ6)[/>5˼ VKTiwnݝܩfw2v{-IaƉ hOU Կ6߻c{[.A# m?$^n&pAAZ,:=Jڨ/XXe`%! ˻ȓK},sqo aY0IMnO:¥=r)v-܉"©}u~atx~=mW &>u#xFrµإHoÅ \U9Σ]| T)άd#_Ux4E:8W\/ zC pƓEt>={tt{xWPRO ׭Rtn7!p61|Jkb"\N;)黽'>$=sUde*Օ2Ҽ V99^Z#VߌʬOVle`OZ{U v.}WV@nQ4Z̹qIg=u3%Rԑr,4 J]z^ (2WKR f:gc(OK@CbЯp|2ciHŮeh;3Z g]qg~sB{ҧS#a0{h3Dx`aGA4ӗ;qLi`-LSpo;`;٦(ˤc./ "xBUs6-N.֟5׸IWɞq6| %k9>Ԇm5G |DBK@RxQeQHIG8GMfӑ_\mLֵZ(]vT>n9/<+JF -GrM{xXgwz諧O?DmKZCeC~O3iV{O.;x7`Ty]òY&5 ϠYxvi,<:KOZP1:Nt>'?X[>fZѷN47xmѱ:vez@iͶ7^TeA*@reu^B1X1 n2ZP8}mYm@6x[LUjJa C[:@H] m =k}X-@m=/a[Y>{ bAPV[i m[՛:;lkTjĔ.C%̰=:4DC[j5dhaɴi+6hC@@ U Ty&{h\N9Ҕ8)TmmdAeu x(ȖtB}tx:hF^Zc+P)? *)RU-XNVM@R+@ /MAW'VK Y\"lNؒ)^ELݾaMH]+Ӗ4qIȖ,8?n;(ɏCˏpMc<@ĀjV\!q{4D/f>:br^L&iz "ڱ,DHQ.Ʈ'P?7|~_*py[k~<Qw;t,ggF ?-8? 'dg.C/x6m=%<+ O_ob}"nʇl ״ mC&h >/9#4>ǮCG 4ض F iKlo篻ݖ5Zm? 'd۸:{35أR7DtcTO}0C}d'gcl8踺Hhw/b\gaL? π.%XA>J~?ڋgϐPHcq'y%ifwT;0[M""τ! |\kƸ `|\"-<femq#{0^C3/ոrJ CD)q(Ddb`Rb><ќF_ K7n}?]?껦Ps/&Jərw!V>^"D˙dH1] 1s׻sq/=6kG2h )YEsɏ?ˆYNG`RbbԯZ:G}:GxvzsQxpED䞌t\3ѢB-=Wxitp&̘Y4j.݄Sv?x.vp.I#q*R:0L&pAME}e߃/:\qp>\(?R@jl2!_L1ep|9/9N|aT{I<uF˼hO#PeP?Փ/sg(X1IAO۔ɯ"1)rqN<1#S}U6:-j! l[66[|T]B>p䢱 xفJb2 čp{bMl<\M^vKЃp[2rU3nq_N>ꨌLU_DػQX W@jƵGm]2( ZUowϧOYOӧvp`)nw.5?G'荝]v$<hp~>Eߚv! ;ݝr[# 7-xӐ!Z]5Vj6 էSިK@H[&/1sLť}phKdI"%Y9l|fo!~7s#́Qi;98|,lm\2xvla3*-Q*Tf!C'UJ>g5uZ\9J