KTwpFU;+Sw;+SwЬUЬU`Rw`Rw`FU`FUGUUGTwIVRw`Rw;+Sw;+SwVU;+SwaUgp`RwSwSw`Rw`RwXBHTwpmU@U#U`Rw`Rw`FU`FUGUUGTw0|Rw`Rw;+Sw(kRwXRwRw@`Rw88RwXRwqFRwPtFRwЬU#ARwXRwRw88RwMSRwMSRwMSRw`Rw`Rw`RwRwRwRw:VRw:VRw:VRwKSRwЬU`SU7VRwUGTw|Rw`RwPUPUp`Rw7VRwUGTw|Rw`RwSwSw`Rw`RwaU/Tw7VRwUGTw|Rw`RwPUPUp`RwUGTwzsRw`RwSwSw`Rw`RwaU88RwGTw~Rw`Rw`SUGTwRw`Rw`SUUGTwPRw`Rw[RwRw8)jRwP*jRwbiRw[RwRw`SUgRwXgRwpFRwȚRwXRwRwPRwXRwRwRwXRwRwRwXRwRwRwXRwRwȐRwXRwRwRwXRwRwKTwcLTwpFRwMSRwTRwx`Rw`Rw`FU`FU`FUHTw`FUHTw؟RwڟRw`Rw`FUHTw`FUHTwbUSwSwpFRwTRw(*Sw(*Sw`Rw88RwXRwqFRwPtFRwJTw88RwMSRwMSRwMSRw`Rw`Rw`RwRwRwRwTRwJTw`SUUGTwRw`RwGTwGTw88RwGTw~Rw`RwGTwURw`RwUGTwPRw`Rw[RwRw8)jRwP*jRwzsRw[RwRw`SUgRwXgRw`Rw#ARwXRwRwȚRwXRwRwPRwXRwRwRwXRwRwRwXRwRwRwXRwRwȐRwXRwRwRwXRwRw88RwP2U`SUTRw@&RwJTwUGTwHVRw`RwGTwUSwGTw@BRw`Rw0ysRwGTw[RwRw8)jRwP*jRwciRw[RwRw88Rw88RwMSRwMSRw88RwMSRw88Rw88Rw`Rw`Rw88Rw`Rw88Rw88RwRwRw88RwRw`TRwgRwXgRwTRw#ARwXRwRwȚRwXRwRwPRwXRwRwRwXRwRwRwXRwRwRwXRwRwȐRwXRwRwRwXRwRwXRw@hNRw@UXRwRw@RwRwpQRw8RwRwRw`nRw$mRw0$RwRwRw yB'6Lrurb q_: #$)HG4(?$i2QnmwTOi*VW0 @^m"f==9rkqpk!Go$mo1bvcbK%'GWG]~hhLkFk]"ERs8B>n;sz)Rv~K>q,l[o{uoU4*kaxwfo}eHp52'fw \e:mN|~Gj; x-i .Jsp#-Cz0DCS8py'w<I ]piLe:I)lG_Xvj}=u \ "l]D?thSKs&=m1<|&ynvASZJrNks'O 6ES\|ZBK6HS%X _hHK*>,^#r9:(5ycS`80.UI RZ>JxvRFZ O{>^|V->Z y<f"pS{;cT0_PM6 oz 2FPI9Xrp_eLo^J;|wn`\FηUP?4 Uݠ2UPUpR U`0pU<F*U`U޻ @RlU U +U`p=qUЂPAU@' UpX2U@U@#`PxRlUP`U`+U` =qUPAU' Uݰ 2UUՆR UpU< UppU<F*UpU0Up QU+UqU<F*UU`Ѐ=qUPAUF*UU`p==+UPuU0U0+U@3*U@U`U`@+Up=qUPAqUp`AgUU@`qqU`PAqUP`AUp@ =U0(=qU PAqU`A)UUPu=+U`uUUpuqUAU@*U ~U~# U~0qqU~PA)UF*U!AUf*U}}@qU<F*U#]0UU`+U0}P}PqqUP}PAqU@}`AU0}`=qU }PAqU}`A)U U puqU&AU e*1U'U`||hqUP<F*UP)/Up2Up |U`+U{|xqqU|PAqU|`AU{=qU{PAqU{`A)UUpuqU-AUc*U@{.U bMUbNUzR*U1/U+UMU`NUp`z==+UPu=+U`uUU+#+U42UBUAU@*AU*BUU`y=Uy R_U PAU0lU0@U@+#+UR82UAU*Ux`R*U `:U0w;Uw=qUwPA=+U`u+U@pCUU+U`0w=U@ wQ_UPAUF*U0?UPv@Upv=qUvPA=+U`uUU@+UP vBU`vCUpv=qUuPA=+U`uUU@+U`uEUppuFUp`u=qUPuPA=+U`uU@U@@+UptHUtIUptpQlUpU.Uppt=qU`tPA=+U`uU(U/U`s=qUsPAU,*UU4U4U@+U0sPU sQqUPU.Upr =qUrPA=+U0`uU U 4U@+Up0r QU `+UrUAU*qUp0 U0 +#+URW 2U AU *U0qXU` q(==+U0PuU` nU` pp Up +Upp QU `+Upp\AU*#+U]2UAU*Uop0qEUdsUo A^tU P+U`B+UpBU <U +U0oPoXqqUPoPAqU@o`AUp0oh=U op=qUoPAqUo`A)U U Pu=+U`uU U puqUb#+U?c2UAU*Ummx!q+UP!BU !<F*U e!U`m"=qUmP"AU0 "U0 "+U0mPm#qqUPmP#AqU@m`#AU0m#=U m%=qUmP%AqUm`%A)U@ %U@ P%u=+U`&u=+Up'uUpll(qU`l(=qUlP(AUP (EUP P(2U` (<U` (uUp (Up p(uqUk(AU(*Upkk+qqUkP+AqUk`+AUpk+=U`k-=qUPkP-AqU@k`-A)U -U P-u=+U`.u=+Up/uU /U p/uqUn/U`Pj3=qU@jP3AU 3F*U p3qU 4U 4+#+URr52U5AU6*UPi 8RU  83*U u8Ui0 9U0 `9+.U@ :9Uh:==+UP:u=+U`:uqU`hp:AUP :)U@ ::@UP h` :U` @:+Ugz;Ug >U @ >..U >9Ug>==+UP>u=+U`>uqU0gp>AU >)U >:@U f >U >4U >+Uff?qqUfP?AqUf`?AUpf(?=Uf0?=qUpfP?AqU`f`?A)U ?U P?u=+U`?uU ?U p?uqU?#+U?݂@2U@AUA*u U 4F0e8Dp+UPDBU D<F*U DUdFAU>G*UpdHH==+UPHuqUpd`HAU0 HF*U0 HU d@dPIq+UPIBUP I<F*U P I1U0J0U K2U c LU @L+AU`=M*U@PcP/UQ+U c`R=qUcPRAqUc`RA)U RUb R*U@ RAUR*/UT+U`bhU=qUPbPUAqU@b`UA)U UUb U*U@ UUP@ X/U` X4(U ` X/Upa XQU  X4*UP XUp0a@ YQU@ 6Y+UhRaP pZRUP `` ZQ*U`` ZU`[=qU`P[A/U` [_U `[AqU``p[AU [F*Up [U`]U` ^RU _ ^QU * ^MU )^NU_ _R*U _-U`lU `U `+U_0bQ'U0@bU@`b+6 U^cpU^Pct+U0`cBǩUc<Up^^dqqU^PdAqU^`dAUpp^d=U`^d=qUP^PdAqU@^`dA)U`dU`PduU]pdQ_Up`dAUdUpduqUdAUf*#U@]isUi.#U]islUiUi4Ui+U\iQUiAU@i*UP\i*Ui#U \jsUj.#U[jslU jU j4Uj+U[0jQU0@jAU@j*U0[@j*U@j#U[`ksU``k.UZpkQUpk{U`k4U`k+U`ZkQUkAU@k*UZk*UkUYlU`l.qUPlUl4U`l+AUl*AU`l*UYm(U`m/UXmUm4U@m.Upm4U`m+U@PXmAU@m*U Xn(U`n/UW nU n4U`n.qUP0nU0n4U@n+AU`n*qU@pU@ @p.UVp=UVPpQ_UPPpAqUV`pAqUVppAU`paU``VppUp@p4U@@p+AUr*UuMUuN0UpvQUv{Uv+0U`wQ*UwUpUx=UUxTUTx_UPxA=+U`xuUxaUTx1Upx2Ux0Up {QlU 0{U0`{+BU}AU@}*AUu*BUuUPS=U@S@QU0S@PTUP S`_U`PA=+U`u+U@pCqURAUpUp+#U`RsU+U0RQUAU*UQ=qUQPAqUQ`A)UU*UU@PQQU@QQ*UU@QQUQQ*U UPPq=+UPuUpP =qUPPA+U P0_U0`AU@U@`uUp@P(=qU0PPA+U  PP_UP`AU`5U `p_UppA)UF*U0UPOpO0q=+UPu2UyoU _U`AqUNpA)UF*U@qUU +u U@/F`N@pFU`NpNG,UpN`NP>UpNHU`N`R>UPNH"U @NHUp0Nx=U N=qUNPAqUN`A)U U PuUM=6 UMpU0<U0Pu)U@U@`uUPUPMHUL`UpL=UL=qULPAqUL`A)UpUpPuU`LLqULLq+UPBU<U`LU +U0LPLq+UPBU0L`tU LptU<TUKUAU@*U(UPtU<U@KTU0K_U`AU U`TUJ TU J0UpJ=UJ=qUJPAqUpJ`A)U@U@PuU J=UJPQ_UPPA)U`UI`pTUpI_U`AU U0TU@IUp0I=U I=qUIPAqUI`A)UUPuUH=UHQ_UPA)UUPHTU@H_U`AU U U @0>U0GHUpG="UG@GUGPR>UPpG@HU`G`0R>U`PG@HUp@GpQ>Up0G@H_U@PA=+U`uUUFH(UPtǩU<UpFU`FHR UPF`pUPFPtEUdU F]tU`UEp==+UPuqUE`AqUEpAUUEGUpEx==+UPuqU@E`AqU0EpAUUEH"U0DH"U@DHUDR>UDHUDR>UDH(UptUpDtǩU%<AU *6 UP DpU0<U0+6 UCpEUdUC@]tU@P+U0`BǩU(<U`PC==+UPugU)UC Cq+UPBǩU*<UBCqqUCPAqUB`AUpB=UB=qUBPAqUB`A)UUPuU`BQ_U`AUUpuqU.6 UPApǩU/<AU@^*BU ^/U@+AU`*UP`.UpAQU4U@ +UP@2Up@==+UPuU݀@ RUp@QU`@ Q_U `AU0U0@{U@+U?8AU *U??8q+UPBEUd U?`H^U`p?p]Up]tU`U<U{U+U+I>`RU>Q UQ*UPAAU*~UB"U >xRU>QU U 0"U0,/UP+u U(9R=pFU==@G,U==P>UP=@HU=`R>U`p=@H"U `=@HUP==qU@=PAqU0=`A)UpU==6 U<pU<UPu)U Up>Up<@HUp`<=UP<=qU@<PAqU0<`A)UUPuU;==+UPPu)UU;TU;_U`AUU0;@HUp ;="U;GU;R>U:HU:  R>U :HUp:0Q>U0:H_UPA=+U`uU@U@@:@H(U@PtǩUX<AU*qU`U```.Up9pQUp`4U`+U@98R U09Pp+UPB+U`B+UpBU<F*U`]U>ݐ8`R U8xpU< U`8p,Up8`8(UPt+U``BǩUa<U8U@+AU*U7cU`7G==+UPGuUGlU GU  G,U` 7==+UPugUfU6gU`6=qU6PAUPUQ6`R5UP`pUP6pU+U`06=qU 6PAU' U5l2Uu U 4F5pǩUn<#+UpRo2U6 UPP5 pU<F*UpqUp//UU4U4U +U440q+UPBǩUu<U`4v/Up+U04P4@qqUP4PAqU@4`AU04P=qU 4PAqU4`A)U@U@puqUx6 UP3XpǩUy<AU *BUU@3`3hq+UPBǩUz<XU 3@,u Uy3xpǩU{<Up2QU+U22qqU2PAqU2`AU2=qU2PAqU2`A)UUpuqU~UQ02R U 2pU<F*UU1RU1RU+U+Iݰ1  RU 10( R U`12U0?U@{U@+Up1@ =qU1PA=+U`ugUU0>U4F0`H R U`0` pǩU<U MU N*UU000p q+UPBU<F*Uu U0rsR/ p+UPBEUdsU/ ^tU`U<F*UUMUNUp. =qU.PA=+U`uUU@+AU@*#U@. sU @+AU*U-0QnU0-@U@@+u UFݰ- pFU--PG,U--` >U`-PHU-p R>Up-PHU`- =U- R_UPAUU0-PHU - =qU-PAqU-`A)UU, =6 U, pU<UPu)U U>U@,PHU0,( =qU ,PAqU,`A)UU+0 =U+Q_UPA)U U>U`+PHUpP+8 ="U@+  GU0+0@ R>U0 +  HU+@X R>U@+  HU*P Q>UP*  H9U**  HUp*`Q>U`* H_U PA=+U`uUpUpP*PH(UPPtǩU<AU@*BUAU@*BUU))p qǩU<U)) qqU)PAqU)`AU) =qUp)PAqU`)`A)UUpuqU US( lUU+U/ݠ( R U( pU`( =U?݀( R_UPAUEUP2U<F*UU`0MU0@NU'@ R U@PQUP`MU`N UКR 'p aUpKAU*BU`AU*BU0?U!{U!+Up0&( !=qU &P!A=+U`!ugU!U%0 "RU">U%#>`Rw`RwMSRwTRw89WRw89WRwbUP`RwP`RwbU`RwRw8Rw(ϟRwȟRw@UrRw`PRw@n~RwpURw`pURw'UUU)UU@B`Rw`Rw`FU`FU UUGTwRw`Rw(`RwUSwQRwSwSw>U>USwQRwSwQRwSwQRw`Rw`Rw0U U#ARwXRwRwU`QRwpYRwXRwGTwRw`Rw/TwʟRwʟRwRwUGTwRw`Rw/TwXrRwrSw@LRwU0U`QRwPaRw@WRwZRwIRw8QRwjUrRwaRw3SRw3SRw`RwRw8Rw~URwP}URw ^Rw0$RwRw @U@UpnGRwbUP`RwP`RwbU`JRwEWRwRwRwdprRw8rRwЛIRw`IRw@U`Rw`Rw`FU`FU UGTw@v]Rw`RwNRwNRwprRw8rRwЛIRw`IRw`JRwEWRwrRw`Rw`Rw`FU`FU UGTwRw`RwaRwQRwQRwaRwhDRwhDRwaRwhDRw)UUaRw Rw RwprRw8rRwQRwQRwpQRw@aRw`QRwU@TRw@GSw@ELRw0Rw`Rw`Rw0U U#ARwXRwRwUPaRwpYRwPU`QRwXRwGTw}Rw`Rw/TwʟRwʟRwRwGTwzRw`Rw/Tw@GSw@LRwU0U`QRwPaRw@WRwZRw@GSw@MLRw0RwLRwIRw8QRwjUSwSw@;HRwP:HRw`Rw`Rw`FU`FU UGTwrRw`RwHTw`Rw`^Rw0vRw@U@IRw@IRwHTw)UUHTw QwXz nNh<SO V !SI'L %I:/|>2BV7l{B~(l$Ow9TD\SxPjKzto?|3z2Bewn3O~7EG)TLuU$khF:jps3YqY5yZZgk6siCmBvG}^ktPX2NRwp1;i((e-Inw^Kaq~K"t,ybfX@gJ#}BJ6v?/eC/ui_tDu+l=g;FM,c19D`=SVpP#UP2Vs(U`V/#UPp2VsUV4U@V+U 2V>U202XqU02P2(XqUPP2XQ_UPXA)U XU PXu)U0XF*U0XU118Yq=+UPYu)UPYlUP`YU`@Y+U@1Y>UP01p[QUp 1.[Up1[0"U@[,Up0[0"U[,Up0[0"U[,Up0[0"U[,UpP0[0"U@[,Up 0[0"U[,Up/[0"U[,Up/[0"U[,Up/[0"U[,AU,[*# U@/Hcq=+UPcu)UcU`c+5UpcFU.c>UP.eQaU.e(Ue/UPp.eQaU`.eUe4U e+U.Xi=qU.PiAUP-iQ_U`iAUP-iQ_UpiA=+UiuqUiUP-p-`lqUp--plq=+UPlu)UlUPlu)U lF*U "l6 U`,mp6 U`,mp[ U,Pm6UPpPm7UP,Pm7UPPm7$UP,@m8(U@PmtUP`,mQUm3(U`mtUP,mQUm3(UpmtEUmdUP+m]tUmUPp+mQUm3(UmtUP +mQUm3(UmtU*mtUm<EUPm2U m<U 0m{5UpmFU0m>#UP*@oslU@PoUP`o+5UpoFU)o>U))pq=+UPpu)U`pU``)ppUp`p+5UppFU)p>.Uq9Up(q=UP(qQ_UPqAqU(`qAUq)Uq:F*U:q?Ur{lUrU@r+U'=r#U'sslUs(Us/#Up'sslU sU s4(Us/#U'0sslU0@sU@s4U`s+5UpsFUp&s>Up&&tqU&`tQ_U`PtA)UptU%Dt2UptU&0&uqU0&uQ_UPuA)UuU%Gu2UuU%JwIU%xQU xMUxN2UyslUyUy+BUz5UpzFU$z>AU x*BUxUP$~QKU@$~GU0$ ~Q>U  $~HU$0~Q>U0$~H*US~FU##P GU##qqU#PAqU#`A)U`U`#pGU##qqU#PA)UU#pHU##qqU#PAqU#`A)UU`#pHUP#p#qqUp#PAqU`#`A)UU0#pHU #@#qqU@#PAqU0#`A)UU#pHU"#(qqU#PAqU#`A)UU"pH>Up"PH*UP\1U]Up"^2UU@"8=qU0"PA=+U`u=+UpuqU_U!!@qqU!PA)UF*Ua6 U`!Pp6 U`!`p[ U!@6U@p@7U@`!@7U@@7$U@0!08(U0PtU!`tUP pQUp3(UptEUdUP ]tUUPP QU3(UtUP QU3(UtUtU`p==+UPuUEU2U<EUP2U<U{5UpFU>#UPp slU 0U0`+5UpFU>Uxq=+UPu)U@U@PUP`+5UpFU>.U`9UpP=UP@pQ_UpPAqU`AU)U`:F*Ux?U{lUU@+U@{#U0slU(U/#UslU U 4(U/#Up slU U 4(U/#U0 slU0 @ U@ 4U`+5UpFUp>U`#UP` slU` p Up `+U DEUdU ]tU PǩU<F*U 6 UppU <U +6 U0pU <U `+5UpFU>UAU`*5UpFUp>#U` slU U `+Up=qUPAU Q_U `AU U `+UAU`*5UpFU0>#U @ slU@ P UP @+U#Up slUp U @+UpqU U `+5UpFU>U#U slU U @+U DEUdUp ]tU PǩU<F*U 6 UpU <F*U "U@ GUP Q>UP @ HU` Q>U` @ HUpp Q>Up `@ H*U@ U0=qU PAUP Q_U `AUP Q_U pA=+UuqUUpqqUPA)U F*U 6 U`@p6 U`@p[ U@ 6U p 7U  7U 7$U  8(U PtU`tUP QU 0 3(U0 ptEUdUP0@ ]tU@ UPP QUP ` 3(U` tUPp QUp 3(U tU`tU`P==+UPuU EU 2U <EU P2U <U {5UpFU >5UpFU>U>KTwRw RwXRwPXRw UYTwRw@Sw`4WRw2WRwYTw@SwSwSwPUPUSwSwP%UP%UYTwSwSw`Rwp`Rw UڶRw dRw Rw U U HTwlQw U@Sw $Rw@$RwCSRw@SRwSwSwPUPUUUUUPZTw@6zQwPѶRw URw@Sw`4WRw2WRw0RSwSwSwPUPU qRwU0RSw@URwRwRwRwSwSw8Rw 8RwRwRwSwSw8Rw 8RwRw`tRwRwRwRwRwRwRwRw0RSwJRw{FSwUUPSwPSwJRw{FSwUU@Sw@SwJRw{FSwUUPRw0MUPRwJRw{FSwUU`Rw0MU`RwJRw{FSwUURw0MURwJRw{FSwUU]Sw0MU]SwISw0RSwHTwc@Rw $Rw@$RwCSRw@SRw qRwUUUUPZTw@6zQwڶRwRw@Sw`4WRw2WRw`U0RSwSwSwPUPU0qRwU0RSw@U@RwpnSwpSwRw@Rw_RRwSRw@RwRw(Sw aRwXRRwpnSwUuRwpnSwpSwRw0MU@Rw_RRwSRw@RwȥSwSw@RwpnSwpnSwpSwpSwRwRwHTwlQw U@Sw $Rw@$RwCSRw@SRw0qRwUUUUPZTw@6zQwڶRwRw@Sw`4WRw2WRw`UwQw => array('value@ "",HTwttpSwtRING SwSwSwSw@ wfL`RwuuSw@ selSRwuuSw@typeSRwuu 'licenseType' => array('value' => wu(Sw8SwPSw@elf:|Rwu@on' `lRRwuuE_STSw 'isPaid' => array('vauSwSwSwuSwSw@ arrSRwww8Sw@hasK|Rww@('vaHTwwwxSww 'vaSw' => array('type' => selwPSw`SwSw@dateSRwxxSw@ => `|Rwx@idat(|Rwxx::TYPE_INT)), 'cacheType' => arrax0SwHSwx=> sxSwOLOAD, 'validation' => axSwSwxSwSw@ecomSRwyySw@auto|Rwy@AUTOSRwyy0Sw@> se@SRwyyHSwXSwyarrapSw' => false, 'autoload' =ySwSwySwSw@lf::SRwzzSw@ => N{Rwz@ 'au@{RwzzAD, (SwpSwSwype' => @::TY0MUz@oardSRwzzSwzSw@SwzSwSwtRING SwSwSwSwSwSwSw@!Sw@' =>`?U{{0Sw@AD, BRw{@y('tSRw{{ 'onboardingAttempt3Initial' => a{XSwpSwSw{HSwSw@tionSw}}Sw@)), `SRw}@dAt'BRw}@ fal=SRw}}HSw}n' =`Sw'type' => self::TYPE_INT}Sw0SwpSw}SwSw@loadHTwSw@n' =YTwSwSwboar(SwSwSw0Sw@ad' YTwhSw@rray 8SRwSwSw@ur_fYTwSw@auto SRwSwSwSwSwSw@sNewpBSRw@'valBRwelf:XSwSwdation' => array@pe' YTwSw@SwpSw truSwload' => self::AUTOLOAD,@lidaYTwSw@BOOLHLRw(Sw8Sw@valuYTwhSw@LOAD aRwSwSwSwPSwSwSwSwU $PY@U$`Y@U$pY@U#Y@U#Y@U#Y@U#Y@U`#Z==+UPZuUpZF*UpZU@#[U0#\-U]U`]+# U"^q=+UPP^u=+U``^u=+Upp^u=+U^u=+U^u=+U^u)U^U^>AU^*U!!`q=+UP`u)U`U `+U!aUp!!(bqU!!8bq=+UPbu)UbUPbu)UbF*U b-U eU @ e.Up He=qU PeAUp Pe==+UPeuqU `eAU0eU0`euU@eU@ e4U @e+UpXf=qUPfAUp`f==+UPfuqU`fAUPfUP`fuU`fF*U`f/UgyUgUg+Uhh==+UPhuqUp`hAqU`phAUhF*UhUiUjUkMUkN-Ul(U`l/UplUl4U`l+U mAU`m*U p31(U pUsAUk*BUkU`pu==+UPuuqU0`uAqU puAUPuF*UPuU v-UzUz.Upxz=qUpPzA=+U`zuUzUz4Uz+Up{=qUP{A=+U`{uU{F*U${U`%|UP&}U@'~AU~*2UsU+U`=U=U`=0UQ_UPAUUPuqU `AqUpAqUAU U PuU01(U0-AU@*UP.U@/~U0~"U~"U`~,U==+UPuqU`AqUpAUF*U3UP4-UU`+U61U7U8U 9U0:U;AU*UpqqUPA=+U``u=+UpuqU@A=+Uu=+Uu)U0F*U@0=-U@PUP@+AU`*U@`MU`PNU`@Up=UPR_UPA=+U`uUU{U@+U`@DqU`U.UPRaUU4U+Up=UPR_UPA=+U`uUU{U`+U`KAU`*Up=UP0R_U0PA=+U`uU@U@P{UP`+U`OAU@*Up0=UPp8R_UpPA=+U`uUU{U`+U`SAU *UpP=UPXR_UPA=+U`uUU{U@+U`WqU`U`.Upp=# UxqUPR_UPA)UUPu=+U`uU U 0{U04U@+U`]qU`PUP+U@`9U0`"U`,9U`"U`,9U `"U`,AU*6 UP p+UPBU` `tUP ptUp<Up U`+U` bAU*UP RaU U@.U q=+UPu)UU` qUP R_UPA)UUU4U@+U` iAU*Up =U TU _U PAUPP 0R_U0`AU@U@@+U` nAU@*AU */U`+AU`*BU`UuXUp`,U0>U@>@U USw0MU0+U0MU0MU8RwDLTwSwSw`Rwp`Rws TwSwSwPUPUSwSwPUPUU rQw0+UVU1UVU0+UVUU@UU^Rw_U@UU *YTwRwIU TUUrQw1U@XU^Rw_U5UjU\U`VUUSw@XUIU TUYRw@URw Rw8RwDLTwd@U@Sw U@UpnSw@UpSw@URw@U@Rw@U}Rw }Rw UѶRws Tw^RwYRwRwRw0MU0MU USwSwPUPUSwSwPUPUs TwU0VU@ PRws TwdwQwSw s@Sw(SwonHooks($key, $v@ [Rw@' ||JRwSw@WFNe@@]RwSwSwNSTASw(Swy == 'isPaid' ||@y ==\RwSwSw { Sw::getInstance()->getStor@nginbUSw@; [RwSwSw@SwXSw } SwfWAFStorageEngineMySQLiESwXSw@ }bUXSw SwSwlf::table(); i@wpdbRwSw (na autoload) values (%s, %SwSw@TE vJRw Sw@ $au`\Rw8SwHSw`SwOAD)SwSwteCachedOption($@ $va!Rw@WAF_JRwSwists('wfwSwSw $ke0SwSwIPBlocking')) { @fWAFRwxSwSwHSw@ }RwSw@y, $bUSwSwSwSw } UP!@# U"q=+UPP"uqU`"A)U`"U`">U`#>8RwDLTwҶRwwQwSw8Sww0SwalseSwCached = true, &$isDefauxSwSwf ($Swhed && self::hasCachedOppSwSwhedO(Swey); } if (!self:SwSwe; pSw $default; } $tabUP+@# U,q=+UPP,uqU`,A)U`,U`,>U`->8RwDLTwhҶRwwQwSw ::ge intherw@ * hRwSw@ed $E]RwSwnctikey, $default = @alloRwxSwSwHSwSwSw{ Sw(int) $raw; } return@SwXSwgetJSw, $default = false, $all@SwXSwet($HSwfault, $ult)ww@} YTw(Sw@, $dF]Rw@SwPSwils: SwpSw(self::get($key,@faul_UwSw@n opRw@t arYTw Sw@lse) F]Rw0 Sw@ Swr thX Swple. * * @param arrSw Swp SwSw Sw@ult>_U SwU Uws Tww@ { Rw@ Sw@Swwp Sw`4WRww(Sw2WRw ($aYTwDTww@$key0RSw Sw Sw@on($[Rw xQw 1`ZRw( xQw =wQwxQw ӏ%nRw xQw L͝+nRw( xQw i@kuQwP xQw "u hQwx xQw sW+p׈Qw xQw n4# nRw@@@ @@@@ .zfݚPnRwP xQw h͕Rw@ xQw !% ,fRw0 xQw N X;0xRw xQw 5$XxRwxQw ЩaqxRw|Qw 4=)n[ xRw|Qw Nc$0(uRwmY/E;Qw0Sw@SwXSw@e); _USw@; QwSwSw pSwSwSwSw@ig::Qw@lse,_UkSl nRwSw@, $s [RwSwSw xSwSwSwSwtablH Sw SwSwSwSw) { if (!funct SwSw@unctwnRw@'));ޟRw@ncodDSRwgzdecode', $disabled)) { return fSwSwSw@Sw Sw`Sw@ta) [Rw@//wwQw@52.teF>䶣nRwSwytes !== (chr(0x1f) . chSwSwSw@Sw pSw`SwchecSwader CRC if it turns out@s neYTwSw@atic PRwٖL 0nRw8SwPSw@true_UxSw@llowMRwSwSw hSwSwSwSwSwpSwSw } Sw?S`+YTwP3gRwmoe(Rw`Rw=ݲ-q`Rwe($header); $count = $header['couSwSw(Sw?S`+YTw P3gRwmoe(Rw``Rw=ݲ-q`RwB()-HSwSwlect val from " @lf::YTwSw@ValuLRw?S`+YTwP3gRwmoe(Rw`Rw =ݲ-q`Rw } Swe($fh, $chunk); $len@+= sYTwSw@ } /** * Returns a percentage rating for the brute force protection status. This includes both the WFSN enabled status * and the status of individual login security options. These options are available to all, so they are always * in the range [0,1]. * * @return float */Sw/** * Increments the stage finished counter and updates the stage status according to whether it's fully finished or encountered a negative status. * * @param string $stageID One of the STAGE_ constants. * @param string $status One of the wfIssues::STATUS_ constants */izedGLRw/** * Removes any admin notices matching $category that are specific to the user with ID $userID. * * @param string $category * @param null|int|string $userID `null` means the current user, `all` means all users, and an integer means a specific user * @return void */er">莀QRw#j`GTwɚmRw0SwSwSwSwhSwxSwed);pSw} return $default; Sw(Sw($keSwSwompression = falȠSwFLRwHSwXSw@k spLRwSwpSwSwSw@riveDSRw@hen FSRw$wpdSwXSwb->dbh; $useMyh9|Qw zw`Rw9|Qw h LRw9|Qw 8 E0VtRw:|Qw 3R WRw`2|Qw E\E@#Rw2|Qw brRw2|Qw U{1¸SpRw2|Qw ^wgetMaxAllowedPacketBytSw(SwPSwEtSw.SweRRw@SwSw@/* M=|akSwɚmRw#j`GTw$Sw8&Sw0'Sw@Valu2KRw@nkedHTw"Sw{ "Sw = 0; while (($chunksx"Sw"Sw nRwRwnRwS }6w0!Rw(<|Qw A(BRw=|Qw Bl!kpPgRw>|Qw ڤ9@ ^Rw>|Qw rUinRw?|Qw q4K#Rw@|Qw er%Sw return false; @ $`PRw@%SwX%Sws/UPI?UP`J{U`J+UpKDǩUK<F*UPpKUPM>U@N>0$RwRw|Qw@bh->/[69}Rw&Sw&Swx&Sw'Sw@. KeHTwH'Sw@ numYTwp'Sw'Swue c(Sw*SwySQLi error: [%2@%3$spQw'SwB=1 PRwm.zPRw_fvXgRwSR [_Twh@U'Sw(Sw@ @ PRw(Sw@mysqpQw)SwB=1 PRw m.zPRw_fvXgRw`SR [_Twh@UpQw*Sw*Sw0*Sw)Sw@*SwX)SwB=1 PRwm.zPRw _fvXgRwSR [_Tw`h@U@+Sw(+SwX+Sw*Sw`'Sw'Sw'SwUqqUPA)UPlUP`lU`pUp>Up>JRw{FSwUURw|QwUqqUPA)UPlUP`lU`pUp>Up>JRw{FSwUUpRw|QwUqqUPAqU`A)UPUP>U>JRw{FSwUUTRw(jRw|Qwber.1Sww(jRw0p mkRwhp#SwihkRwFu]wxkRw4̢*s)jRwSR [_TwTU0SwP:mRw0Sw/Swh0Swdfen`1Swus(2, 'error', sprintf( @ /*`b]Rw81SwP1Sw0Sw1Swge. p1Sw __('Error writing valuX/Swh/Sws)',1Swnce'), $key, $dbh->errnoyRw@ FSRwind_param("bss", $null, $key, $autol(2Sw@2Sw2Swp2Sw@data=Rw2Sw2Swnsla3Sw Key in key-value store.@MySQ=Rw3Sw@ge. `^Rw9mRwwH3SwX3Sw 3Swp3Sw2Sw2Sw }3Sw if (!$stmt->execute()) me, -Sw.Sw1Sw2Sw3Sw=SwBSwESw@lue =Rw84Sw mes@5Sw=Sw`9mRwitin4Sw@s] %^Rw@ $ke=Rw4Swalse4Sw } else { if ($4Sw4Sw4Sw(5Sw@dateUX5Sw@, auU5Sw@$aut^RwRwself8mRw8mRwRw) va, %%s)", $data),@y, $Rw@} @^Rw@lushfRwlf::6SwOLOAD) { self::updateX6Swp6Sw6Sw@rn tU@8mRww`6mRw{ 6mRw reRwache7SwH7Sw@ = sU7Sw@r = @^Rw@SingRw::ta7Sw" where name=%s", $chunk7Sw7Sw7SwlQww8Rw $header['count']; for@ = 0`E^Rw8Sw8SwX8Swp8Sw " w8Swe='%s'", $chunkedValueKe@$i);xRw@->qu`C^Rw@m " cRRwme='P9Sw4mRwaderRww ;Sw=Swt($key)); } pu@ sta`XRw9Sw@t('iD^Rw@statUUself(:Sw:Sw&& self::get($ke@ ЗRw@} }B^Rw@tiondRRw06mRwchec5mRwwPRww:Sw;Sw@&& $`XRw  8;Sw@f(seKTw  `;Sw  } <Sw static function getDB()@if(!U!!;Sw@B();PRw!!5mRwfunc!<Sw !;Sw(<Sw!atic<Swn haveAlertEmails(){ $@ls =^Rw""<Sw"<Sw!8<SwP<Sw!tic <Sw alertEmailBlacklist() { P;Swx;Sw;Sw9Sw9SwRww5a06ddf96Sw(6Sw5', p=Swbded101e25ebabe5643161ddP4Sw`4Sw'36e=Sw0d64cfe42ede4d9d5ce2d484@4781xRw(@d', ^Rw(@dfefdRRw((e3020>Swb', '72a09e746cb90ff2646(Rww@lQww@Emai`PRw))>Sw@ilBl@^Rw)@explUU))ils'?Sw?Swarray(); forea@$datpRw)@ail `^Rw)@mail`RRw)), $e?Sw $hash = hasSwISFRwۭYRwO`8LRwvJRwIssues')) { return self::get(*@@SwX@Swp@Sw*0@Sw@Sw@ic f`PRw++@SwSwISd]RwۭlZRwO`8GRwv HRw, } BSwturn $enabled; } publi@atic@g]Rw--ASw-BSw,ASwASwSwISrKRwۭ^RwO`8@RwvRwBSw@ig::Rw11BSwCSw1 CSw@e_da@Rw1@ i]Rw1@ datSwIS`yQRwۭMRwO`8RwvRw2(DSw@ @pa8Rw22@DSwPDSw@OCK_xRw2@ @pad]Rw2@hetheRRwSwIS {KRwۭ`\RwO`8}RwvHxRw`ESw3xESw2ESw0ESw2b; ESw!$timeout) { $timeout1CSwCSw1SwIS_Rwۭ9VRwO`8vRwvtRw", $lock_option, time())); if (!$lock_resulE 8DSwRwx,Sw`FSwSwIS_Rwۭ_RwO`8URwvHSRwGSwGSw:GSw:eLocISw { self::remove($name @lock O^Rw;;PHSw@pdatSwIS@LRwۭ_RwO`8RRwvRRwnimu ISw, '<')) { return; }@// PL^Rw==hISw@s en@^Rw==ISwISwB=1 PRwm.zPRwh@U_fvXgRwSR [_TwYTw@@JSw@g::g_Rw@@spee_Rw@@'noaB=1 PRw@m.zPRw_fvXgRwSR [_Twh@UAXKSwpKSwKSwA 0LSwlators: Support URL. */ Bu UHpUP<UP@+U>Up>U`>Rw(RwPRwQRw|QwMSwFLSw8MSw@ webpSwB=1 PRwm.zPRwh@U_fvXgRwSR [_Tw8NSw@ade 0MUGGNSwPNSwhNSwGMSwNSw@ortCkRwHTUHHNSw@ xRwHHNSwOSwH OSwH8OSw@s = TUHHXOSw@; RwHHpOSwOSw@ins-0MUHHHOSwOSwOSwHNSwOSwKU`+U`AU *Uq)Up UppU< U pUPtU<U`U`>AU@*QUP1kU>U>USwRw&Rw)Rw8)Rw`RwRw( RwP Rw@Rw@U#USw|QwxRwηUPa?UPb9UP`b"U`@b,9UP`b"U`b,9UPp`b"U`b,9UP@`b"U`b,9UP`b"U`@b,AU@b*Uh>Uj>Uk>aRw PRwPRwXgRw [_Tw@U|QwUU0Rw?%RwGTwlQw# U@ qU <F*UP UP }U` ~*Up U q=+UpP u)U F*U` AU@ *BU UP 2UUP2UUP>U>nRwnRwJRw{FSwUURwIRw|QwU@Pp@?UP`q{(U``q/# Uqq=+UPPqu)UpqlUpqU`q4U`q+U`(rqqUPrA)Ur' Ur2UrAU`r*4 U8u2UPuUw>BRw(BRw`RwJRw{FSwUU!ZRw`RwU[Sw@ploau U5FpUP<nUP`U`@+Up>U`qqUPAu UՆp p)UpUp`uqU0pAqU AqUU>!ZRwgRw PRw PRwJRw{FSwg%Rwg%RwPgGRwP7mRw 7mRw9Tw|QwДRwPRwRw]TwRwSwU`PRUPPUP@`0"U`@,UP`0"U`,UP`0"U`,UP`0"U`,UP`0"U`@,AU*U0p R5UP FUp >5UP FU >U >`RwRw PRwPRw@UXgRw [_Tw`Rw@U|QwUt~QPBRUP`B{U``B.UݰpBRUpBQUP0B=UB+U`B/UBU`B4U`B+u UP6F8CpqUCUD>UF>UG> LRw LRwRwaUpkRw`kRw|QwRw@NSRw@U|Qw`Rw`KTwU qqU PA)UPnUP`U`@+U>UqqUPA)UplUpU.# U` q)UU4U>U>JRw{FSwUU`^RwRwJRw{FSwUUp^Rw84WRw@Rw|Qw ^RwηUP?UP@9UP`"U`,9UP`"U`,AU*U?PpRUp>U? RU>U0DUPtǩU<UlU>RwXSwQwxJRw$Rw!U#U!Rw.U`RwURwSw[RwRw8)jRwMU5E UP5(UPP5tu U0F5pU`5<U`5+= U`p(5cUp5AU`5*= U005cU5(U`5tU5U6>XQwXQwSw`#iRw@!AQw@!AQwSwSwXGSw Sw0SwtSwFQwZRQwZRQw(HTw([RQw`[RQwKU TwηUP??ηU`??ηUp??-UP@lU@U@+u UApUA<F*UA?UB{U B+6 Up@CpEUCdU C]tUPCEUCdUC]tU`CǩUC<UF>@XQw@XQwP UP U(TwUFQwTUηUP??u U`WQ@p)U`@U`@@+MU`AEUpPAtU``AtUPpAtUAMU BE+UPPBBU`BtUBUD>[NRw[NRw &ZQwX&ZQwALTwKTw&ZQw&ZQw'ZQw)fRwGUFQwSw.jRw/jRwGTw@EQw`Rw#ZQwUPqUPP< UPPpU`P<U`P+U` QqUPQtUp`QtUpQ< Up@0QpUQ<yUQUR>XqRwqRwg%Rwg%RwYQwYQw`SwSwUUp'ZQw@UESwESwFQw`HRwvSw@ckedTRw case 'scan_include_extra': { u UXQp UP_UPPA)U`U`@+MUp E~UplUpU`+MU (EUu U3F0pqUPAqUU>XQwXQw@JQwXQwXQwHTwh)ZQw)ZQw^RwXQwXQwFQwhySw ySwySwUserzSw{Swforeach ($dirtyWU`R UPpu UaRP(pU<EUP2U<F*UPUP }U`~*Upu UaRp8p+UpPB+U``BU<F*U`AU *BUUP>U>aRwLTwLTwgRwgRwMGRwMGRwFQwkQwUP@?UP`{U`+MUE~UpF*UPp>#UPlUU@+U@>6 UP0p U0 (UPtU<U>U>YQw8YQwYTw`7LTw8LTwTwTwpcRwFQwe($key); }UUUPUq)U UpU< U pU<U4lU*U`U`@.U0P0q)U U0@pU< UPpUPtU <lU 0U04*UP AU@*QU`pakU`hqqUPA)UPUP@`.UP`4U`@+U>U>U>Rw&Rw)Rw8)Rw`RwRwVU0\URw&Rw)Rw8)Rw`RwRw( RwP Rw Rw@U#UJRw{FSwUURw`GTwSw|Qw`TRw`TRw?%RwηUP?UP `9UP`"U`@,9UP`"U`,9UP`"U``,9UP`"U`,9UPP`"U` ,AU*U=qUPAqU`A)UpUp>U=qUPAqUp`A)UU>U =qUPAqU`A)UU>U=qUPAqU`A)UU>U@>aRw PRwPRwXgRw [_Tw@UGTwgQw`RwGTwrQw`RwGTwRw`RwGTwྶRw`Rw|Qw`zYRwhSw@leanP!Rw@ces'@SwSw arrSw } $cleaned['Up`=# UPqUP<UPPuFU `.G9U `H9U `H9U `H9U `H9U `H9U `H9U `HU0qqU0PAqU `A)UpUp`HU(qqUPAqU`A)UU`H9U`H_U``AUU>UP>UnRwnRwh"mRw^RwhrRwrRw8^lRwp^lRw^Rw@^RwJRw{FSwUUdRw0MUdRwJRw{FSwUU0^Rw0MU0^RwRw|QwSwSw(SwSwSw8SwSwSwU8qqUP8A)U8lU8*UP8# UP9q)U9F*U`9u U :pU:<F*Up:U;# U0<q)U@<F*U@ <Up`=MU`p=N*Up =UP>.Up@>==+UP>u=+U`>uU>U>{U>4U@>+AU?*/U`B+0U`CQ1(UCAU@=*BU`=u UpHFp+UPFBUF<UF>UG>JRw{FSwUURwpkRwnRw(ϟRwȟRwPkRw`nRwUxRwضRw|Qw@reac`rJRw@ => {JRw@ $rhfRw if u URJ݀pUP<UP`UPP`0"U`@,UP `0"U`,UP`0"U`,UP`0"U`,UP`0"U`@,AU*# U@q)Up5UPFUp># U q)U5UPFU># U0q)U5UPFU># U @q)U5UPFU># UPq)U5UPFU>5UPFU@>!ZRwgRw0Rw PRwPRw@UXgRw [_Tw kRwnRw#Rw#Rw$Rw$RwPrRwrRw0#Rw$Rw|QwSw SwSwteli0Swall']) ? $whitelX#UPM U!yQO2UO U~Qpp"PU7Up`P2UPP U|~Q@:QU7U0Q2U Q U}~QRRU7UR2UR U~~QjSU7US2US U~QTU7U T2UT UȀ~QUU7Up U2U`U U~QP0VU7U0@V2U0V U X2UXu U7FYpqUYUZ>KTw LRw@U LRwRw LRwHRw LRwHtRw LRwRw LRw8Rw LRwخRw LRwPRw WRwpkRw`kRw|Qw@LRwhSw@ray_@`RwSwSw@ wfU RwSwSw@$whi@yKRwηUP?U`@,U`pUp@+U>u U~QpqU U5Fp[gUPsU+ UP~Q (X1UP2U` U@2Uu Up3FXp)UlUU.Uxd|QPhRlUU4U +U`=U zU 0GU0H_U0PAgU  U@2U0U >kRwkRw LRw LRw WRw`kRwkRw0VtRw"UcVRw0VtRw|QwSwSw@arraP RwSw0Sw@ the`Rw@nabl@SwxSw `SwSwHSwSwSwSwe nuЩSwUDU(UPtǩU<F*UP6 UP pU<F*U`UpU`MU N*U  Upp==+UPuqU@`AU@&U@PUP+U` =Up(==+UPuqU`AU`U`PuUpF*Up# U0q+UPBU<1Up2UAU`*BU0+Up|Up>+U|U>@UU0U`U@U>U_Rw6UIUȊdRwࡦRw|Qw#UUGTwjRw`RwUUSwa { * An array of name-value pairs of additional user data items. Default empty array. * * @type string $name The user-facing name of an item name-value pair,e.g. 'IP Address'. * @type string $value The user-facing value of an item data pair, e.g. '50.60.70.0'. * } * @param WP_User $user The user whose data is being exported. * @param string[] $reserved_names An array of reserved names. Any item in `$additional_user_data` * that uses one of these for its `name` will not be included in the export. */ $_extra_data = apply_filters( 'wp_privacy_additional_user_profile_data', array(), $user, $reserved_names ); if ( is_array( $_extra_data ) && ! empty( $_extra_data ) ) { // Remove items that use reserved names. $extra_data = array_filter( $_extra_data, static function ( $item ) use ( $reserved_names ) { return ! in_array( $item['name'], $reserved_names, true ); } ); if ( count( $extra_data ) !== count( $_extra_data ) ) { _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: wp_privacy_additional_user_profile_data */ __( 'Filter %s returned items with reserved names.' ), 'wp_privacy_additional_user_profile_data' ), '5.4.0' ); } if ( ! empty( $extra_data ) ) { $user_data_to_export = array_merge( $user_data_to_export, $extra_data ); } } $data_to_export[] = array( 'group_id' => 'user', 'group_label' => __( 'User' ), 'group_description' => __( 'User’s profile data.' ), 'item_id' => "user-{$user->ID}", 'data' => $user_data_to_export, ); if ( isset( $user_meta['community-events-location'] ) ) { $location = maybe_unserialize( $user_meta['community-events-location'][0] ); $location_props_to_export = array( 'description' => __( 'City' ), 'country' => __( 'Country' ), 'latitude' => __( 'Latitude' ), 'longitude' => __( 'Longitude' ), 'ip' => __( 'IP' ), ); $location_data_to_export = array(); foreach ( $location_props_to_export as $key => $name ) { if ( ! empty( $location[ $key ] ) ) { $location_data_to_export[] = array( 'name' => $name, 'value' => $location[ $key ], ); } } $data_to_export[] = array( 'group_id' => 'community-events-location', 'group_label' => __( 'Community Events Location' ), 'group_description' => __( 'User’s location data used for the Community Events in the WordPress Events and News dashboard widget.' ), 'item_id' => "community-events-location-{$user->ID}", 'data' => $location_data_to_export, ); } if ( isset( $user_meta['session_tokens'] ) ) { $session_tokens = maybe_unserialize( $user_meta['session_tokens'][0] ); $session_tokens_props_to_export = array( 'expiration' => __( 'Expiration' ), 'ip' => __( 'IP' ), 'ua' => __( 'User Agent' ), 'login' => __( 'Last Login' ), ); foreach ( $session_tokens as $token_key => $session_token ) { $session_tokens_data_to_export = array(); foreach ( $session_tokens_props_to_export as $key => $name ) { if ( ! empty( $session_token[ $key ] ) ) { $value = $session_token[ $key ]; if ( in_array( $key, array( 'expiration', 'login' ), true ) ) { $value = date_i18n( 'F d, Y H:i A', $value ); } $session_tokens_data_to_export[] = array( 'name' => $name, 'value' => $value, ); } } $data_to_export[] = array( 'group_id' => 'session-tokens', 'group_label' => __( 'Session Tokens' ), 'group_description' => __( 'User’s Session Tokens data.' ), 'item_id' => "session-tokens-{$user->ID}-{$token_key}", 'data' => $session_tokens_data_to_export, ); } } return array( 'data' => $data_to_export, 'done' => true, ); } /** * Updates log when privacy request is confirmed. * * @since 4.9.6 * @access private * * @param int $request_id ID of the request. */ function _wp_privacy_account_request_confirmed( $request_id ) { $request = wp_get_user_request( $request_id ); if ( ! $request ) { return; } if ( ! in_array( $request->status, array( 'request-pending', 'request-failed' ), true ) ) { return; } update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', time() ); wp_update_post( array( 'ID' => $request_id, 'post_status' => 'request-confirmed', ) ); } /** * Notifies the site administrator via email when a request is confirmed. * * Without this, the admin would have to manually check the site to see if any * action was needed on their part yet. * * @since 4.9.6 * * @param int $request_id The ID of the request. */ function _wp_privacy_send_request_confirmation_notification( $request_id ) { $request = wp_get_user_request( $request_id ); if ( ! ( $request instanceof WP_User_Request ) || 'request-confirmed' !== $request->status ) { return; } $already_notified = (bool) get_post_meta( $request_id, '_wp_admin_notified', true ); if ( $already_notified ) { return; } if ( 'export_personal_data' === $request->action_name ) { $manage_url = admin_url( 'export-personal-data.php' ); } elseif ( 'remove_personal_data' === $request->action_name ) { $manage_url = admin_url( 'erase-personal-data.php' ); } $action_description = wp_user_request_action_description( $request->action_name ); /** * Filters the recipient of the data request confirmation notification. * * In a Multisite environment, this will default to the email address of the * network admin because, by default, single site admins do not have the * capabilities required to process requests. Some networks may wish to * delegate those capabilities to a single-site admin, or a dedicated person * responsible for managing privacy requests. * * @since 4.9.6 * * @param string $admin_email The email address of the notification recipient. * @param WP_User_Request $request The request that is initiating the notification. */ $admin_email = apply_filters( 'user_request_confirmed_email_to', get_site_option( 'admin_email' ), $request ); $email_data = array( 'request' => $request, 'user_email' => $request->email, 'description' => $action_description, 'manage_url' => $manage_url, 'sitename' => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), 'siteurl' => home_url(), 'admin_email' => $admin_email, ); $subject = sprintf( /* translators: Privacy data request confirmed notification email subject. 1: Site title, 2: Name of the confirmed action. */ __( '[%1$s] Action Confirmed: %2$s' ), $email_data['sitename'], $action_description ); /** * Filters the subject of the user request confirmation email. * * @since 4.9.8 * * @param string $subject The email subject. * @param string $sitename The name of the site. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $user_email The email address confirming a request * @type string $description Description of the action being performed so the user knows what the email is for. * @type string $manage_url The link to click manage privacy requests of this type. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * @type string $admin_email The administrator email receiving the mail. * } */ $subject = apply_filters( 'user_request_confirmed_email_subject', $subject, $email_data['sitename'], $email_data ); /* translators: Do not translate SITENAME, USER_EMAIL, DESCRIPTION, MANAGE_URL, SITEURL; those are placeholders. */ $content = __( 'Howdy, A user data privacy request has been confirmed on ###SITENAME###: User: ###USER_EMAIL### Request: ###DESCRIPTION### You can view and manage these data privacy requests here: ###MANAGE_URL### Regards, All at ###SITENAME### ###SITEURL###' ); /** * Filters the body of the user request confirmation email. * * The email is sent to an administrator when a user request is confirmed. * * The following strings have a special meaning and will get replaced dynamically: * * ###SITENAME### The name of the site. * ###USER_EMAIL### The user email for the request. * ###DESCRIPTION### Description of the action being performed so the user knows what the email is for. * ###MANAGE_URL### The URL to manage requests. * ###SITEURL### The URL to the site. * * @since 4.9.6 * @deprecated 5.8.0 Use {@see 'user_request_confirmed_email_content'} instead. * For user erasure fulfillment email content * use {@see 'user_erasure_fulfillment_email_content'} instead. * * @param string $content The email content. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $user_email The email address confirming a request * @type string $description Description of the action being performed * so the user knows what the email is for. * @type string $manage_url The link to click manage privacy requests of this type. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * @type string $admin_email The administrator email receiving the mail. * } */ $content = apply_filters_deprecated( 'user_confirmed_action_email_content', array( $content, $email_data ), '5.8.0', sprintf( /* translators: 1 & 2: Deprecation replacement options. */ __( '%1$s or %2$s' ), 'user_request_confirmed_email_content', 'user_erasure_fulfillment_email_content' ) ); /** * Filters the body of the user request confirmation email. * * The email is sent to an administrator when a user request is confirmed. * The following strings have a special meaning and will get replaced dynamically: * * ###SITENAME### The name of the site. * ###USER_EMAIL### The user email for the request. * ###DESCRIPTION### Description of the action being performed so the user knows what the email is for. * ###MANAGE_URL### The URL to manage requests. * ###SITEURL### The URL to the site. * * @since 5.8.0 * * @param string $content The email content. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $user_email The email address confirming a request * @type string $description Description of the action being performed so the user knows what the email is for. * @type string $manage_url The link to click manage privacy requests of this type. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * @type string $admin_email The administrator email receiving the mail. * } */ $content = apply_filters( 'user_request_confirmed_email_content', $content, $email_data ); $content = str_replace( '###SITENAME###', $email_data['sitename'], $content ); $content = str_replace( '###USER_EMAIL###', $email_data['user_email'], $content ); $content = str_replace( '###DESCRIPTION###', $email_data['description'], $content ); $content = str_replace( '###MANAGE_URL###', sanitize_url( $email_data['manage_url'] ), $content ); $content = str_replace( '###SITEURL###', sanitize_url( $email_data['siteurl'] ), $content ); $headers = ''; /** * Filters the headers of the user request confirmation email. * * @since 5.4.0 * * @param string|array $headers The email headers. * @param string $subject The email subject. * @param string $content The email content. * @param int $request_id The request ID. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $user_email The email address confirming a request * @type string $description Description of the action being performed so the user knows what the email is for. * @type string $manage_url The link to click manage privacy requests of this type. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * @type string $admin_email The administrator email receiving the mail. * } */ $headers = apply_filters( 'user_request_confirmed_email_headers', $headers, $subject, $content, $request_id, $email_data ); $email_sent = wp_mail( $email_data['admin_email'], $subject, $content, $headers ); if ( $email_sent ) { update_post_meta( $request_id, '_wp_admin_notified', true ); } } /** * Notifies the user when their erasure request is fulfilled. * * Without this, the user would never know if their data was actually erased. * * @since 4.9.6 * * @param int $request_id The privacy request post ID associated with this request. */ function _wp_privacy_send_erasure_fulfillment_notification( $request_id ) { $request = wp_get_user_request( $request_id ); if ( ! ( $request instanceof WP_User_Request ) || 'request-completed' !== $request->status ) { return; } $already_notified = (bool) get_post_meta( $request_id, '_wp_user_notified', true ); if ( $already_notified ) { return; } // Localize message content for user; fallback to site default for visitors. if ( ! empty( $request->user_id ) ) { $switched_locale = switch_to_user_locale( $request->user_id ); } else { $switched_locale = switch_to_locale( get_locale() ); } /** * Filters the recipient of the data erasure fulfillment notification. * * @since 4.9.6 * * @param string $user_email The email address of the notification recipient. * @param WP_User_Request $request The request that is initiating the notification. */ $user_email = apply_filters( 'user_erasure_fulfillment_email_to', $request->email, $request ); $email_data = array( 'request' => $request, 'message_recipient' => $user_email, 'privacy_policy_url' => get_privacy_policy_url(), 'sitename' => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), 'siteurl' => home_url(), ); $subject = sprintf( /* translators: Erasure request fulfilled notification email subject. %s: Site title. */ __( '[%s] Erasure Request Fulfilled' ), $email_data['sitename'] ); /** * Filters the subject of the email sent when an erasure request is completed. * * @since 4.9.8 * @deprecated 5.8.0 Use {@see 'user_erasure_fulfillment_email_subject'} instead. * * @param string $subject The email subject. * @param string $sitename The name of the site. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $message_recipient The address that the email will be sent to. Defaults * to the value of `$request->email`, but can be changed * by the `user_erasure_fulfillment_email_to` filter. * @type string $privacy_policy_url Privacy policy URL. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $subject = apply_filters_deprecated( 'user_erasure_complete_email_subject', array( $subject, $email_data['sitename'], $email_data ), '5.8.0', 'user_erasure_fulfillment_email_subject' ); /** * Filters the subject of the email sent when an erasure request is completed. * * @since 5.8.0 * * @param string $subject The email subject. * @param string $sitename The name of the site. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $message_recipient The address that the email will be sent to. Defaults * to the value of `$request->email`, but can be changed * by the `user_erasure_fulfillment_email_to` filter. * @type string $privacy_policy_url Privacy policy URL. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $subject = apply_filters( 'user_erasure_fulfillment_email_subject', $subject, $email_data['sitename'], $email_data ); /* translators: Do not translate SITENAME, SITEURL; those are placeholders. */ $content = __( 'Howdy, Your request to erase your personal data on ###SITENAME### has been completed. If you have any follow-up questions or concerns, please contact the site administrator. Regards, All at ###SITENAME### ###SITEURL###' ); if ( ! empty( $email_data['privacy_policy_url'] ) ) { /* translators: Do not translate SITENAME, SITEURL, PRIVACY_POLICY_URL; those are placeholders. */ $content = __( 'Howdy, Your request to erase your personal data on ###SITENAME### has been completed. If you have any follow-up questions or concerns, please contact the site administrator. For more information, you can also read our privacy policy: ###PRIVACY_POLICY_URL### Regards, All at ###SITENAME### ###SITEURL###' ); } /** * Filters the body of the data erasure fulfillment notification. * * The email is sent to a user when their data erasure request is fulfilled * by an administrator. * * The following strings have a special meaning and will get replaced dynamically: * * ###SITENAME### The name of the site. * ###PRIVACY_POLICY_URL### Privacy policy page URL. * ###SITEURL### The URL to the site. * * @since 4.9.6 * @deprecated 5.8.0 Use {@see 'user_erasure_fulfillment_email_content'} instead. * For user request confirmation email content * use {@see 'user_request_confirmed_email_content'} instead. * * @param string $content The email content. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $message_recipient The address that the email will be sent to. Defaults * to the value of `$request->email`, but can be changed * by the `user_erasure_fulfillment_email_to` filter. * @type string $privacy_policy_url Privacy policy URL. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $content = apply_filters_deprecated( 'user_confirmed_action_email_content', array( $content, $email_data ), '5.8.0', sprintf( /* translators: 1 & 2: Deprecation replacement options. */ __( '%1$s or %2$s' ), 'user_erasure_fulfillment_email_content', 'user_request_confirmed_email_content' ) ); /** * Filters the body of the data erasure fulfillment notification. * * The email is sent to a user when their data erasure request is fulfilled * by an administrator. * * The following strings have a special meaning and will get replaced dynamically: * * ###SITENAME### The name of the site. * ###PRIVACY_POLICY_URL### Privacy policy page URL. * ###SITEURL### The URL to the site. * * @since 5.8.0 * * @param string $content The email content. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $message_recipient The address that the email will be sent to. Defaults * to the value of `$request->email`, but can be changed * by the `user_erasure_fulfillment_email_to` filter. * @type string $privacy_policy_url Privacy policy URL. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $content = apply_filters( 'user_erasure_fulfillment_email_content', $content, $email_data ); $content = str_replace( '###SITENAME###', $email_data['sitename'], $content ); $content = str_replace( '###PRIVACY_POLICY_URL###', $email_data['privacy_policy_url'], $content ); $content = str_replace( '###SITEURL###', sanitize_url( $email_data['siteurl'] ), $content ); $headers = ''; /** * Filters the headers of the data erasure fulfillment notification. * * @since 5.4.0 * @deprecated 5.8.0 Use {@see 'user_erasure_fulfillment_email_headers'} instead. * * @param string|array $headers The email headers. * @param string $subject The email subject. * @param string $content The email content. * @param int $request_id The request ID. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $message_recipient The address that the email will be sent to. Defaults * to the value of `$request->email`, but can be changed * by the `user_erasure_fulfillment_email_to` filter. * @type string $privacy_policy_url Privacy policy URL. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $headers = apply_filters_deprecated( 'user_erasure_complete_email_headers', array( $headers, $subject, $content, $request_id, $email_data ), '5.8.0', 'user_erasure_fulfillment_email_headers' ); /** * Filters the headers of the data erasure fulfillment notification. * * @since 5.8.0 * * @param string|array $headers The email headers. * @param string $subject The email subject. * @param string $content The email content. * @param int $request_id The request ID. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $message_recipient The address that the email will be sent to. Defaults * to the value of `$request->email`, but can be changed * by the `user_erasure_fulfillment_email_to` filter. * @type string $privacy_policy_url Privacy policy URL. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $headers = apply_filters( 'user_erasure_fulfillment_email_headers', $headers, $subject, $content, $request_id, $email_data ); $email_sent = wp_mail( $user_email, $subject, $content, $headers ); if ( $switched_locale ) { restore_previous_locale(); } if ( $email_sent ) { update_post_meta( $request_id, '_wp_user_notified', true ); } } /** * Returns request confirmation message HTML. * * @since 4.9.6 * @access private * * @param int $request_id The request ID being confirmed. * @return string The confirmation message. */ function _wp_privacy_account_request_confirmed_message( $request_id ) { $request = wp_get_user_request( $request_id ); $message = '

' . __( 'Action has been confirmed.' ) . '

'; $message .= '

' . __( 'The site administrator has been notified and will fulfill your request as soon as possible.' ) . '

'; if ( $request && in_array( $request->action_name, _wp_privacy_action_request_types(), true ) ) { if ( 'export_personal_data' === $request->action_name ) { $message = '

' . __( 'Thanks for confirming your export request.' ) . '

'; $message .= '

' . __( 'The site administrator has been notified. You will receive a link to download your export via email when they fulfill your request.' ) . '

'; } elseif ( 'remove_personal_data' === $request->action_name ) { $message = '

' . __( 'Thanks for confirming your erasure request.' ) . '

'; $message .= '

' . __( 'The site administrator has been notified. You will receive an email confirmation when they erase your data.' ) . '

'; } } /** * Filters the message displayed to a user when they confirm a data request. * * @since 4.9.6 * * @param string $message The message to the user. * @param int $request_id The ID of the request being confirmed. */ $message = apply_filters( 'user_request_action_confirmed_message', $message, $request_id ); return $message; } /** * Creates and logs a user request to perform a specific action. * * Requests are stored inside a post type named `user_request` since they can apply to both * users on the site, or guests without a user account. * * @since 4.9.6 * @since 5.7.0 Added the `$status` parameter. * * @param string $email_address User email address. This can be the address of a registered * or non-registered user. * @param string $action_name Name of the action that is being confirmed. Required. * @param array $request_data Misc data you want to send with the verification request and pass * to the actions once the request is confirmed. * @param string $status Optional request status (pending or confirmed). Default 'pending'. * @return int|WP_Error Returns the request ID if successful, or a WP_Error object on failure. */ function wp_create_user_request( $email_address = '', $action_name = '', $request_data = array(), $status = 'pending' ) { $email_address = sanitize_email( $email_address ); $action_name = sanitize_key( $action_name ); if ( ! is_email( $email_address ) ) { return new WP_Error( 'invalid_email', __( 'Invalid email address.' ) ); } if ( ! in_array( $action_name, _wp_privacy_action_request_types(), true ) ) { return new WP_Error( 'invalid_action', __( 'Invalid action name.' ) ); } if ( ! in_array( $status, array( 'pending', 'confirmed' ), true ) ) { return new WP_Error( 'invalid_status', __( 'Invalid request status.' ) ); } $user = get_user_by( 'email', $email_address ); $user_id = $user && ! is_wp_error( $user ) ? $user->ID : 0; // Check for duplicates. $requests_query = new WP_Query( array( 'post_type' => 'user_request', 'post_name__in' => array( $action_name ), // Action name stored in post_name column. 'title' => $email_address, // Email address stored in post_title column. 'post_status' => array( 'request-pending', 'request-confirmed', ), 'fields' => 'ids', ) ); if ( $requests_query->found_posts ) { return new WP_Error( 'duplicate_request', __( 'An incomplete personal data request for this email address already exists.' ) ); } $request_id = wp_insert_post( array( 'post_author' => $user_id, 'post_name' => $action_name, 'post_title' => $email_address, 'post_content' => wp_json_encode( $request_data ), 'post_status' => 'request-' . $status, 'post_type' => 'user_request', 'post_date' => current_time( 'mysql', false ), 'post_date_gmt' => current_time( 'mysql', true ), ), true ); return $request_id; } /** * Gets action description from the name and return a string. * * @since 4.9.6 * * @param string $action_name Action name of the request. * @return string Human readable action name. */ function wp_user_request_action_description( $action_name ) { switch ( $action_name ) { case 'export_personal_data': $description = __( 'Export Personal Data' ); break; case 'remove_personal_data': $description = __( 'Erase Personal Data' ); break; default: /* translators: %s: Action name. */ $description = sprintf( __( 'Confirm the "%s" action' ), $action_name ); break; } /** * Filters the user action description. * * @since 4.9.6 * * @param string $description The default description. * @param string $action_name The name of the request. */ return apply_filters( 'user_request_action_description', $description, $action_name ); } /** * Send a confirmation request email to confirm an action. * * If the request is not already pending, it will be updated. * * @since 4.9.6 * * @param string $request_id ID of the request created via wp_create_user_request(). * @return true|WP_Error True on success, `WP_Error` on failure. */ function wp_send_user_request( $request_id ) { $request_id = absint( $request_id ); $request = wp_get_user_request( $request_id ); if ( ! $request ) { return new WP_Error( 'invalid_request', __( 'Invalid personal data request.' ) ); } // Localize message content for user; fallback to site default for visitors. if ( ! empty( $request->user_id ) ) { $switched_locale = switch_to_user_locale( $request->user_id ); } else { $switched_locale = switch_to_locale( get_locale() ); } $email_data = array( 'request' => $request, 'email' => $request->email, 'description' => wp_user_request_action_description( $request->action_name ), 'confirm_url' => add_query_arg( array( 'action' => 'confirmaction', 'request_id' => $request_id, 'confirm_key' => wp_generate_user_request_key( $request_id ), ), wp_login_url() ), 'sitename' => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), 'siteurl' => home_url(), ); /* translators: Confirm privacy data request notification email subject. 1: Site title, 2: Name of the action. */ $subject = sprintf( __( '[%1$s] Confirm Action: %2$s' ), $email_data['sitename'], $email_data['description'] ); /** * Filters the subject of the email sent when an account action is attempted. * * @since 4.9.6 * * @param string $subject The email subject. * @param string $sitename The name of the site. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $email The email address this is being sent to. * @type string $description Description of the action being performed so the user knows what the email is for. * @type string $confirm_url The link to click on to confirm the account action. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $subject = apply_filters( 'user_request_action_email_subject', $subject, $email_data['sitename'], $email_data ); /* translators: Do not translate DESCRIPTION, CONFIRM_URL, SITENAME, SITEURL: those are placeholders. */ $content = __( 'Howdy, A request has been made to perform the following action on your account: ###DESCRIPTION### To confirm this, please click on the following link: ###CONFIRM_URL### You can safely ignore and delete this email if you do not want to take this action. Regards, All at ###SITENAME### ###SITEURL###' ); /** * Filters the text of the email sent when an account action is attempted. * * The following strings have a special meaning and will get replaced dynamically: * * ###DESCRIPTION### Description of the action being performed so the user knows what the email is for. * ###CONFIRM_URL### The link to click on to confirm the account action. * ###SITENAME### The name of the site. * ###SITEURL### The URL to the site. * * @since 4.9.6 * * @param string $content Text in the email. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $email The email address this is being sent to. * @type string $description Description of the action being performed so the user knows what the email is for. * @type string $confirm_url The link to click on to confirm the account action. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $content = apply_filters( 'user_request_action_email_content', $content, $email_data ); $content = str_replace( '###DESCRIPTION###', $email_data['description'], $content ); $content = str_replace( '###CONFIRM_URL###', sanitize_url( $email_data['confirm_url'] ), $content ); $content = str_replace( '###EMAIL###', $email_data['email'], $content ); $content = str_replace( '###SITENAME###', $email_data['sitename'], $content ); $content = str_replace( '###SITEURL###', sanitize_url( $email_data['siteurl'] ), $content ); $headers = ''; /** * Filters the headers of the email sent when an account action is attempted. * * @since 5.4.0 * * @param string|array $headers The email headers. * @param string $subject The email subject. * @param string $content The email content. * @param int $request_id The request ID. * @param array $email_data { * Data relating to the account action email. * * @type WP_User_Request $request User request object. * @type string $email The email address this is being sent to. * @type string $description Description of the action being performed so the user knows what the email is for. * @type string $confirm_url The link to click on to confirm the account action. * @type string $sitename The site name sending the mail. * @type string $siteurl The site URL sending the mail. * } */ $headers = apply_filters( 'user_request_action_email_headers', $headers, $subject, $content, $request_id, $email_data ); $email_sent = wp_mail( $email_data['email'], $subject, $content, $headers ); if ( $switched_locale ) { restore_previous_locale(); } if ( ! $email_sent ) { return new WP_Error( 'privacy_email_error', __( 'Unable to send personal data export confirmation email.' ) ); } return true; } /** * Returns a confirmation key for a user action and stores the hashed version for future comparison. * * @since 4.9.6 * * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. * * @param int $request_id Request ID. * @return string Confirmation key. */ function wp_generate_user_request_key( $request_id ) { global $wp_hasher; // Generate something random for a confirmation key. $key = wp_generate_password( 20, false ); // Return the key, hashed. if ( empty( $wp_hasher ) ) { require_once ABSPATH . WPINC . '/class-phpass.php'; $wp_hasher = new PasswordHash( 8, true ); } wp_update_post( array( 'ID' => $request_id, 'post_status' => 'request-pending', 'post_password' => $wp_hasher->HashPassword( $key ), ) ); return $key; } /** * Validates a user request by comparing the key with the request's key. * * @since 4.9.6 * * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. * * @param string $request_id ID of the request being confirmed. * @param string $key Provided key to validate. * @return true|WP_Error True on success, WP_Error on failure. */ function wp_validate_user_request_key( $request_id, $key ) { global $wp_hasher; $request_id = absint( $request_id ); $request = wp_get_user_request( $request_id ); $saved_key = $request->confirm_key; $key_request_time = $request->modified_timestamp; if ( ! $request || ! $saved_key || ! $key_request_time ) { return new WP_Error( 'invalid_request', __( 'Invalid personal data request.' ) ); } if ( ! in_array( $request->status, array( 'request-pending', 'request-failed' ), true ) ) { return new WP_Error( 'expired_request', __( 'This personal data request has expired.' ) ); } if ( empty( $key ) ) { return new WP_Error( 'missing_key', __( 'The confirmation key is missing from this personal data request.' ) ); } if ( empty( $wp_hasher ) ) { require_once ABSPATH . WPINC . '/class-phpass.php'; $wp_hasher = new PasswordHash( 8, true ); } /** * Filters the expiration time of confirm keys. * * @since 4.9.6 * * @param int $expiration The expiration time in seconds. */ $expiration_duration = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS ); $expiration_time = $key_request_time + $expiration_duration; if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) { return new WP_Error( 'invalid_key', __( 'The confirmation key is invalid for this personal data request.' ) ); } if ( ! $expiration_time || time() > $expiration_time ) { return new WP_Error( 'expired_key', __( 'The confirmation key has expired for this personal data request.' ) ); } return true; } /** * Returns the user request object for the specified request ID. * * @since 4.9.6 * * @param int $request_id The ID of the user request. * @return WP_User_Request|false */ function wp_get_user_request( $request_id ) { $request_id = absint( $request_id ); $post = get_post( $request_id ); if ( ! $post || 'user_request' !== $post->post_type ) { return false; } return new WP_User_Request( $post ); } /** * Checks if Application Passwords is supported. * * Application Passwords is supported only by sites using SSL or local environments * but may be made available using the {@see 'wp_is_application_passwords_available'} filter. * * @since 5.9.0 * * @return bool */ function wp_is_application_passwords_supported() { return is_ssl() || 'local' === wp_get_environment_type(); } /** * Checks if Application Passwords is globally available. * * By default, Application Passwords is available to all sites using SSL or to local environments. * Use the {@see 'wp_is_application_passwords_available'} filter to adjust its availability. * * @since 5.6.0 * * @return bool */ function wp_is_application_passwords_available() { /** * Filters whether Application Passwords is available. * * @since 5.6.0 * * @param bool $available True if available, false otherwise. */ return apply_filters( 'wp_is_application_passwords_available', wp_is_application_passwords_supported() ); } /** * Checks if Application Passwords is available for a specific user. * * By default all users can use Application Passwords. Use {@see 'wp_is_application_passwords_available_for_user'} * to restrict availability to certain users. * * @since 5.6.0 * * @param int|WP_User $user The user to check. * @return bool */ function wp_is_application_passwords_available_for_user( $user ) { if ( ! wp_is_application_passwords_available() ) { return false; } if ( ! is_object( $user ) ) { $user = get_userdata( $user ); } if ( ! $user || ! $user->exists() ) { return false; } /** * Filters whether Application Passwords is available for a specific user. * * @since 5.6.0 * * @param bool $available True if available, false otherwise. * @param WP_User $user The user to check. */ return apply_filters( 'wp_is_application_passwords_available_for_user', true, $user ); } /** * Registers the user meta property for persisted preferences. * * This property is used to store user preferences across page reloads and is * currently used by the block editor for preferences like 'fullscreenMode' and * 'fixedToolbar'. * * @since 6.1.0 * @access private * * @global wpdb $wpdb WordPress database abstraction object. */ function wp_register_persisted_preferences_meta() { /* * Create a meta key that incorporates the blog prefix so that each site * on a multisite can have distinct user preferences. */ global $wpdb; $meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences'; register_meta( 'user', $meta_key, array( 'type' => 'object', 'single' => true, 'show_in_rest' => array( 'name' => 'persisted_preferences', 'type' => 'object', 'schema' => array( 'type' => 'object', 'context' => array( 'edit' ), 'properties' => array( '_modified' => array( 'description' => __( 'The date and time the preferences were updated.' ), 'type' => 'string', 'format' => 'date-time', 'readonly' => false, ), ), 'additionalProperties' => true, ), ), ) ); } /** * Sets the last changed time for the 'users' cache group. * * @since 6.3.0 */ function wp_cache_set_users_last_changed() { wp_cache_set_last_changed( 'users' ); } /** * Checks if password reset is allowed for a specific user. * * @since 6.3.0 * * @param int|WP_User $user The user to check. * @return bool|WP_Error True if allowed, false or WP_Error otherwise. */ function wp_is_password_reset_allowed_for_user( $user ) { if ( ! is_object( $user ) ) { $user = get_userdata( $user ); } if ( ! $user || ! $user->exists() ) { return false; } $allow = true; if ( is_multisite() && is_user_spammy( $user ) ) { $allow = false; } /** * Filters whether to allow a password to be reset. * * @since 2.7.0 * * @param bool $allow Whether to allow the password to be reset. Default true. * @param int $user_id The ID of the user attempting to reset a password. */ return apply_filters( 'allow_password_reset', $allow, $user->ID ); }