Persian Woocommerce - Version 5.8.0

Version Description

  • ..




  • *
Download this release

Release Info

Developer Persianscript
Plugin Icon 128x128 Persian Woocommerce
Version 5.8.0
Comparing to
See all releases

Code changes from version 5.2.2 to 5.8.0

assets/js/jquery.min.js DELETED
@@ -1,2 +0,0 @@
1
- /*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
2
- !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(p,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),"function"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k="sizzle"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",$=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",F=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="<a id='"+k+"'></a><select id='"+k+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(F," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[k]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,"$1"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(B,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split("").sort(D).join("")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[":"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,"parentNode")},parentsUntil:function(e,t,n){return T(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return T(e,"nextSibling")},prevAll:function(e){return T(e,"previousSibling")},nextUntil:function(e,t,n){return T(e,"nextSibling",n)},prevUntil:function(e,t,n){return T(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return"undefined"!=typeof e.contentDocument?e.contentDocument:(A(e,"template")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\x20\t\r\n\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[["notify","progress",k.Callbacks("memory"),k.Callbacks("memory"),2],["resolve","done",k.Callbacks("once memory"),k.Callbacks("once memory"),0,"resolved"],["reject","fail",k.Callbacks("once memory"),k.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),k.ready()}k.fn.ready=function(e){return F.then(e)["catch"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,"ms-").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(Z,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks("once memory").add(function(){Q.remove(e,[t+"queue",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Q.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ne=new RegExp("^(?:([+-])=|)("+te+")([a-z%]*)$","i"),re=["Top","Right","Bottom","Left"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&oe(e)&&"none"===k.css(e,"display")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,"")},u=s(),l=n&&n[3]||(k.cssNumber[t]?"":"px"),c=e.nodeType&&(k.cssNumber[t]||"px"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Q.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ce[s]=u)))):"none"!==n&&(l[c]="none",Q.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],"globalEval",!t||Q.get(t[n],"globalEval"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement("div")),(xe=E.createElement("input")).setAttribute("type","radio"),xe.setAttribute("checked","checked"),xe.setAttribute("name","t"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Q.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:"focusin",blur:"focusout"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/<script|<style|<link/i,Le=/checked\s*(?:[^=]|=\s*.checked.)/i,He=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,"script"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Q.access(u,"globalEval")&&k.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")}):b(u.textContent.replace(He,""),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,"<$1></$2>")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp("^("+te+")(?!px)[a-z%]+$","i"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join("|"),"i");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",u.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n="1%"!==e.top,a=12===t(e.marginLeft),u.style.right="60%",o=36===t(e.right),r=36===t(e.width),u.style.position="absolute",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement("div"),u=E.createElement("div");u.style&&(u.style.backgroundClip="content-box",u.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=["Webkit","Moz","ms"],Xe=E.createElement("div").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:"absolute",visibility:"hidden",display:"block"},Ke={letterSpacing:"0",fontWeight:"400"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function et(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=k.css(e,n+re[a],!0,i)),r?("content"===n&&(u-=k.css(e,"padding"+re[a],!0,i)),"margin"!==n&&(u-=k.css(e,"border"+re[a]+"Width",!0,i))):(u+=k.css(e,"padding"+re[a],!0,i),"padding"!==n?u+=k.css(e,"border"+re[a]+"Width",!0,i):s+=k.css(e,"border"+re[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&"border-box"===k.css(e,"boxSizing",!1,r),o=i,a=_e(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||"auto"===a||!parseFloat(a)&&"inline"===k.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===k.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?"border":"content"),o,r,a)+"px"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),"normal"===i&&t in Ke&&(i=Ke[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each(["height","width"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===k.css(e,"boxSizing",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,"border",!1,i)-.5)),s&&(r=ne.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,"marginLeft"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),k.each({margin:"",padding:"",border:"Width"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?"":"px")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=re[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,"fxshow");for(r in n.queue||(null==(a=k._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,"display")),"none"===(c=k.css(e,"display"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,"display"),fe([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===k.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Q.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,"fxshow"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&"object"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Q.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each(["toggle","show","hide"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft("show"),slideUp:ft("hide"),slideToggle:ft("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement("input"),at=E.createElement("select").appendChild(E.createElement("option")),ot.type="checkbox",y.checkOn=""!==ot.value,y.optSelected=at.selected,(ot=E.createElement("input")).value="t",ot.type="radio",y.radioValue="t"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(" ")}function xt(e){return e.getAttribute&&e.getAttribute("class")||""}function bt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,"tabindex");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr("class","");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=xt(this))&&Q.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Q.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+mt(xt(n))+" ").indexOf(t))return!0;return!1}});var wt=/\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?"":e+""})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(wt,""):null==e?"":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,"value");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each(["radio","checkbox"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[k.expando]?e:new k.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,"events")||{})[e.type]&&Q.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\?/;k.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||k.error("Invalid XML: "+e),t};var Nt=/\[\]$/,At=/\r?\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)qt(n+"["+t+"]",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join("&")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,"elements");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(":disabled")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,"\r\n")}}):{name:t.name,value:n.replace(At,"\r\n")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Ft=E.createElement("a");function Bt(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+"").replace(Mt,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(R)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+"//"+Ft.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Lt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(St.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,"$1"),o=(St.test(f)?"&":"?")+"_="+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader("If-Modified-Since",k.lastModified[f]),k.etag[f]&&T.setRequestHeader("If-None-Match",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+$t+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(k.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(k.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--k.active||k.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,"json")},getScript:function(e,t){return k.get(e,void 0,t,"script")}}),k.each(["get","post"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&"withCredentials"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),k.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&k.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?k("<div>").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),k.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},"function"==typeof define&&define.amd&&define("jquery",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});
 
 
include/class-address.php CHANGED
@@ -1,402 +1,404 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
-
5
- if ( ! class_exists( 'Persian_Woocommerce_Address' ) ) :
6
-
7
- class Persian_Woocommerce_Address extends Persian_Woocommerce_Core {
8
-
9
- //public
10
- public $country, $states, $class;
11
-
12
- //private
13
- private $fields = array();
14
-
15
- private $selected_city = array();
16
-
17
- //private static
18
- private static $action_priority = 0;
19
-
20
- private static $iran_cities_page = false;
21
-
22
- private static $inline_script_printed = false;
23
-
24
- public function __construct() {
25
-
26
- $this->country = 'IR';
27
- $this->states = array(
28
- 'ABZ' => 'البرز',
29
- 'ADL' => 'اردبیل',
30
- 'EAZ' => 'آذربایجان شرقی',
31
- 'WAZ' => 'آذربایجان غربی',
32
- 'BHR' => 'بوشهر',
33
- 'CHB' => 'چهارمحال و بختیاری',
34
- 'FRS' => 'فارس',
35
- 'GIL' => 'گیلان',
36
- 'GLS' => 'گلستان',
37
- 'HDN' => 'همدان',
38
- 'HRZ' => 'هرمزگان',
39
- 'ILM' => 'ایلام',
40
- 'ESF' => 'اصفهان',
41
- 'KRN' => 'کرمان',
42
- 'KRH' => 'کرمانشاه',
43
- 'NKH' => 'خراسان شمالی',
44
- 'RKH' => 'خراسان رضوی',
45
- 'SKH' => 'خراسان جنوبی',
46
- 'KHZ' => 'خوزستان',
47
- 'KBD' => 'کهگیلویه و بویراحمد',
48
- 'KRD' => 'کردستان',
49
- 'LRS' => 'لرستان',
50
- 'MKZ' => 'مرکزی',
51
- 'MZN' => 'مازندران',
52
- 'GZN' => 'قزوین',
53
- 'QHM' => 'قم',
54
- 'SMN' => 'سمنان',
55
- 'SBN' => 'سیستان و بلوچستان',
56
- 'THR' => 'تهران',
57
- 'YZD' => 'یزد',
58
- 'ZJN' => 'زنجان'
59
- );
60
-
61
- add_filter( 'woocommerce_get_country_locale', array( $this, 'locales' ) );
62
- add_filter( 'woocommerce_localisation_address_formats', array( $this, 'address_formats' ) );
63
- add_filter( 'woocommerce_states', array( $this, 'iran_states' ), 10, 1 );
64
-
65
- if ( PW()->get_options( 'enable_iran_cities' ) == 'yes' ) {
66
-
67
- if ( ( $class = array( 'first', 'last' ) ) && PW()->get_options( 'flip_state_city' ) == 'yes' ) {
68
- $class = array_reverse( $class );
69
- }
70
- $this->class = array( 'state' => $class[0], 'city' => $class[1] );
71
-
72
- add_filter( 'woocommerce_checkout_fields', array( $this, 'checkout_fields' ) );
73
- add_filter( 'woocommerce_billing_fields', array( $this, 'billing_fields' ) );
74
- add_filter( 'woocommerce_shipping_fields', array( $this, 'shipping_fields' ) );
75
-
76
- add_filter( 'woocommerce_form_field_billing_iran_cities', array( $this, 'iran_cities_field' ), 11, 4 );
77
- add_filter( 'woocommerce_form_field_shipping_iran_cities', array( $this, 'iran_cities_field' ), 11, 4 );
78
-
79
- add_action( 'wp_enqueue_scripts', array( $this, 'external_js' ) );
80
- add_action( 'wp_footer', array( $this, 'inline_js' ), 0 );
81
- add_action( 'wp_footer', array( $this, 'force_inline_js' ), 999999 );
82
  }
83
- }
84
-
85
- public function locales( $locales ) {
86
- $locales[ $this->country ] = array(
87
- 'state' => array( 'label' => __( 'Province', 'woocommerce' ) ),
88
- 'postcode' => array( 'label' => __( 'Postcode', 'woocommerce' ) )
89
- );
90
 
91
- return $locales;
92
- }
 
93
 
94
- public function address_formats( $formats ) {
95
- $formats[ $this->country ] = "{first_name} {last_name}\n{company}\n{country}\n{state}\n{city}\n{address_1}\n{address_2}\n{postcode}";
96
 
97
- return $formats;
 
 
98
  }
 
 
 
 
 
 
 
99
 
100
- public function iran_states( $states ) {
 
101
 
102
- $states[ $this->country ] = $this->states;
 
103
 
104
- if ( PW()->get_options( 'allowed_states' ) == 'all' ) {
105
- return $states;
106
- }
107
 
108
- $selections = PW()->get_options( 'specific_allowed_states' );
109
 
110
- if ( is_array( $selections ) ) {
111
- $states[ $this->country ] = array_intersect_key( $this->states, array_flip( $selections ) );
112
- }
113
 
 
114
  return $states;
115
  }
116
 
117
- //--------------------------------------------
118
- public function checkout_fields( $fields ) {
119
 
120
- $this->fields = $fields;
 
 
121
 
122
- if ( is_checkout() ) {
123
- $types = array( 'billing', 'shipping' );
124
- foreach ( $types as $type ) {
125
 
126
- if ( ! empty( $fields[ $type ][ $type . '_city' ] ) ) {
127
- $fields[ $type ][ $type . '_city' ] = $this->modify_city_field( $fields[ $type ][ $type . '_city' ], $type );
128
- }
129
 
130
- if ( ! empty( $fields[ $type ][ $type . '_state' ] ) ) {
131
- $fields[ $type ][ $type . '_state' ] = $this->modify_state_field( $fields[ $type ][ $type . '_state' ], $type );
132
- }
133
- }
134
- }
135
 
136
- return $fields;
137
- }
138
 
139
- public function billing_fields( $fields ) {
140
 
141
- if ( is_wc_endpoint_url( 'edit-address' ) ) {
142
- $type = 'billing';
143
- if ( ! empty( $fields[ $type . '_city' ] ) ) {
144
- $fields[ $type . '_city' ] = $this->modify_city_field( $fields[ $type . '_city' ], $type );
145
  }
146
- if ( ! empty( $fields[ $type . '_state' ] ) ) {
147
- $fields[ $type . '_state' ] = $this->modify_state_field( $fields[ $type . '_state' ], $type );
 
148
  }
149
  }
150
-
151
- return $fields;
152
  }
153
 
154
- public function shipping_fields( $fields ) {
 
155
 
156
- if ( is_wc_endpoint_url( 'edit-address' ) ) {
157
- $type = 'shipping';
158
- if ( ! empty( $fields[ $type . '_city' ] ) ) {
159
- $fields[ $type . '_city' ] = $this->modify_city_field( $fields[ $type . '_city' ], $type );
160
- }
161
- if ( ! empty( $fields[ $type . '_state' ] ) ) {
162
- $fields[ $type . '_state' ] = $this->modify_state_field( $fields[ $type . '_state' ], $type );
163
- }
164
- }
165
 
166
- return $fields;
 
 
 
 
 
 
 
167
  }
168
 
169
- public function modify_state_field( $fields, $type ) {
170
- $classes = '';
171
- if ( ! empty( $fields['class'] ) && $classes = $fields['class'] ) {
172
- $classes = is_array( $classes ) ? implode( ',', $classes ) : $classes;
173
- $classes = str_ireplace( 'form-row-wide', 'form-row-' . $this->class['state'], $classes );
 
 
 
 
 
 
 
174
  }
175
- $fields['class'] = apply_filters( $type . '_iran_state_class', explode( ',', $classes ), $fields, $type );
 
 
 
176
 
177
- return $fields;
 
 
 
 
178
  }
 
179
 
180
- public function modify_city_field( $fields, $type ) {
181
- $classes = '';
182
- if ( ! empty( $fields['class'] ) && $classes = $fields['class'] ) {
183
- $classes = is_array( $classes ) ? implode( ',', $classes ) : $classes;
184
- $classes = str_ireplace( 'form-row-wide', 'form-row-' . $this->class['city'], $classes );
185
- }
186
- $fields['class'] = apply_filters( $type . '_iran_city_class', explode( ',', $classes ), $fields, $type );
187
- $fields['type'] = apply_filters( $type . '_iran_city_type', $type . '_iran_cities', $fields, $type );
188
- $fields['options'] = apply_filters( $type . '_iran_city_options', array( '' => '' ), $fields, $type );
189
 
190
- return $fields;
 
 
 
 
191
  }
 
 
 
192
 
193
- public function iran_cities_field( $field, $key, $args, $value ) {
 
194
 
195
- $type = explode( '_', $args['type'] );
196
- if ( ! empty( $value ) ) {
197
- $this->selected_city[] = $value . '_vsh_' . $type[0];
198
- }
199
 
200
- $required = $args['required'] ? ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>' : '';
 
 
 
201
 
202
- $args['label_class'] = array();
203
- if ( is_string( $args['label_class'] ) ) {
204
- $args['label_class'] = array( $args['label_class'] );
205
- }
206
 
207
- if ( is_null( $value ) ) {
208
- $value = ! empty( $args['default'] ) ? $args['default'] : '';
209
- }
 
210
 
211
- $selected_value = $args['type'] . '_selected_value';
212
- global ${$selected_value};
213
- ${$selected_value} = $value;
214
 
215
- $custom_attributes = array();
216
- if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) {
217
- foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
218
- $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
219
- }
 
 
 
220
  }
 
221
 
222
- if ( ! empty( $args['validate'] ) ) {
223
- foreach ( $args['validate'] as $validate ) {
224
- $args['class'][] = 'validate-' . $validate;
225
- }
226
  }
 
227
 
228
- $args['placeholder'] = __( 'یک شهر انتخاب کنید', 'woocommerce' );
229
 
230
- $label_id = $args['id'];
231
- $field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
232
 
233
- $field = '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="state_select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '"></select>';
234
 
235
- $field_html = '';
236
 
237
- if ( $args['label'] && 'checkbox' != $args['type'] ) {
238
- $field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . $args['label'] . $required . '</label>';
239
- }
240
 
241
- $field_html .= $field;
242
 
243
- if ( $args['description'] ) {
244
- $field_html .= '<span class="description">' . esc_attr( $args['description'] ) . '</span>';
245
- }
246
 
247
- $container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
248
- $container_id = esc_attr( $args['id'] ) . '_field';
249
 
250
- $after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
251
 
252
- $iran_cities = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
253
 
254
- return apply_filters( 'iran_cities_field_select_input', $iran_cities, $field_container, $container_class, $container_id, $field_html, $field, $key, $args, $value, $after );
255
- }
256
 
257
- public function external_js() {
258
- wp_dequeue_script( 'pw-iran-cities' );
259
- wp_deregister_script( 'pw-iran-cities' );
260
- wp_register_script( 'pw-iran-cities', apply_filters( 'persian_woo_iran_cities', PW()->plugin_url( 'assets/js/iran_cities.min.js' ) ), false, PW_VERSION, true );
261
 
262
- if ( self::$iran_cities_page = ( is_checkout() || is_wc_endpoint_url( 'edit-address' ) ) ) {
263
- wp_enqueue_script( 'pw-iran-cities' );
264
- }
265
  }
 
266
 
267
- public function inline_js( $force_inline_js = false ) {
268
- if ( ! $force_inline_js ) {
269
 
270
- if ( self::$inline_script_printed == 'yes' || ! self::$iran_cities_page || self::$action_priority > 100 ) {
271
- return;
272
- }
273
 
274
- if ( ! ( wp_script_is( 'jquery', 'done' ) && ! wp_script_is( 'wc-country-select', 'done' ) ) ) {
275
- self::$action_priority += 5;
276
- add_action( 'wp_footer', array( $this, 'inline_js' ), self::$action_priority );
277
 
278
- return;
279
- }
280
  }
 
281
 
282
- self::$inline_script_printed = 'yes';
283
- $value_index = apply_filters( 'iran_cities_value_index', 0 );
284
- $types = array( 'billing', 'shipping' );
285
- ?>
286
- <script type="text/javascript">
287
- if (!window.jQuery) {
288
- alert("کتابخانه جیکوئری قبل از کدهای مربوط به شهرهای ایران لود نشده است!");
289
- }
290
- jQuery(function ($) {
291
- <?php foreach ($types as $type) :
292
- $selected_value = $type . '_iran_cities_selected_value';
293
- global ${$selected_value};
294
- $value = ! empty( ${$selected_value} ) ? ${$selected_value} : '';
295
- $placeholder = isset( $this->fields[ $type ][ $type . '_city' ]['placeholder'] ) ? $this->fields[ $type ][ $type . '_city' ]['placeholder'] : __( 'City', 'woocommerce' );
296
 
297
- $countries = 'get_' . str_replace( 'billing', 'allowed', $type ) . '_countries';
298
- $countries = WC()->countries->$countries();
299
- $iran_exist = isset( $countries[ strtoupper( $this->country ) ] ) || isset( $countries[ strtolower( $this->country ) ] ) || isset( $countries[ ucfirst( $this->country ) ] ) ? 'yes' : 'no';
300
- $just_iran = count( $countries ) == 1 && $iran_exist == 'yes' ? 'yes' : 'no';
301
- ?>
302
 
303
- var <?php echo $type; ?>_iran_exist = '<?php echo $iran_exist; ?>';
304
- var <?php echo $type; ?>_just_iran = '<?php echo $just_iran; ?>';
 
 
305
 
306
- $(document.body).on('change', '#<?php echo $type; ?>_state', function () {
 
 
 
 
307
 
308
- if (<?php echo $type; ?>_iran_exist == 'yes' && (<?php echo $type; ?>_just_iran || $('#<?php echo $type; ?>_country').val() == '<?php echo $this->country ?>')) {
 
309
 
310
- <?php echo $type; ?>_cities = [];
311
- <?php echo $type; ?>_cities[0] = new Array('خطا در دریافت شهرها', '0');
312
 
313
- if (typeof Persian_Woo_iranCities === "function")
314
- <?php echo $type; ?>_cities = Persian_Woo_iranCities('' + $('#<?php echo $type; ?>_state').val() + '');
315
- else {
316
- alert('تابع مربوط به شهرهای ایران یافت نمیشود. با مدیریت در میان بگذارید.');
317
- }
318
 
319
- <?php echo $type; ?>_cities.sort(function (a, b) {
320
- if (a[0] == b[0])
321
- return 0;
322
- if (a[0] > b[0])
323
- return 1;
324
- else
325
- return -1;
326
- });
327
- var options = '<option value="-1">انتخاب کنید</option>';
328
- var j;
329
- <?php echo $type; ?>_selected = '';
330
- for (j in <?php echo $type; ?>_cities) {
331
- selected = '';
332
- if (<?php echo $type; ?>_cities[j][<?php echo $value_index; ?>] == '<?php echo $value;?>') {
333
- selected = "selected";
334
- <?php echo $type; ?>_selected = '<?php echo $value;?>';
335
- }
336
- options += "<option value='" + <?php echo $type; ?>_cities[j][<?php echo $value_index; ?>] + "' " + selected + ">" + <?php echo $type; ?>_cities[j][0] + "</option>";
337
- }
338
- $('#<?php echo $type; ?>_city').empty();
339
- if ($("#<?php echo $type; ?>_city").is('select')) {
340
- $('#<?php echo $type; ?>_city').append(options);
 
 
 
341
  }
342
- $('#<?php echo $type; ?>_city').val(<?php echo $type; ?>_selected).trigger("change");
343
  }
344
- });
345
- $('#<?php echo $type; ?>_state').trigger('change');
 
 
 
 
 
 
346
 
347
- var <?php echo $type; ?>_city_select = $('#<?php echo $type; ?>_city_field').html();
348
- var <?php echo $type; ?>_city_input = '<input id="<?php echo $type; ?>_city" name="<?php echo $type; ?>_city" type="text" class="input-text" value="<?php echo $value;?>" placeholder="<?php echo $placeholder;?>" />';
349
 
350
- $(document.body).on('change', '#<?php echo $type; ?>_country', function () {
351
- var is_iran = $('#<?php echo $type; ?>_country').val() == '<?php echo $this->country ?>' ? 'yes' : 'no';
352
- set_iran_cities_field('<?php echo $type; ?>', is_iran);
353
- });
354
- $('#<?php echo $type; ?>_country').trigger('change');
355
 
356
- if (!$('#<?php echo $type; ?>_country').length) {
357
- set_iran_cities_field('<?php echo $type; ?>', <?php echo $type; ?>_just_iran);
358
- }
359
 
360
- $(document.body).on('change', '#<?php echo $type; ?>_city', function () {
361
- if ($('#<?php echo $type; ?>_city').val() == 'لطفا استان خود را انتخاب کنید') {
362
- if ($().select2 && $('#<?php echo $type; ?>_state').data('select2'))
363
- $('#<?php echo $type; ?>_state').select2('open');
364
- }
365
- });
366
 
367
- <?php if ( is_checkout() ) {
368
- wc_enqueue_js( "if ($().select2 && $('#" . $type . "_city').data('select2') && !$('#" . $type . "_state').data('select2'))
369
  $('#" . $type . "_state').select2();" );
370
- } ?>
371
-
372
- <?php endforeach; ?>
373
- function set_iran_cities_field(type, iran) {
374
- if (iran == 'yes') {
375
- if (!$('#' + type + '_city').is('select')) {
376
- $('#' + type + '_city_field').empty();
377
- $('#' + type + '_city_field').html(eval(type + '_city_select'));
378
- $('#' + type + '_state').val('').trigger("change");
379
- $('#' + type + '_city').val('').trigger("change");
380
- }
381
- }
382
- else {
383
- $('#' + type + '_city_field').find('*').not('label').remove();
384
- $('#' + type + '_city_field').append(eval(type + '_city_input'));
385
  $('#' + type + '_state').val('').trigger("change");
386
  $('#' + type + '_city').val('').trigger("change");
387
  }
 
 
 
 
 
388
  }
 
389
 
390
- });
391
- </script>
392
- <?php
393
- }
394
 
395
- public function force_inline_js() {
396
- if ( self::$inline_script_printed != 'yes' && self::$iran_cities_page && wp_script_is( 'jquery', 'done' ) ) {
397
- $this->inline_js( true );
398
- }
399
  }
400
  }
401
- endif;
 
402
  PW()->address = new Persian_Woocommerce_Address();
1
+ <?php
2
+
3
+ defined( 'ABSPATH' ) || exit;
4
+
5
+ class Persian_Woocommerce_Address extends Persian_Woocommerce_Core {
6
+
7
+ //public
8
+ public $country, $states, $class;
9
+
10
+ //private
11
+ private $fields = [];
12
+
13
+ private $selected_city = [];
14
+
15
+ //private static
16
+ private static $action_priority = 0;
17
+
18
+ private static $iran_cities_page = false;
19
+
20
+ private static $inline_script_printed = false;
21
+
22
+ public function __construct() {
23
+
24
+ $this->country = 'IR';
25
+ $this->states = [
26
+ 'ABZ' => 'البرز',
27
+ 'ADL' => 'اردبیل',
28
+ 'EAZ' => 'آذربایجان شرقی',
29
+ 'WAZ' => 'آذربایجان غربی',
30
+ 'BHR' => 'بوشهر',
31
+ 'CHB' => 'چهارمحال و بختیاری',
32
+ 'FRS' => 'فارس',
33
+ 'GIL' => 'گیلان',
34
+ 'GLS' => 'گلستان',
35
+ 'HDN' => 'همدان',
36
+ 'HRZ' => 'هرمزگان',
37
+ 'ILM' => 'ایلام',
38
+ 'ESF' => 'اصفهان',
39
+ 'KRN' => 'کرمان',
40
+ 'KRH' => 'کرمانشاه',
41
+ 'NKH' => 'خراسان شمالی',
42
+ 'RKH' => 'خراسان رضوی',
43
+ 'SKH' => 'خراسان جنوبی',
44
+ 'KHZ' => 'خوزستان',
45
+ 'KBD' => 'کهگیلویه و بویراحمد',
46
+ 'KRD' => 'کردستان',
47
+ 'LRS' => 'لرستان',
48
+ 'MKZ' => 'مرکزی',
49
+ 'MZN' => 'مازندران',
50
+ 'GZN' => 'قزوین',
51
+ 'QHM' => 'قم',
52
+ 'SMN' => 'سمنان',
53
+ 'SBN' => 'سیستان و بلوچستان',
54
+ 'THR' => 'تهران',
55
+ 'YZD' => 'یزد',
56
+ 'ZJN' => 'زنجان',
57
+ ];
58
+
59
+ add_filter( 'woocommerce_get_country_locale', [ $this, 'locales' ] );
60
+ add_filter( 'woocommerce_localisation_address_formats', [ $this, 'address_formats' ] );
61
+ add_filter( 'woocommerce_states', [ $this, 'iran_states' ], 10, 1 );
62
+
63
+ if ( PW()->get_options( 'enable_iran_cities' ) == 'yes' ) {
64
+
65
+ if ( ( $class = [ 'first', 'last' ] ) && PW()->get_options( 'flip_state_city' ) == 'yes' ) {
66
+ $class = array_reverse( $class );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
+ $this->class = [ 'state' => $class[0], 'city' => $class[1] ];
 
 
 
 
 
 
69
 
70
+ add_filter( 'woocommerce_checkout_fields', [ $this, 'checkout_fields' ] );
71
+ add_filter( 'woocommerce_billing_fields', [ $this, 'billing_fields' ] );
72
+ add_filter( 'woocommerce_shipping_fields', [ $this, 'shipping_fields' ] );
73
 
74
+ add_filter( 'woocommerce_form_field_billing_iran_cities', [ $this, 'iran_cities_field' ], 11, 4 );
75
+ add_filter( 'woocommerce_form_field_shipping_iran_cities', [ $this, 'iran_cities_field' ], 11, 4 );
76
 
77
+ add_action( 'wp_enqueue_scripts', [ $this, 'external_js' ] );
78
+ add_action( 'wp_footer', [ $this, 'inline_js' ], 0 );
79
+ add_action( 'wp_footer', [ $this, 'force_inline_js' ], 999999 );
80
  }
81
+ }
82
+
83
+ public function locales( $locales ) {
84
+ $locales[ $this->country ] = [
85
+ 'state' => [ 'label' => __( 'Province', 'woocommerce' ) ],
86
+ 'postcode' => [ 'label' => __( 'Postcode', 'woocommerce' ) ],
87
+ ];
88
 
89
+ return $locales;
90
+ }
91
 
92
+ public function address_formats( $formats ) {
93
+ $formats[ $this->country ] = "{first_name} {last_name}\n{company}\n{country}\n{state}\n{city}\n{address_1}\n{address_2}\n{postcode}";
94
 
95
+ return $formats;
96
+ }
 
97
 
98
+ public function iran_states( $states ) {
99
 
100
+ $states[ $this->country ] = $this->states;
 
 
101
 
102
+ if ( PW()->get_options( 'allowed_states' ) == 'all' ) {
103
  return $states;
104
  }
105
 
106
+ $selections = PW()->get_options( 'specific_allowed_states' );
 
107
 
108
+ if ( is_array( $selections ) ) {
109
+ $states[ $this->country ] = array_intersect_key( $this->states, array_flip( $selections ) );
110
+ }
111
 
112
+ return $states;
113
+ }
 
114
 
115
+ //--------------------------------------------
116
+ public function checkout_fields( $fields ) {
 
117
 
118
+ $this->fields = $fields;
 
 
 
 
119
 
120
+ if ( is_checkout() ) {
 
121
 
122
+ $types = [ 'billing', 'shipping' ];
123
 
124
+ foreach ( $types as $type ) {
125
+
126
+ if ( ! empty( $fields[ $type ][ $type . '_city' ] ) ) {
127
+ $fields[ $type ][ $type . '_city' ] = $this->modify_city_field( $fields[ $type ][ $type . '_city' ], $type );
128
  }
129
+
130
+ if ( ! empty( $fields[ $type ][ $type . '_state' ] ) ) {
131
+ $fields[ $type ][ $type . '_state' ] = $this->modify_state_field( $fields[ $type ][ $type . '_state' ], $type );
132
  }
133
  }
 
 
134
  }
135
 
136
+ return $fields;
137
+ }
138
 
139
+ public function billing_fields( $fields ) {
 
 
 
 
 
 
 
 
140
 
141
+ if ( is_wc_endpoint_url( 'edit-address' ) ) {
142
+ $type = 'billing';
143
+ if ( ! empty( $fields[ $type . '_city' ] ) ) {
144
+ $fields[ $type . '_city' ] = $this->modify_city_field( $fields[ $type . '_city' ], $type );
145
+ }
146
+ if ( ! empty( $fields[ $type . '_state' ] ) ) {
147
+ $fields[ $type . '_state' ] = $this->modify_state_field( $fields[ $type . '_state' ], $type );
148
+ }
149
  }
150
 
151
+ return $fields;
152
+ }
153
+
154
+ public function shipping_fields( $fields ) {
155
+
156
+ if ( is_wc_endpoint_url( 'edit-address' ) ) {
157
+ $type = 'shipping';
158
+ if ( ! empty( $fields[ $type . '_city' ] ) ) {
159
+ $fields[ $type . '_city' ] = $this->modify_city_field( $fields[ $type . '_city' ], $type );
160
+ }
161
+ if ( ! empty( $fields[ $type . '_state' ] ) ) {
162
+ $fields[ $type . '_state' ] = $this->modify_state_field( $fields[ $type . '_state' ], $type );
163
  }
164
+ }
165
+
166
+ return $fields;
167
+ }
168
 
169
+ public function modify_state_field( $fields, $type ) {
170
+ $classes = '';
171
+ if ( ! empty( $fields['class'] ) && $classes = $fields['class'] ) {
172
+ $classes = is_array( $classes ) ? implode( ',', $classes ) : $classes;
173
+ $classes = str_ireplace( 'form-row-wide', 'form-row-' . $this->class['state'], $classes );
174
  }
175
+ $fields['class'] = apply_filters( $type . '_iran_state_class', explode( ',', $classes ), $fields, $type );
176
 
177
+ return $fields;
178
+ }
 
 
 
 
 
 
 
179
 
180
+ public function modify_city_field( $fields, $type ) {
181
+ $classes = '';
182
+ if ( ! empty( $fields['class'] ) && $classes = $fields['class'] ) {
183
+ $classes = is_array( $classes ) ? implode( ',', $classes ) : $classes;
184
+ $classes = str_ireplace( 'form-row-wide', 'form-row-' . $this->class['city'], $classes );
185
  }
186
+ $fields['class'] = apply_filters( $type . '_iran_city_class', explode( ',', $classes ), $fields, $type );
187
+ $fields['type'] = apply_filters( $type . '_iran_city_type', $type . '_iran_cities', $fields, $type );
188
+ $fields['options'] = apply_filters( $type . '_iran_city_options', [ '' => '' ], $fields, $type );
189
 
190
+ return $fields;
191
+ }
192
 
193
+ public function iran_cities_field( $field, $key, $args, $value ) {
 
 
 
194
 
195
+ $type = explode( '_', $args['type'] );
196
+ if ( ! empty( $value ) ) {
197
+ $this->selected_city[] = $value . '_vsh_' . $type[0];
198
+ }
199
 
200
+ $required = $args['required'] ? ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>' : '';
 
 
 
201
 
202
+ $args['label_class'] = [];
203
+ if ( is_string( $args['label_class'] ) ) {
204
+ $args['label_class'] = [ $args['label_class'] ];
205
+ }
206
 
207
+ if ( is_null( $value ) ) {
208
+ $value = ! empty( $args['default'] ) ? $args['default'] : '';
209
+ }
210
 
211
+ $selected_value = $args['type'] . '_selected_value';
212
+ global ${$selected_value};
213
+ ${$selected_value} = $value;
214
+
215
+ $custom_attributes = [];
216
+ if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) {
217
+ foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
218
+ $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
219
  }
220
+ }
221
 
222
+ if ( ! empty( $args['validate'] ) ) {
223
+ foreach ( $args['validate'] as $validate ) {
224
+ $args['class'][] = 'validate-' . $validate;
 
225
  }
226
+ }
227
 
228
+ $args['placeholder'] = __( 'یک شهر انتخاب کنید', 'woocommerce' );
229
 
230
+ $label_id = $args['id'];
231
+ $field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
232
 
233
+ $field = '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="state_select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . ' placeholder="' . esc_attr( $args['placeholder'] ) . '"></select>';
234
 
235
+ $field_html = '';
236
 
237
+ if ( $args['label'] && 'checkbox' != $args['type'] ) {
238
+ $field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . $args['label'] . $required . '</label>';
239
+ }
240
 
241
+ $field_html .= $field;
242
 
243
+ if ( $args['description'] ) {
244
+ $field_html .= '<span class="description">' . esc_attr( $args['description'] ) . '</span>';
245
+ }
246
 
247
+ $container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
248
+ $container_id = esc_attr( $args['id'] ) . '_field';
249
 
250
+ $after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
251
 
252
+ $iran_cities = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
253
 
254
+ return apply_filters( 'iran_cities_field_select_input', $iran_cities, $field_container, $container_class, $container_id, $field_html, $field, $key, $args, $value, $after );
255
+ }
256
 
257
+ public function external_js() {
258
+ wp_dequeue_script( 'pw-iran-cities' );
259
+ wp_deregister_script( 'pw-iran-cities' );
260
+ wp_register_script( 'pw-iran-cities', apply_filters( 'persian_woo_iran_cities', PW()->plugin_url( 'assets/js/iran_cities.min.js' ) ), false, PW_VERSION, true );
261
 
262
+ if ( self::$iran_cities_page = ( is_checkout() || is_wc_endpoint_url( 'edit-address' ) ) ) {
263
+ wp_enqueue_script( 'pw-iran-cities' );
 
264
  }
265
+ }
266
 
267
+ public function inline_js( $force_inline_js = false ) {
268
+ if ( ! $force_inline_js ) {
269
 
270
+ if ( self::$inline_script_printed == 'yes' || ! self::$iran_cities_page || self::$action_priority > 100 ) {
271
+ return;
272
+ }
273
 
274
+ if ( ! ( wp_script_is( 'jquery', 'done' ) && ! wp_script_is( 'wc-country-select', 'done' ) ) ) {
275
+ self::$action_priority += 5;
276
+ add_action( 'wp_footer', [ $this, 'inline_js' ], self::$action_priority );
277
 
278
+ return;
 
279
  }
280
+ }
281
 
282
+ self::$inline_script_printed = 'yes';
283
+ $value_index = apply_filters( 'iran_cities_value_index', 0 );
284
+ $types = [ 'billing', 'shipping' ];
285
+ ?>
286
+ <script type="text/javascript">
287
+ if (!window.jQuery) {
288
+ alert("کتابخانه جیکوئری قبل از کدهای مربوط به شهرهای ایران لود نشده است!");
289
+ }
290
+ jQuery(function ($) {
291
+ <?php foreach ($types as $type) :
 
 
 
 
292
 
293
+ $type = esc_attr( $type );
 
 
 
 
294
 
295
+ $selected_value = $type . '_iran_cities_selected_value';
296
+ global ${$selected_value};
297
+ $value = ! empty( ${$selected_value} ) ? ${$selected_value} : '';
298
+ $placeholder = isset( $this->fields[ $type ][ $type . '_city' ]['placeholder'] ) ? $this->fields[ $type ][ $type . '_city' ]['placeholder'] : __( 'City', 'woocommerce' );
299
 
300
+ $countries = 'get_' . str_replace( 'billing', 'allowed', $type ) . '_countries';
301
+ $countries = WC()->countries->$countries();
302
+ $iran_exist = isset( $countries[ strtoupper( $this->country ) ] ) || isset( $countries[ strtolower( $this->country ) ] ) || isset( $countries[ ucfirst( $this->country ) ] ) ? 'yes' : 'no';
303
+ $just_iran = count( $countries ) == 1 && $iran_exist == 'yes' ? 'yes' : 'no';
304
+ ?>
305
 
306
+ var <?php echo esc_attr( $type ); ?>_iran_exist = '<?php echo esc_attr( $iran_exist ); ?>';
307
+ var <?php echo esc_attr( $type ); ?>_just_iran = '<?php echo esc_attr( $just_iran ); ?>';
308
 
309
+ $(document.body).on('change', '#<?php echo esc_attr( $type ); ?>_state', function () {
 
310
 
311
+ if (<?php echo esc_attr( $type ); ?>_iran_exist == 'yes' && (<?php echo esc_attr( $type ); ?>_just_iran || $('#<?php echo esc_attr( $type ); ?>_country').val() == '<?php echo $this->country ?>')) {
 
 
 
 
312
 
313
+ <?php echo esc_attr( $type ); ?>_cities = [];
314
+ <?php echo esc_attr( $type ); ?>_cities[0] = new Array('خطا در دریافت شهرها', '0');
315
+
316
+ if (typeof Persian_Woo_iranCities === "function")
317
+ <?php echo esc_attr( $type ); ?>_cities = Persian_Woo_iranCities('' + $('#<?php echo esc_attr( $type ); ?>_state').val() + '');
318
+ else {
319
+ alert('تابع مربوط به شهرهای ایران یافت نمیشود. با مدیریت در میان بگذارید.');
320
+ }
321
+
322
+ <?php echo esc_attr( $type ); ?>_cities.sort(function (a, b) {
323
+ if (a[0] == b[0])
324
+ return 0;
325
+ if (a[0] > b[0])
326
+ return 1;
327
+ else
328
+ return -1;
329
+ });
330
+ var options = '<option value="-1">انتخاب کنید</option>';
331
+ var j;
332
+ <?php echo esc_attr( $type ); ?>_selected = '';
333
+ for (j in <?php echo esc_attr( $type ); ?>_cities) {
334
+ selected = '';
335
+ if (<?php echo esc_attr( $type ); ?>_cities[j][<?php echo intval( $value_index ); ?>] == '<?php echo esc_attr( $value );?>') {
336
+ selected = "selected";
337
+ <?php echo esc_attr( $type ); ?>_selected = '<?php echo esc_attr( $value );?>';
338
  }
339
+ options += "<option value='" + <?php echo esc_attr( $type ); ?>_cities[j][<?php echo intval( $value_index ); ?>] + "' " + selected + ">" + <?php echo esc_attr( $type ); ?>_cities[j][0] + "</option>";
340
  }
341
+ $('#<?php echo esc_attr( $type ); ?>_city').empty();
342
+ if ($("#<?php echo esc_attr( $type ); ?>_city").is('select')) {
343
+ $('#<?php echo esc_attr( $type ); ?>_city').append(options);
344
+ }
345
+ $('#<?php echo esc_attr( $type ); ?>_city').val(<?php echo esc_attr( $type ); ?>_selected).trigger("change");
346
+ }
347
+ });
348
+ $('#<?php echo esc_attr( $type ); ?>_state').trigger('change');
349
 
350
+ var <?php echo esc_attr( $type ); ?>_city_select = $('#<?php echo esc_attr( $type ); ?>_city_field').html();
351
+ var <?php echo esc_attr( $type ); ?>_city_input = '<input id="<?php echo esc_attr( $type ); ?>_city" name="<?php echo esc_attr( $type ); ?>_city" type="text" class="input-text" value="<?php echo esc_attr( $value );?>" placeholder="<?php echo esc_attr( $placeholder );?>" />';
352
 
353
+ $(document.body).on('change', '#<?php echo esc_attr( $type ); ?>_country', function () {
354
+ var is_iran = $('#<?php echo esc_attr( $type ); ?>_country').val() == '<?php echo $this->country ?>' ? 'yes' : 'no';
355
+ set_iran_cities_field('<?php echo esc_attr( $type ); ?>', is_iran);
356
+ });
357
+ $('#<?php echo esc_attr( $type ); ?>_country').trigger('change');
358
 
359
+ if (!$('#<?php echo esc_attr( $type ); ?>_country').length) {
360
+ set_iran_cities_field('<?php echo esc_attr( $type ); ?>', <?php echo esc_attr( $type ); ?>_just_iran);
361
+ }
362
 
363
+ $(document.body).on('change', '#<?php echo esc_attr( $type ); ?>_city', function () {
364
+ if ($('#<?php echo esc_attr( $type ); ?>_city').val() == 'لطفا استان خود را انتخاب کنید') {
365
+ if ($().select2 && $('#<?php echo esc_attr( $type ); ?>_state').data('select2'))
366
+ $('#<?php echo esc_attr( $type ); ?>_state').select2('open');
367
+ }
368
+ });
369
 
370
+ <?php if ( is_checkout() ) {
371
+ wc_enqueue_js( "if ($().select2 && $('#" . $type . "_city').data('select2') && !$('#" . $type . "_state').data('select2'))
372
  $('#" . $type . "_state').select2();" );
373
+ } ?>
374
+
375
+ <?php endforeach; ?>
376
+ function set_iran_cities_field(type, iran) {
377
+ if (iran == 'yes') {
378
+ if (!$('#' + type + '_city').is('select')) {
379
+ $('#' + type + '_city_field').empty();
380
+ $('#' + type + '_city_field').html(eval(type + '_city_select'));
 
 
 
 
 
 
 
381
  $('#' + type + '_state').val('').trigger("change");
382
  $('#' + type + '_city').val('').trigger("change");
383
  }
384
+ } else {
385
+ $('#' + type + '_city_field').find('*').not('label').remove();
386
+ $('#' + type + '_city_field').append(eval(type + '_city_input'));
387
+ $('#' + type + '_state').val('').trigger("change");
388
+ $('#' + type + '_city').val('').trigger("change");
389
  }
390
+ }
391
 
392
+ });
393
+ </script>
394
+ <?php
395
+ }
396
 
397
+ public function force_inline_js() {
398
+ if ( self::$inline_script_printed != 'yes' && self::$iran_cities_page && wp_script_is( 'jquery', 'done' ) ) {
399
+ $this->inline_js( true );
 
400
  }
401
  }
402
+ }
403
+
404
  PW()->address = new Persian_Woocommerce_Address();
include/class-core.php CHANGED
@@ -1,355 +1,207 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
-
5
- if ( ! class_exists( 'Persian_Woocommerce_Core' ) ) :
6
 
7
- class Persian_Woocommerce_Core {
8
 
9
- protected $options;
10
 
11
- // sub classes
12
- public $tools, $widget, $translate, $currencies, $address, $gateways;
13
 
14
- protected static $_instance = null;
 
15
 
16
- public static function instance() {
17
- if ( is_null( self::$_instance ) ) {
18
- self::$_instance = new self();
19
- }
20
 
21
- return self::$_instance;
 
 
22
  }
23
 
24
- public function __construct() {
 
25
 
26
- $this->activated_plugin();
27
 
28
- $this->options = get_option( 'PW_Options' );
29
 
30
- //add_filter( 'woocommerce_show_addons_page', '__return_false', 100 );
31
- add_action( 'admin_menu', [ $this, 'admin_menus' ], 59 );
32
- add_action( 'admin_head', [ $this, 'admin_head' ] );
33
- add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
34
- add_action( 'admin_notices', [ $this, 'notices_render' ] );
35
- add_action( 'wp_ajax_pw_notice_dismiss', [ $this, 'notices_dismiss' ] );
36
- add_action( 'plugins_loaded', [ $this, 'plugins_loaded' ], 10 );
37
- }
38
 
39
- public function plugins_loaded() {
40
- require_once( 'class-gateways.php' );
41
- }
 
 
 
42
 
43
- public function admin_menus() {
 
 
44
 
45
- add_menu_page( 'ووکامرس فارسی', 'ووکامرس فارسی', 'manage_options', 'persian-wc', array(
46
- $this->translate,
47
- 'translate_page'
48
- ), $this->plugin_url( 'assets/images/logo.png' ), '55.6' );
49
 
50
- add_submenu_page( 'persian-wc', 'حلقه های ترجمه', 'حلقه های ترجمه', 'manage_options', 'persian-wc', array(
51
- $this->translate,
52
- 'translate_page'
53
- ) );
54
 
55
- add_submenu_page( 'persian-wc', 'ابزار ها', 'ابزار ها', 'manage_options', 'persian-wc-tools', array(
56
- $this->tools,
57
- 'tools_page'
58
- ) );
59
 
60
- do_action( "PW_Menu" );
 
 
 
61
 
62
- add_submenu_page( 'persian-wc', 'افزونه ها', 'افزونه ها', 'manage_woocommerce', 'persian-wc-plugins', array(
63
- $this,
64
- 'plugins_page'
65
- ) );
66
 
67
- add_submenu_page( 'persian-wc', 'پوسته ها', 'پوسته ها', 'manage_woocommerce', 'persian-wc-themes', array(
68
- $this,
69
- 'themes_page'
70
- ) );
71
 
72
- add_submenu_page( 'persian-wc', 'پیشخوان پست تاپین', 'پیشخوان پست تاپین', 'manage_woocommerce', 'https://yun.ir/pwtm' );
 
 
 
73
 
74
- add_submenu_page( 'woocommerce', 'افزونه های پارسی', 'افزونه های پارسی', 'manage_woocommerce', 'wc-persian-plugins', array(
75
- $this,
76
- 'plugins_page'
77
- ) );
78
 
79
- add_submenu_page( 'woocommerce', 'پوسته های پارسی', 'پوسته های پارسی', 'manage_woocommerce', 'wc-persian-themes', array(
80
- $this,
81
- 'themes_page'
82
- ) );
83
 
84
- add_submenu_page( 'persian-wc', 'درباره ما', 'درباره ما', 'manage_options', 'persian-wc-about', array(
85
- $this,
86
- 'about_page'
87
- ) );
88
- }
89
 
90
- public function admin_head() {
91
- ?>
92
- <script type="text/javascript">
93
- jQuery(document).ready(function ( $ ) {
94
- $("ul#adminmenu a[href$='https://yun.ir/pwtm']").attr('target', '_blank');
95
- });
96
- </script>
97
- <?php
98
- }
99
 
100
- public function themes_page() {
101
- wp_enqueue_style( 'woocommerce_admin_styles' );
102
- include( 'view/html-admin-page-themes.php' );
103
- }
 
 
 
 
 
104
 
105
- public function plugins_page() {
106
- wp_enqueue_style( 'woocommerce_admin_styles' );
107
- include( 'view/html-admin-page-plugins.php' );
108
- }
109
 
110
- public function about_page() {
111
- include( 'view/html-admin-page-about.php' );
112
- }
 
113
 
114
- public function activated_plugin() {
115
- global $wpdb;
 
116
 
117
- if ( ! file_exists( PW_DIR . '/.activated' ) ) {
118
- return false;
119
- }
120
 
121
- $woocommerce_ir_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}woocommerce_ir` (
 
 
 
 
122
  `id` int(11) NOT NULL AUTO_INCREMENT,
123
  `text1` text CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
124
  `text2` text CHARACTER SET utf8 COLLATE utf8_persian_ci,
125
  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;";
126
 
127
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
128
- dbDelta( $woocommerce_ir_sql );
129
-
130
- //delete deprecated tables-----------------------------
131
- $deprecated_tables = [
132
- 'woocommerce_ir_cities',
133
- 'Woo_Iran_Cities_By_HANNANStd',
134
- ];
135
-
136
- foreach ( $deprecated_tables as $deprecated_table ) {
137
- $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}{$deprecated_table}" );
138
- }
139
-
140
- //delete deprecated Options-----------------------------
141
- $deprecated_options = array(
142
- 'is_cities_installed',
143
- 'pw_delete_city_table_2_5',
144
- 'woocommerce_persian_feed',
145
- 'redirect_to_woo_persian_about_page',
146
- 'enable_woocommerce_notice_dismissed',
147
- 'Persian_Woocommerce_rename_old_table',
148
- );
149
-
150
- foreach ( $deprecated_options as $deprecated_option ) {
151
- delete_option( $deprecated_option );
152
- }
153
-
154
- for ( $i = 0; $i < 10; $i ++ ) {
155
- delete_option( 'persian_woo_notice_number_' . $i );
156
- }
157
-
158
- unlink( PW_DIR . '/.activated' );
159
-
160
- if ( ! headers_sent() ) {
161
- wp_redirect( admin_url( 'admin.php?page=persian-wc-about' ) );
162
- die();
163
- }
164
- }
165
 
166
- public function enqueue_scripts() {
167
- $pages = [
168
- 'persian-wc-about',
169
- 'persian-wc-plugins',
170
- 'wc-persian-plugins',
171
- 'persian-wc-themes',
172
- 'wc-persian-themes',
173
- ];
174
-
175
- if ( ! empty( $_GET['page'] ) && in_array( $_GET['page'], $pages ) ) {
176
- wp_register_style( 'pw-admin-fonts', $this->plugin_url( 'assets/css/admin.font.css' ) );
177
- wp_enqueue_style( 'pw-admin-fonts' );
178
- }
179
  }
180
 
181
- public function plugin_url( $path = null ) {
182
- return untrailingslashit( plugins_url( is_null( $path ) ? '/' : $path, PW_FILE ) );
 
 
 
 
 
 
 
 
 
 
183
  }
184
 
185
- public function get_options( $option_name = null, $default = false ) {
 
 
186
 
187
- if ( is_null( $option_name ) ) {
188
- return $this->options;
189
- }
190
 
191
- $default_options = array();
 
 
 
 
192
 
193
- if ( ! empty( $this->tools ) && method_exists( $this->tools, 'get_tools_default' ) ) {
194
- $default_options = $this->tools->get_tools_default();
195
- }
 
 
 
 
 
196
 
197
- if ( isset( $this->options[ $option_name ] ) ) {
198
- return $this->options[ $option_name ];
199
- } elseif ( isset( $default_options["PW_Options[$option_name]"] ) ) {
200
- return $default_options["PW_Options[$option_name]"];
201
- } else {
202
- return $default;
203
- }
204
- }
205
 
206
- public function notices_render() {
207
- $notices = array();
208
- $this->notices_texts( $notices );
209
- $dismissed = (array) get_option( 'persian_woocommerce_dismissed_notices' );
210
-
211
- foreach ( $notices as $id => $notice ) {
212
- if ( count( $notice ) == 3 && ! $notice[2] ) {
213
- continue;
214
- }
215
- if ( ! in_array( $id, $dismissed ) ) {
216
- printf( '<div class="notice persian_woocommerce_notice notice-%2$s is-dismissible" id="persian_woocommerce_%1$s"><p>%3$s</p></div>', $id, $notice[0], $notice[1] );
217
- break;
218
- }
219
- }
220
- ?>
221
- <script type="text/javascript">
222
- jQuery(document).ready(function ( $ ) {
223
- $(document.body).on('click', '.notice-dismiss', function () {
224
- var notice = $(this).closest('.persian_woocommerce_notice');
225
- notice = notice.attr('id');
226
- if( notice.indexOf('persian_woocommerce_') !== -1 ) {
227
- notice = notice.replace('persian_woocommerce_', '');
228
- $.ajax({
229
- url: "<?php echo admin_url( 'admin-ajax.php' ) ?>",
230
- type: "post",
231
- data: {
232
- notice: notice,
233
- action: 'pw_notice_dismiss',
234
- security: "<?php echo wp_create_nonce( 'pw_notice_dismiss' ); ?>"
235
- },
236
- success: function ( response ) {
237
- }
238
- });
239
- }
240
- return false;
241
- });
242
- });
243
- </script>
244
- <?php
245
  }
 
246
 
247
- public function notices_dismiss() {
 
 
248
 
249
- check_ajax_referer( 'pw_notice_dismiss', 'security' );
250
 
251
- if ( ! empty( $_POST['notice'] ) ) {
252
- $dismissed = (array) get_option( 'persian_woocommerce_dismissed_notices' );
253
- $dismissed[] = $_POST['notice'];
254
- update_option( 'persian_woocommerce_dismissed_notices', array_unique( $dismissed ) );
255
- }
256
- die();
257
  }
258
 
259
- private function notices_texts( &$notices ) {
260
- global $pagenow;
261
-
262
- $post_type = $_GET['post_type'] ?? null;
263
- $page = $_GET['page'] ?? null;
264
- $tab = $_GET['tab'] ?? null;
265
-
266
- $notices['tapin-orders'] = [
267
- 'success',
268
- '<b>با افزونه حمل و نقل ووکامرس فارسی یک دفتر پستی اختصاصی داشته باش و بدون مراجعه به پست همه سفارشاتتو ارسال کن.</b>
269
- <ul>
270
- <li>- تولید فاکتور پست همراه با بارکد پستی به صورت آنلاین</li>
271
- <li>- جمع آوری مرسولات از محل شما توسط ماموران پست</li>
272
- <li>- ارسال کد رهگیری پستی برای مشتریان به صورت پیامکی</li>
273
- <li>- بروزرسانی خودکار آخرین وضعیت مرسوله در پنل ووکامرس</li>
274
- </ul>
275
- <a href="https://yun.ir/pwto" target="_blank">
276
- <input type="button" class="button button-primary" value="اطلاعات بیشتر">
277
- </a>
278
- <a href="' . admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) . '" target="_blank">
279
- <input type="button" class="button" value="نصب افزونه پیشخوان پست">
280
- </a>',
281
- $pagenow == 'edit.php' && $post_type == 'shop_order'
282
- ];
283
-
284
- $notices['tapin-shipping'] = [
285
- 'success',
286
- '<b>با افزونه حمل و نقل ووکامرس فارسی به رایگان هزینه پست سفارشی و پیشتاز رو بصورت دقیق و طبق آخرین تعرفه پست محاسبه کنید و سرویس پرداخت در محل رو در سراسر کشور فعال کنید.</b>
287
- <ul>
288
- <li>- محاسبه دقیق هزینه ارسال بر اساس وزن و شهر خریدار</li>
289
- <li>- امکان تخفیف در هزینه ارسال بر اساس میزان خرید</li>
290
- <li>- صدور آنلاین کد رهگیری پستی و تولید فاکتور</li>
291
- <li>- ارسال کد رهگیری به خریدار به صورت پیامکی و در پنل کاربری</li>
292
- </ul>
293
- <a href="https://yun.ir/pwts" target="_blank">
294
- <input type="button" class="button button-primary" value="اطلاعات بیشتر">
295
- </a>
296
- <a href="' . admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) . '" target="_blank">
297
- <input type="button" class="button" value="نصب افزونه پیشخوان پست">
298
- </a>',
299
- $page == 'wc-settings' && $tab == 'shipping'
300
- ];
301
-
302
- $notices['tapin-tools'] = [
303
- 'success',
304
- '
305
- <a href="https://yun.ir/pwtt" target="_blank">
306
- <img src="' . $this->plugin_url( 'assets/images/tapin.jpg' ) . '" style="width: 100%">
307
- </a>',
308
- $page == 'persian-wc-tools'
309
- ];
310
-
311
- $notices['tapin-dashboard'] = [
312
- 'success',
313
- '<b>پیشخوان وردپرس خود را رایگان به شرکت ملی پست متصل کنید و یک دفتر پستی اختصاصی داشته باشید.</b>
314
- <ul>
315
- <li>- محاسبه دقیق هزینه های پستی در سبد خرید</li>
316
- <li>- جمع آری سفارشات از محل شما توسط ماموران پست در سراسر کشور</li>
317
- <li>- صدور فاکتور استاندارد پست همراه با بارکد پست</li>
318
- <li>- ارسال کد رهگیری پست به مشتری به صورت پیامکی و پنل کاربری</li>
319
- </ul>
320
- <a href="https://yun.ir/pwtd" target="_blank">
321
- <input type="button" class="button button-primary" value="اطلاعات بیشتر">
322
- </a>
323
- <a href="' . admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) . '" target="_blank">
324
- <input type="button" class="button" value="نصب افزونه پیشخوان پست">
325
- </a>',
326
- true
327
- ];
328
-
329
- $notices['persian-date'] = [
330
- 'info',
331
- '<b>ووکامرس فارسی با طمع ووکامرس شمسی!</b>
332
- <ul>
333
- <li>- شمسی سازی محیط وردپرس بدون نیاز به افزونه جانبی</li>
334
- <li>- شمسی سازی ووکامرس در محصولات، سفارشات، کوپن ها و گزارشات</li>
335
- <li>- افزودن DatePicker شمسی در پنل ووکامرس</li>
336
- <li>- برای فعالسازی شمسی ساز ووکامرس روی کلید زیر کلیک کنید:</li>
337
- </ul>
338
- <a href="' . admin_url( 'admin.php?page=persian-wc-tools' ) . '" target="_blank">
339
- <input type="button" class="button button-primary" value="فعالسازی شمسی ساز وردپرس و ووکامرس">
340
- </a>',
341
- $this->get_options( 'enable_jalali_datepicker' ) !== 'yes',
342
- ];
343
-
344
- $notices['pws'] = [
345
- 'info',
346
- sprintf( 'بنظر میرسه هنوز حمل و نقل (پست پیشتاز، سفارشی، پیک موتوری و...) فروشگاه رو پیکربندی نکردید؟ <a href="%s" target="_blank">نصب افزونه حمل و نقل فارسی ووکامرس و پیکربندی.</a>', admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) ),
347
- class_exists( 'WC_Shipping_Zones' ) && ! count( WC_Shipping_Zones::get_zones() ) && current_user_can( 'install_plugins' ),
348
- ];
349
 
 
 
 
 
 
 
 
 
 
 
350
  }
351
  }
352
- endif;
 
353
 
354
  if ( ! class_exists( 'Persian_Woocommerce_Plugin' ) ) {
355
  class Persian_Woocommerce_Plugin extends Persian_Woocommerce_Core {
1
+ <?php
 
 
 
 
2
 
3
+ defined( 'ABSPATH' ) || exit;
4
 
5
+ class Persian_Woocommerce_Core {
6
 
7
+ protected $options;
 
8
 
9
+ // sub classes
10
+ public $tools, $translate, $address, $gateways;
11
 
12
+ protected static $_instance = null;
 
 
 
13
 
14
+ public static function instance() {
15
+ if ( is_null( self::$_instance ) ) {
16
+ self::$_instance = new self();
17
  }
18
 
19
+ return self::$_instance;
20
+ }
21
 
22
+ public function __construct() {
23
 
24
+ $this->activated_plugin();
25
 
26
+ $this->options = get_option( 'PW_Options' );
 
 
 
 
 
 
 
27
 
28
+ //add_filter( 'woocommerce_show_addons_page', '__return_false', 100 );
29
+ add_action( 'admin_menu', [ $this, 'admin_menus' ], 59 );
30
+ add_action( 'admin_head', [ $this, 'admin_head' ] );
31
+ add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
32
+ add_action( 'plugins_loaded', [ $this, 'plugins_loaded' ], 10 );
33
+ }
34
 
35
+ public function plugins_loaded() {
36
+ require_once( 'class-gateways.php' );
37
+ }
38
 
39
+ public function admin_menus() {
 
 
 
40
 
41
+ add_menu_page( 'ووکامرس فارسی', 'ووکامرس فارسی', 'manage_options', 'persian-wc', [
42
+ $this->translate,
43
+ 'translate_page',
44
+ ], $this->plugin_url( 'assets/images/logo.png' ), '55.6' );
45
 
46
+ add_submenu_page( 'persian-wc', 'حلقه های ترجمه', 'حلقه های ترجمه', 'manage_options', 'persian-wc', [
47
+ $this->translate,
48
+ 'translate_page',
49
+ ] );
50
 
51
+ add_submenu_page( 'persian-wc', 'ابزار ها', 'ابزار ها', 'manage_options', 'persian-wc-tools', [
52
+ $this->tools,
53
+ 'tools_page',
54
+ ] );
55
 
56
+ do_action( "PW_Menu" );
 
 
 
57
 
58
+ add_submenu_page( 'persian-wc', 'افزونه ها', 'افزونه ها', 'manage_woocommerce', 'persian-wc-plugins', [
59
+ $this,
60
+ 'plugins_page',
61
+ ] );
62
 
63
+ add_submenu_page( 'persian-wc', 'پوسته ها', 'پوسته ها', 'manage_woocommerce', 'persian-wc-themes', [
64
+ $this,
65
+ 'themes_page',
66
+ ] );
67
 
68
+ add_submenu_page( 'persian-wc', 'پیشخوان پست تاپین', 'پیشخوان پست تاپین', 'manage_woocommerce', 'https://yun.ir/pwtm' );
 
 
 
69
 
70
+ add_submenu_page( 'woocommerce', 'افزونه های پارسی', 'افزونه های پارسی', 'manage_woocommerce', 'wc-persian-plugins', [
71
+ $this,
72
+ 'plugins_page',
73
+ ] );
74
 
75
+ add_submenu_page( 'woocommerce', 'پوسته های پارسی', 'پوسته های پارسی', 'manage_woocommerce', 'wc-persian-themes', [
76
+ $this,
77
+ 'themes_page',
78
+ ] );
 
79
 
80
+ add_submenu_page( 'persian-wc', 'درباره ما', 'درباره ما', 'manage_options', 'persian-wc-about', [
81
+ $this,
82
+ 'about_page',
83
+ ] );
84
+ }
 
 
 
 
85
 
86
+ public function admin_head() {
87
+ ?>
88
+ <script type="text/javascript">
89
+ jQuery(document).ready(function ($) {
90
+ $("ul#adminmenu a[href$='https://yun.ir/pwtm']").attr('target', '_blank');
91
+ });
92
+ </script>
93
+ <?php
94
+ }
95
 
96
+ public function themes_page() {
97
+ wp_enqueue_style( 'woocommerce_admin_styles' );
98
+ include( 'view/html-admin-page-themes.php' );
99
+ }
100
 
101
+ public function plugins_page() {
102
+ wp_enqueue_style( 'woocommerce_admin_styles' );
103
+ include( 'view/html-admin-page-plugins.php' );
104
+ }
105
 
106
+ public function about_page() {
107
+ include( 'view/html-admin-page-about.php' );
108
+ }
109
 
110
+ public function activated_plugin() {
111
+ global $wpdb;
 
112
 
113
+ if ( ! file_exists( PW_DIR . '/.activated' ) ) {
114
+ return false;
115
+ }
116
+
117
+ $woocommerce_ir_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}woocommerce_ir` (
118
  `id` int(11) NOT NULL AUTO_INCREMENT,
119
  `text1` text CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
120
  `text2` text CHARACTER SET utf8 COLLATE utf8_persian_ci,
121
  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;";
122
 
123
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
124
+ dbDelta( $woocommerce_ir_sql );
125
+
126
+ //delete deprecated tables-----------------------------
127
+ $deprecated_tables = [
128
+ 'woocommerce_ir_cities',
129
+ 'Woo_Iran_Cities_By_HANNANStd',
130
+ ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
+ foreach ( $deprecated_tables as $deprecated_table ) {
133
+ $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}{$deprecated_table}" );
 
 
 
 
 
 
 
 
 
 
 
134
  }
135
 
136
+ //delete deprecated Options-----------------------------
137
+ $deprecated_options = [
138
+ 'is_cities_installed',
139
+ 'pw_delete_city_table_2_5',
140
+ 'woocommerce_persian_feed',
141
+ 'redirect_to_woo_persian_about_page',
142
+ 'enable_woocommerce_notice_dismissed',
143
+ 'Persian_Woocommerce_rename_old_table',
144
+ ];
145
+
146
+ foreach ( $deprecated_options as $deprecated_option ) {
147
+ delete_option( $deprecated_option );
148
  }
149
 
150
+ for ( $i = 0; $i < 10; $i ++ ) {
151
+ delete_option( 'persian_woo_notice_number_' . $i );
152
+ }
153
 
154
+ unlink( PW_DIR . '/.activated' );
 
 
155
 
156
+ if ( ! headers_sent() ) {
157
+ wp_redirect( admin_url( 'admin.php?page=persian-wc-about' ) );
158
+ die();
159
+ }
160
+ }
161
 
162
+ public function enqueue_scripts() {
163
+ $pages = [
164
+ 'persian-wc-about',
165
+ 'persian-wc-plugins',
166
+ 'wc-persian-plugins',
167
+ 'persian-wc-themes',
168
+ 'wc-persian-themes',
169
+ ];
170
 
171
+ $sanitize_text_field = sanitize_text_field( $_GET['page'] ?? null );
 
 
 
 
 
 
 
172
 
173
+ if ( in_array( $sanitize_text_field, $pages ) ) {
174
+ wp_register_style( 'pw-admin-fonts', $this->plugin_url( 'assets/css/admin.font.css' ) );
175
+ wp_enqueue_style( 'pw-admin-fonts' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  }
177
+ }
178
 
179
+ public function plugin_url( $path = null ) {
180
+ return untrailingslashit( plugins_url( is_null( $path ) ? '/' : $path, PW_FILE ) );
181
+ }
182
 
183
+ public function get_options( $option_name = null, $default = false ) {
184
 
185
+ if ( is_null( $option_name ) ) {
186
+ return $this->options;
 
 
 
 
187
  }
188
 
189
+ $default_options = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
 
191
+ if ( ! empty( $this->tools ) && method_exists( $this->tools, 'get_tools_default' ) ) {
192
+ $default_options = $this->tools->get_tools_default();
193
+ }
194
+
195
+ if ( isset( $this->options[ $option_name ] ) ) {
196
+ return $this->options[ $option_name ];
197
+ } elseif ( isset( $default_options["PW_Options[$option_name]"] ) ) {
198
+ return $default_options["PW_Options[$option_name]"];
199
+ } else {
200
+ return $default;
201
  }
202
  }
203
+
204
+ }
205
 
206
  if ( ! class_exists( 'Persian_Woocommerce_Plugin' ) ) {
207
  class Persian_Woocommerce_Plugin extends Persian_Woocommerce_Core {
include/class-currencies.php CHANGED
@@ -1,43 +1,41 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
-
5
- if ( ! class_exists( 'Persian_Woocommerce_Currencies' ) ) :
6
 
7
- class Persian_Woocommerce_Currencies extends Persian_Woocommerce_Core {
8
 
9
- public $currencies;
10
 
11
- public function __construct() {
12
 
13
- $this->currencies = array(
14
- 'IRR' => __( 'ریال', 'woocommerce' ),
15
- 'IRHR' => __( 'هزار ریال', 'woocommerce' ),
16
- 'IRT' => __( 'تومان', 'woocommerce' ),
17
- 'IRHT' => __( 'هزار تومان', 'woocommerce' )
18
- );
19
 
20
- add_filter( 'woocommerce_currencies', array( $this, 'currencies' ) );
21
- add_filter( 'woocommerce_currency_symbol', array( $this, 'currencies_symbol' ), 10, 2 );
22
- }
 
 
 
23
 
24
- public function currencies( $currencies ) {
 
 
25
 
26
- foreach ( $this->currencies as $key => $value ) {
27
- unset( $currencies[ $key ] );
28
- }
29
 
30
- return array_merge( $currencies, $this->currencies );
 
31
  }
32
 
33
- public function currencies_symbol( $currency_symbol, $currency ) {
 
34
 
35
- if ( in_array( $currency, array_keys( $this->currencies ) ) ) {
36
- return $this->currencies[ $currency ];
37
- }
38
 
39
- return $currency_symbol;
 
40
  }
 
 
41
  }
42
- endif;
43
- PW()->currencies = new Persian_Woocommerce_Currencies();
 
1
+ <?php
 
 
 
 
2
 
3
+ defined( 'ABSPATH' ) || exit;
4
 
5
+ class Persian_Woocommerce_Currencies extends Persian_Woocommerce_Core {
6
 
7
+ public $currencies;
8
 
9
+ public function __construct() {
 
 
 
 
 
10
 
11
+ $this->currencies = [
12
+ 'IRR' => __( 'ریال', 'woocommerce' ),
13
+ 'IRHR' => __( 'هزار ریال', 'woocommerce' ),
14
+ 'IRT' => __( 'تومان', 'woocommerce' ),
15
+ 'IRHT' => __( 'هزار تومان', 'woocommerce' ),
16
+ ];
17
 
18
+ add_filter( 'woocommerce_currencies', [ $this, 'currencies' ] );
19
+ add_filter( 'woocommerce_currency_symbol', [ $this, 'currencies_symbol' ], 10, 2 );
20
+ }
21
 
22
+ public function currencies( $currencies ): array {
 
 
23
 
24
+ foreach ( $this->currencies as $key => $value ) {
25
+ unset( $currencies[ $key ] );
26
  }
27
 
28
+ return array_merge( $currencies, $this->currencies );
29
+ }
30
 
31
+ public function currencies_symbol( $currency_symbol, $currency ) {
 
 
32
 
33
+ if ( in_array( $currency, array_keys( $this->currencies ) ) ) {
34
+ return $this->currencies[ $currency ];
35
  }
36
+
37
+ return $currency_symbol;
38
  }
39
+ }
40
+
41
+ new Persian_Woocommerce_Currencies();
include/class-gateways.php CHANGED
@@ -1,678 +1,691 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
-
5
- if ( ! class_exists( 'Persian_Woocommerce_Gateways' ) && class_exists( 'WC_Payment_Gateway' ) ) :
6
-
7
- abstract class Persian_Woocommerce_Gateways extends WC_Payment_Gateway {
8
-
9
- protected $order_id = 0;
10
-
11
- private $verification_params;
12
-
13
- const PREFIX = 'Woocommerce_Ir_Gateway_';
14
-
15
- public static function register( $gateway ) {
16
- add_filter( 'woocommerce_payment_gateways', function ( $methods ) use ( $gateway ) {
17
-
18
- $methods[] = self::PREFIX . $gateway;
19
-
20
- return array_unique( $methods );
21
- } );
22
- }
23
-
24
- protected function init( $gateway ) {
25
-
26
- $Gateway_Class = get_class( $gateway );
27
-
28
- if ( stripos( $Gateway_Class, self::PREFIX ) === false ) {
29
- return false;
30
- }
31
-
32
- $gateway_class = strtolower( $Gateway_Class );
33
- $gateway->id = str_ireplace( self::PREFIX, '', $gateway_class );
34
-
35
- if ( method_exists( $gateway, 'init_form_fields' ) ) {
36
- $gateway->init_form_fields();
37
- } else {
38
- $this->init_form_fields();
39
- }
40
-
41
- if ( method_exists( $gateway, 'init_settings' ) ) {
42
- $gateway->init_settings();
43
- } else {
44
- $this->init_settings();
45
- }
46
-
47
- $gateway->has_fields = false;
48
- $gateway->title = $gateway->settings['title'] ?: $gateway->method_title;
49
- $gateway->description = $gateway->settings['description'];
50
- $gateway->method_description = $gateway->method_description ?: sprintf( 'تنظیمات درگاه پرداخت %s برای افزونه فروشگاه ساز ووکامرس', $gateway->method_title );
51
-
52
- if ( empty( $gateway->icon ) && class_exists( 'ReflectionClass' ) ) {
53
- try {
54
- $file = ( new ReflectionClass( $Gateway_Class ) )->getFileName();
55
- $gateway->icon = trailingslashit( WP_PLUGIN_URL ) . plugin_basename( dirname( $file ) ) . '/assets/images/logo.png';
56
- } catch ( Exception $e ) {
57
- }
58
- }
59
-
60
- add_action( 'woocommerce_update_options_payment_gateways_' . $gateway->id,
61
- array( $gateway, 'process_admin_options' ) );
62
-
63
- add_filter( 'woocommerce_settings_api_sanitized_fields_' . $gateway->id, array(
64
- $gateway,
65
- 'unsanitie_fields'
66
- ) );
67
-
68
- add_action( 'woocommerce_receipt_' . $gateway->id,
69
- array( $gateway, 'process_payment_request' ) );
70
-
71
- add_action( 'woocommerce_api_' . $gateway_class,
72
- array( $gateway, 'process_payment_verify' ) );
73
- }
74
-
75
- public function unsanitie_fields( $fields ) {
76
-
77
- $unsanitie_fields = array();
78
- foreach ( (array) $fields as $key => $value ) {
79
- if ( substr( $key, - 3 ) == '___' ) {
80
- $unsanitie_fields[] = $key;
81
- }
82
- }
83
-
84
- if ( ! empty( $unsanitie_fields ) ) {
85
- foreach ( $_POST as $key => $value ) {
86
- foreach ( $unsanitie_fields as $item ) {
87
- if ( stripos( $key, $item ) !== false ) {
88
- $fields[ $item ] = trim( $value );
89
- }
90
- }
91
- }
92
- }
93
-
94
- return $fields;
95
- }
96
-
97
- public function init_form_fields() {
98
-
99
- $main = array(
100
- 'enabled' => array(
101
- 'title' => 'فعالسازی',
102
- 'type' => 'checkbox',
103
- 'label' => 'فعالسازی درگاه',
104
- 'description' => 'برای فعالسازی این درگاه پرداخت باید چک باکس را تیک بزنید',
105
- 'default' => 'yes',
106
- 'desc_tip' => true,
107
- ),
108
- 'title' => array(
109
- 'title' => 'عنوان درگاه',
110
- 'type' => 'text',
111
- 'description' => 'عنوان این درگاه که در طی خرید به مشتری نمایش داده میشود',
112
- 'default' => $this->method_title,
113
- 'desc_tip' => true,
114
- ),
115
- 'description' => array(
116
- 'title' => 'توضیحات درگاه',
117
- 'type' => 'text',
118
- 'desc_tip' => true,
119
- 'description' => 'توضیحاتی که در طی عملیات پرداخت برای این درگاه نمایش داده خواهد شد',
120
- 'default' => sprintf( 'پرداخت امن به وسیله کلیه کارت های عضو شتاب از طریق درگاه %s', $this->method_title )
121
- ),
122
- 'direct_redirect' => array(
123
- 'title' => 'هدایت مستقیم به درگاه',
124
- 'type' => 'checkbox',
125
- 'label' => 'در صورتی که قصد دارید کاربر مستقیما به درگاه هدایت شود و در صفحه پیشفاکتور گزینه پرداحت را کلیک نکند، این گزینه را فعال نمایید.',
126
- 'description' => 'به صورت پیشفرض (غیرفعال بودن این گزینه) خریدار قبل از هدایت به درگاه ابتدا شماره سفارش و قیمت نهایی را مشاهده میکند و سپس با زدن دکمه تایید به درگاه هدایت میشود.',
127
- 'default' => 'no',
128
- 'desc_tip' => true,
129
- ),
130
- );
131
-
132
- $fields = $this->fields();
133
-
134
- $shortcodes = array();
135
- foreach ( $this->fields_shortcodes() as $shortcode => $title ) {
136
- $shortcode = '{' . trim( $shortcode, '\{\}' ) . '}';
137
- $shortcodes[] = "$shortcode:$title";
138
- }
139
- $shortcodes = '<br>' . implode( ' - ', $shortcodes );
140
-
141
- unset( $fields['shortcodes'] );
142
-
143
- $messages = array(
144
- 'completed_massage' => array(
145
- 'title' => 'پیام پرداخت موفق',
146
- 'type' => 'textarea',
147
- 'description' => 'متن پیامی که میخواهید بعد از پرداخت موفق به کاربر نمایش دهید را وارد نمایید. همچنین می توانید از شورت کدهای زیر نیز استفاده نمایید.' . $shortcodes,
148
- 'default' => 'با تشکر از شما. سفارش شما با موفقیت پرداخت شد.',
149
- ),
150
- 'failed_massage' => array(
151
- 'title' => 'پیام پرداخت ناموفق',
152
- 'type' => 'textarea',
153
- 'description' => 'متن پیامی که میخواهید بعد از پرداخت ناموفق به کاربر نمایش دهید را وارد نمایید. همچنین می توانید از شورت کد {fault} برای نمایش دلیل خطای رخ داده استفاده نمایید. این دلیل خطا از سایت درگاه ارسال میگردد.',
154
- 'default' => 'پرداخت شما ناموفق بوده است. لطفا مجددا تلاش نمایید یا در صورت بروز اشکال با مدیر سایت تماس بگیرید.',
155
- ),
156
- 'cancelled_massage' => array(
157
- 'title' => 'پیام انصراف از پرداخت',
158
- 'type' => 'textarea',
159
- 'description' => 'متن پیامی که میخواهید بعد از انصراف کاربر از پرداخت نمایش دهید را وارد نمایید. این پیام بعد از بازگشت از بانک نمایش داده خواهد شد.',
160
- 'default' => 'پرداخت به دلیل انصراف شما ناتمام باقی ماند.',
161
- ),
162
- );
163
-
164
- $this->form_fields = array_merge( $main, $fields, $messages );
165
- foreach ( array_merge( $main, $messages ) as $key => $value ) {
166
- if ( isset( $fields[ $key ] ) ) {
167
- $this->form_fields[ $key ] = $fields[ $key ];
168
- }
169
- }
170
- $this->form_fields = array_filter( $this->form_fields );
171
- }
172
-
173
- public function process_payment( $order ) {
174
-
175
- $order = $this->get_order( $order );
176
-
177
- return array(
178
- 'result' => 'success',
179
- 'redirect' => $order->get_checkout_payment_url( true )
180
- );
181
- }
182
-
183
- public function process_payment_request( $order_id ) {
184
-
185
- $this->order_id = $order_id;
186
- $this->session( 'set', 'order_id', $order_id );
187
- $order = $this->get_order( $order_id );
188
- $form = $this->option( 'direct_redirect' ) != '1';
189
-
190
- if ( $form ) {
191
- echo '<form action="" method="POST" class="pw-gateway-checkout-form" id="pw-gateway-checkout-form-' . $this->id . '">
192
- <input type="submit" name="pw-gateway-submit" class="pw-gateway-submit button alt" value="پرداخت"/>
193
- <a class="pw-gateway-cancel button cancel" href="' . $this->get_checkout_url() . '">بازگشت</a>
194
- </form><br/>';
195
- }
196
-
197
- if ( ! $form || isset( $_POST['pw-gateway-submit'] ) ) {
198
- $error = $this->request( $order );
199
- $this->set_message( 'failed', $error, true, false );
200
- $order->add_order_note( sprintf( 'در هنگام اتصال به درگاه %s خطای زیر رخ داده است.', $this->title ) . "<br>{$error}" );
201
- }
202
- }
203
-
204
- public function process_payment_verify() {
205
-
206
- $redirect = $this->get_checkout_url();
207
-
208
- $order_id = ! empty( $_GET['wc_order'] ) ? $_GET['wc_order'] : $this->session( 'get', 'order_id' );
209
- if ( empty( $order_id ) ) {
210
- $this->set_message( 'failed', 'شماره سفارش وجود ندارد.', true, $redirect );
211
- }
212
-
213
- $order = $this->get_order( $order_id );
214
-
215
- if ( ! $this->needs_payment( $order ) ) {
216
- $this->set_message( 'failed', 'وضعیت تراکنش قبلا مشخص شده است.', true, $redirect, true );
217
- }
218
-
219
- $this->order_id = $order_id;
220
-
221
- $result = $this->verify( $order );
222
-
223
- if ( ! is_array( $result ) ) {
224
- $error = is_string( $result ) && strlen( $result ) > 5 ? $result : 'اطلاعات صحت سنجی تراکنش صحیح نیست.';
225
- $this->set_message( 'failed', $error, true, $redirect, true );
226
- }
227
-
228
- $error = '';
229
- $status = ! empty( $result['status'] ) ? $result['status'] : '';
230
- $transaction_id = ! empty( $result['transaction_id'] ) ? $result['transaction_id'] : '';
231
-
232
- if ( $status == 'completed' ) {
233
-
234
- $redirect = $this->get_return_url( $order );
235
-
236
- $order->payment_complete( $transaction_id );
237
- $this->empty_cart();
238
- $this->set_verification();
239
-
240
- $shortcodes = $this->get_shortcodes_values();
241
- $note = array( 'تراکنش موفق بود.' );
242
- foreach ( $this->fields_shortcodes() as $key => $value ) {
243
- $key = trim( $key, '\{\}' );
244
- $note[] = "$value : {$shortcodes[$key]}";
245
- }
246
- $order->add_order_note( implode( "<br>", $note ), 1 );
247
-
248
- } elseif ( $status == 'cancelled' ) {
249
- $order->add_order_note( 'تراکنش به بعلت انصراف کاربر ناتمام باقی ماند.', 1 );
250
- } else {
251
- $error = ! empty( $result['error'] ) ? $result['error'] : 'در حین پرداخت خطایی رخ داده است.';
252
- $order->add_order_note( sprintf( 'در هنگام بازگشت از درگاه %s خطای زیر رخ داده است.', $this->title ) . "<br>{$error}", 1 );
253
- }
254
-
255
- $this->set_message( $status, $error, true, $redirect );
256
- exit;
257
- }
258
-
259
- /*
260
- * ---------------------------------------------------
261
- * */
262
- protected function order_id( $order ) {
263
-
264
- if ( is_numeric( $order ) ) {
265
- $order_id = $order;
266
- } elseif ( method_exists( $order, 'get_id' ) ) {
267
- $order_id = $order->get_id();
268
- } elseif ( ! ( $order_id = absint( get_query_var( 'order-pay' ) ) ) ) {
269
- $order_id = $order->id;
270
- }
271
-
272
- if ( ! empty( $order_id ) ) {
273
- $this->order_id = $order_id;
274
- }
275
-
276
- return $order_id;
277
- }
278
-
279
- protected function get_order( $order = 0 ) {
280
-
281
- if ( empty( $order ) ) {
282
- $order = $this->order_id;
283
- }
284
-
285
- if ( empty( $order ) ) {
286
- return (object) array();
287
- }
288
-
289
- if ( is_numeric( $order ) ) {
290
- $this->order_id = $order;
291
-
292
- $order = new WC_Order( $order );
293
- }
294
-
295
- return $order;
296
- }
297
-
298
- protected function get_order_props( $prop, $default = '' ) {
299
-
300
- if ( empty( $this->order_id ) ) {
301
- return '';
302
- }
303
-
304
- $order = $this->get_order();
305
-
306
- $method = 'get_' . $prop;
307
-
308
- if ( method_exists( $order, $method ) ) {
309
- $prop = $order->$method();
310
- } elseif ( ! empty( $order->{$prop} ) ) {
311
- $prop = $order->{$prop};
312
- } else {
313
- $prop = '';
314
- }
315
-
316
- return ! empty( $prop ) ? $prop : $default;
317
- }
318
-
319
- protected function get_order_items( $product = false ) {
320
-
321
- if ( empty( $this->order_id ) ) {
322
- return array();
323
- }
324
-
325
- $order = $this->get_order();
326
- $items = $order->get_items();
327
-
328
- if ( $product ) {
329
- $products = array();
330
- foreach ( (array) $items as $item ) {
331
- $products[] = $item['name'] . ' (' . $item['qty'] . ') ';
332
- }
333
-
334
- return implode( ' - ', $products );
335
- }
336
-
337
- return $items;
338
- }
339
-
340
- protected function get_order_mobile() {
341
-
342
- $Mobile = $this->get_order_props( 'billing_phone' );
343
- $Mobile = $this->get_order_props( 'billing_mobile', $Mobile );
344
-
345
- $Mobile = str_ireplace( array( '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ),
346
- array( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ), $Mobile ); //farsi
347
-
348
- $Mobile = str_ireplace( array( '٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩' ),
349
- array( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ), $Mobile ); //arabi
350
-
351
- $Mobile = preg_replace( '/\D/is', '', $Mobile );
352
- $Mobile = ltrim( $Mobile, '0' );
353
- $Mobile = substr( $Mobile, 0, 2 ) == '98' ? substr( $Mobile, 2 ) : $Mobile;
354
-
355
- return '0' . $Mobile;
356
- }
357
-
358
- protected function get_currency() {
359
-
360
- if ( empty( $this->order_id ) ) {
361
- return '';
362
- }
363
-
364
- $order = $this->get_order();
365
-
366
- $currency = method_exists( $order, 'get_currency' ) ? $order->get_currency() : $order->get_order_currency();
367
-
368
- $irt = array( 'irt', 'toman', 'tomaan', 'iran toman', 'iranian toman', 'تومان', 'تومان ایران' );
369
- if ( in_array( strtolower( $currency ), $irt ) ) {
370
- $currency = 'IRT';
371
- }
372
-
373
- $irr = array( 'irr', 'rial', 'iran rial', 'iranian rial', 'ریال', 'ریال ایران' );
374
- if ( in_array( strtolower( $currency ), $irr ) ) {
375
- $currency = 'IRR';
376
- }
377
-
378
- return $currency;
379
- }
380
-
381
- protected function get_total( $to_currency = 'IRR' ) {
382
-
383
- if ( empty( $this->order_id ) ) {
384
- return 0;
385
- }
386
-
387
- $order = $this->get_order();
388
-
389
- if ( method_exists( $order, 'get_total' ) ) {
390
- $price = $order->get_total();
391
- } else {
392
- $price = intval( $order->order_total );
393
- }
394
-
395
- $currency = strtoupper( $this->get_currency() );
396
- $to_currency = strtoupper( $to_currency );
397
-
398
- if ( in_array( $currency, array( 'IRHR', 'IRHT' ) ) ) {
399
- $currency = str_ireplace( 'H', '', $currency );
400
- $price *= 1000;
401
- }
402
-
403
- if ( $currency == 'IRR' && $to_currency == 'IRT' ) {
404
- $price /= 10;
405
- }
406
-
407
- if ( $currency == 'IRT' && $to_currency == 'IRR' ) {
408
- $price *= 10;
409
- }
410
-
411
- return $price;
412
- }
413
-
414
- protected function needs_payment( $order = 0 ) {
415
-
416
- if ( empty( $order ) && empty( $this->order_id ) ) {
417
- return true;
418
- }
419
-
420
- $order = $this->get_order( $order );
421
-
422
- if ( method_exists( $order, 'needs_payment' ) ) {
423
- return $order->needs_payment();
424
- }
425
-
426
- if ( empty( $this->order_id ) && ! empty( $order ) ) {
427
- $this->order_id = $this->order_id( $order );
428
- }
429
-
430
- return ! in_array( $this->get_order_props( 'status' ), array( 'completed', 'processing' ) );
431
- }
432
-
433
- protected function get_verify_url() {
434
- return add_query_arg( 'wc_order', $this->order_id, WC()->api_request_url( get_class( $this ) ) );
435
- }
436
-
437
- protected function get_checkout_url() {
438
- if ( function_exists( 'wc_get_checkout_url' ) ) {
439
- return wc_get_checkout_url();
440
- } else {
441
- global $woocommerce;
442
-
443
- return $woocommerce->cart->get_checkout_url();
444
- }
445
- }
446
-
447
- protected function empty_cart() {
448
- if ( function_exists( 'wc_empty_cart' ) ) {
449
- wc_empty_cart();
450
- } elseif ( function_exists( 'WC' ) && ! empty( WC()->cart ) && method_exists( WC()->cart, 'empty_cart' ) ) {
451
- WC()->cart->empty_cart();
452
- } else {
453
- global $woocommerce;
454
- $woocommerce->cart->empty_cart();
455
- }
456
- }
457
-
458
- protected function fields_shortcodes( $fields = array() ) {
459
-
460
- $fields = ! empty( $fields ) ? $fields : $this->fields();
461
-
462
- return ! empty( $fields['shortcodes'] ) && is_array( $fields['shortcodes'] ) ? $fields['shortcodes'] : array();
463
- }
464
-
465
- protected function get_shortcodes_values() {
466
-
467
- $shortcodes = array();
468
- foreach ( $this->fields_shortcodes() as $key => $value ) {
469
- $key = trim( $key, '\{\}' );
470
- $shortcodes[ $key ] = get_post_meta( $this->order_id, '_' . $key, true );
471
- }
472
-
473
- return $shortcodes;
474
- }
475
-
476
- protected function set_shortcodes( $shortcodes ) {
477
-
478
- $fields_shortcodes = $this->fields_shortcodes();
479
-
480
- foreach ( $shortcodes as $key => $value ) {
481
-
482
- if ( is_numeric( $key ) ) {
483
- $key = $fields_shortcodes[ $key ];
484
- }
485
-
486
- if ( ! empty( $key ) && ! is_array( $key ) ) {
487
- $key = trim( $key, '\{\}' );
488
- update_post_meta( $this->order_id, '_' . $key, $value );
489
- }
490
- }
491
- }
492
-
493
- protected function set_message( $status, $error = '', $notice = true, $redirect = false, $failed_note = false ) {
494
-
495
- if ( ! in_array( $status, array( 'completed', 'cancelled', 'failed' ) ) ) {
496
- $status = 'failed';
497
- }
498
-
499
- if ( ! empty( $error ) && $failed_note && ( $order = $this->get_order() ) && ! empty( $order ) ) {
500
- $order->add_order_note( 'خطا: ' . $error, 1 );
501
- }
502
-
503
- $shortcodes = array_merge( $this->get_shortcodes_values(), array( '{fault}' => $error ) );
504
-
505
- $message = $this->option( $status . '_massage' );
506
- $find = array_map( function ( $value ) {
507
- return '{' . trim( $value, '\{\}' ) . '}';
508
- }, array_keys( $shortcodes ) );
509
- $message = str_ireplace( $find, array_values( $shortcodes ), $message );
510
- $message = wpautop( wptexturize( trim( $message ) ) );
511
-
512
- if ( $notice ) {
513
- wc_add_notice( $message, $status == 'completed' ? 'success' : 'error' );
514
- }
515
-
516
- if ( $redirect ) {
517
- wp_redirect( $redirect );
518
- exit;
519
- }
520
-
521
- return $message;
522
- }
523
-
524
- protected function check_verification( $params ) {
525
-
526
- if ( function_exists( 'func_get_args' ) ) {
527
- $args = func_get_args();
528
- if ( count( $args ) > 1 ) {
529
- $params = array_merge( array_values( $args ), $params );
530
- $params = implode( '_', array_unique( $params ) );
531
- }
532
- }
533
-
534
- if ( is_array( $params ) ) {
535
- $params = implode( '_', $params );
536
- }
537
- $params = $this->id . '_' . $params;
538
-
539
- global $wpdb;
540
- $query = "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key='_verification_params' AND meta_value='%s'";
541
- $check = $wpdb->get_row( $wpdb->prepare( $query, $params ) );
542
- if ( ! empty( $check ) ) {
543
- return $this->set_message( 'failed', 'این تراکنش قبلا یکبار وریفای شده بود.', true, $this->get_checkout_url(), true );
544
- }
545
- $this->verification_params = $params;
546
- }
547
-
548
- protected function set_verification() {
549
- if ( ! empty( $this->verification_params ) ) {
550
- update_post_meta( $this->order_id, '_verification_params', $this->verification_params );
551
- }
552
- }
553
-
554
- /*
555
- * Helpers
556
- * */
557
- protected function option( $name ) {
558
-
559
- $option = '';
560
- if ( method_exists( $this, 'get_option' ) ) {
561
- $option = $this->get_option( $name );
562
- } elseif ( ! empty( $this->settings[ $name ] ) ) {
563
- $option = $this->settings[ $name ];
564
- }
565
-
566
- if ( in_array( strtolower( $option ), array( 'yes', 'on', 'true' ) ) ) {
567
- $option = '1';
568
- }
569
- if ( in_array( strtolower( $option ), array( 'no', 'off', 'false' ) ) ) {
570
- $option = false;
571
- }
572
-
573
- return $option;
574
- }
575
-
576
- protected function get( $name, $default = '' ) {
577
- return ! empty( $_GET[ $name ] ) ? sanitize_text_field( $_GET[ $name ] ) : $default;
578
- }
579
-
580
- protected function post( $name, $default = '' ) {
581
- return ! empty( $_POST[ $name ] ) ? sanitize_text_field( $_POST[ $name ] ) : $default;
582
- }
583
-
584
- protected function store_date( $key, $value ) {
585
- $this->session( 'set', $key, $value );
586
- update_post_meta( $this->order_id, '_' . $this->id . '_' . $key, $value );
587
- }
588
-
589
- protected function get_stored( $key ) {
590
-
591
- $value = get_post_meta( $this->order_id, '_' . $this->id . '_' . $key, true );
592
-
593
- return ! empty( $value ) ? $value : $this->session( 'get', $key );
594
- }
595
-
596
- protected function session( $action, $name, $value = '' ) {
597
-
598
- global $woocommerce;
599
-
600
- $name = $this->id . '_' . $name;
601
-
602
- $wc_session = function_exists( 'WC' ) && ! empty( WC()->session );
603
-
604
- if ( $action == 'set' ) {
605
-
606
- if ( $wc_session && method_exists( WC()->session, 'set' ) ) {
607
- WC()->session->set( $name, $value );
608
- } else {
609
- $woocommerce->session->{$name} = $value;
610
- }
611
-
612
- } elseif ( $action == 'get' ) {
613
-
614
- if ( $wc_session && method_exists( WC()->session, 'get' ) ) {
615
- $value = WC()->session->get( $name );
616
- unset( WC()->session->{$name} );
617
- } else {
618
- $value = $woocommerce->session->{$name};
619
- unset( $woocommerce->session->{$name} );
620
- }
621
-
622
- return $value;
623
- }
624
-
625
- return '';
626
- }
627
-
628
- protected function redirect( $url ) {
629
- if ( ! headers_sent() ) {
630
- header( 'Location: ' . trim( $url ) );
631
- } else {
632
- echo "<script type='text/javascript'>window.onload = function () { top.location.href = '" . $url . "'; };</script>";
633
- }
634
- exit;
635
- }
636
-
637
- protected function submit_form( $form ) {
638
-
639
- $name = 'pw_gateway_name_' . $this->id;
640
-
641
- $form = explode( '>', $form );
642
- $form[0] = preg_replace( '/name=[\'\"].*?[\'\"]/i', '', $form[0] );
643
- $form = implode( '>', $form );
644
- $form = str_ireplace( "<form", "<form name=\"{$name}\"", $form );
645
-
646
- echo 'در حال هدایت به درگاه ....';
647
- $function = "document.{$name}.submit();";
648
- if ( headers_sent() ) {
649
- $script = "<script type=\"text/javascript\">function PWformSubmit(){ $function } PWformSubmit();";
650
- $script .= $function;
651
- $script .= "</script>";
652
- echo $script . $form;
653
- } else {
654
- $script = "<script type=\"text/javascript\">$function</script>";
655
- echo $form . $script;
656
- }
657
- die();
658
- }
659
-
660
- protected function nusoap() {
661
- if ( ! class_exists( 'nusoap_client' ) ) {
662
- include_once( 'lib/nusoap.php' );
663
- }
664
- }
665
-
666
- /*
667
- * Abstract methods and must be override
668
- * */
669
-
670
- abstract protected function fields();
671
-
672
- abstract protected function request( $order );
673
-
674
- abstract protected function verify( $order );
675
-
676
- }
677
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
678
  include 'gateways/class-payir.php';
1
+ <?php
2
+
3
+ defined( 'ABSPATH' ) || exit;
4
+
5
+ if ( ! class_exists( 'Persian_Woocommerce_Gateways' ) && class_exists( 'WC_Payment_Gateway' ) ) :
6
+
7
+ abstract class Persian_Woocommerce_Gateways extends WC_Payment_Gateway {
8
+
9
+ protected $order_id = 0;
10
+
11
+ private $verification_params;
12
+
13
+ const PREFIX = 'Woocommerce_Ir_Gateway_';
14
+
15
+ public static function register( $gateway ) {
16
+ add_filter( 'woocommerce_payment_gateways', function ( $methods ) use ( $gateway ) {
17
+
18
+ $methods[] = self::PREFIX . $gateway;
19
+
20
+ return $methods;
21
+ } );
22
+ }
23
+
24
+ protected function init( $gateway ) {
25
+
26
+ $Gateway_Class = get_class( $gateway );
27
+
28
+ if ( stripos( $Gateway_Class, self::PREFIX ) === false ) {
29
+ return false;
30
+ }
31
+
32
+ $gateway_class = strtolower( $Gateway_Class );
33
+ $gateway->id = str_ireplace( self::PREFIX, '', $gateway_class );
34
+
35
+ if ( method_exists( $gateway, 'init_form_fields' ) ) {
36
+ $gateway->init_form_fields();
37
+ } else {
38
+ $this->init_form_fields();
39
+ }
40
+
41
+ if ( method_exists( $gateway, 'init_settings' ) ) {
42
+ $gateway->init_settings();
43
+ } else {
44
+ $this->init_settings();
45
+ }
46
+
47
+ $gateway->has_fields = false;
48
+ $gateway->title = $gateway->settings['title'] ?: $gateway->method_title;
49
+ $gateway->description = $gateway->settings['description'];
50
+ $gateway->method_description = $gateway->method_description ?: sprintf( 'تنظیمات درگاه پرداخت %s برای افزونه فروشگاه ساز ووکامرس', $gateway->method_title );
51
+
52
+ if ( empty( $gateway->icon ) && class_exists( 'ReflectionClass' ) ) {
53
+ try {
54
+ $file = ( new ReflectionClass( $Gateway_Class ) )->getFileName();
55
+ $gateway->icon = trailingslashit( WP_PLUGIN_URL ) . plugin_basename( dirname( $file ) ) . '/assets/images/logo.png';
56
+ } catch ( Exception $e ) {
57
+ }
58
+ }
59
+
60
+ add_action( 'woocommerce_update_options_payment_gateways_' . $gateway->id,
61
+ [ $gateway, 'process_admin_options' ] );
62
+
63
+ add_filter( 'woocommerce_settings_api_sanitized_fields_' . $gateway->id, [
64
+ $gateway,
65
+ 'unsanitie_fields',
66
+ ] );
67
+
68
+ add_action( 'woocommerce_receipt_' . $gateway->id,
69
+ [ $gateway, 'process_payment_request' ] );
70
+
71
+ add_action( 'woocommerce_api_' . $gateway_class,
72
+ [ $gateway, 'process_payment_verify' ] );
73
+ }
74
+
75
+ public function unsanitie_fields( $fields ) {
76
+
77
+ $unsanitie_fields = [];
78
+ foreach ( (array) $fields as $key => $value ) {
79
+ if ( substr( $key, - 3 ) == '___' ) {
80
+ $unsanitie_fields[] = $key;
81
+ }
82
+ }
83
+
84
+ if ( ! empty( $unsanitie_fields ) ) {
85
+ foreach ( $_POST as $key => $value ) {
86
+ foreach ( $unsanitie_fields as $item ) {
87
+ if ( stripos( $key, $item ) !== false ) {
88
+ $fields[ $item ] = trim( $value );
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ return $fields;
95
+ }
96
+
97
+ public function init_form_fields() {
98
+
99
+ $main = [
100
+ 'enabled' => [
101
+ 'title' => 'فعالسازی',
102
+ 'type' => 'checkbox',
103
+ 'label' => 'فعالسازی درگاه',
104
+ 'description' => 'برای فعالسازی این درگاه پرداخت باید چک باکس را تیک بزنید',
105
+ 'default' => 'yes',
106
+ 'desc_tip' => true,
107
+ ],
108
+ 'title' => [
109
+ 'title' => 'عنوان درگاه',
110
+ 'type' => 'text',
111
+ 'description' => 'عنوان این درگاه که در طی خرید به مشتری نمایش داده میشود',
112
+ 'default' => $this->method_title,
113
+ 'desc_tip' => true,
114
+ ],
115
+ 'description' => [
116
+ 'title' => 'توضیحات درگاه',
117
+ 'type' => 'text',
118
+ 'desc_tip' => true,
119
+ 'description' => 'توضیحاتی که در طی عملیات پرداخت برای این درگاه نمایش داده خواهد شد',
120
+ 'default' => sprintf( 'پرداخت امن به وسیله کلیه کارت های عضو شتاب از طریق درگاه %s', $this->method_title ),
121
+ ],
122
+ 'direct_redirect' => [
123
+ 'title' => 'هدایت مستقیم به درگاه',
124
+ 'type' => 'checkbox',
125
+ 'label' => 'در صورتی که قصد دارید کاربر مستقیما به درگاه هدایت شود و در صفحه پیشفاکتور گزینه پرداحت را کلیک نکند، این گزینه را فعال نمایید.',
126
+ 'description' => 'به صورت پیشفرض (غیرفعال بودن این گزینه) خریدار قبل از هدایت به درگاه ابتدا شماره سفارش و قیمت نهایی را مشاهده میکند و سپس با زدن دکمه تایید به درگاه هدایت میشود.',
127
+ 'default' => 'no',
128
+ 'desc_tip' => true,
129
+ ],
130
+ ];
131
+
132
+ $fields = $this->fields();
133
+
134
+ $shortcodes = [];
135
+ foreach ( $this->fields_shortcodes() as $shortcode => $title ) {
136
+ $shortcode = '{' . trim( $shortcode, '\{\}' ) . '}';
137
+ $shortcodes[] = "$shortcode:$title";
138
+ }
139
+ $shortcodes = '<br>' . implode( ' - ', $shortcodes );
140
+
141
+ unset( $fields['shortcodes'] );
142
+
143
+ $messages = [
144
+ 'completed_massage' => [
145
+ 'title' => 'پیام پرداخت موفق',
146
+ 'type' => 'textarea',
147
+ 'description' => 'متن پیامی که میخواهید بعد از پرداخت موفق به کاربر نمایش دهید را وارد نمایید. همچنین می توانید از شورت کدهای زیر نیز استفاده نمایید.' . $shortcodes,
148
+ 'default' => 'با تشکر از شما. سفارش شما با موفقیت پرداخت شد.',
149
+ ],
150
+ 'failed_massage' => [
151
+ 'title' => 'پیام پرداخت ناموفق',
152
+ 'type' => 'textarea',
153
+ 'description' => 'متن پیامی که میخواهید بعد از پرداخت ناموفق به کاربر نمایش دهید را وارد نمایید. همچنین می توانید از شورت کد {fault} برای نمایش دلیل خطای رخ داده استفاده نمایید. این دلیل خطا از سایت درگاه ارسال میگردد.',
154
+ 'default' => 'پرداخت شما ناموفق بوده است. لطفا مجددا تلاش نمایید یا در صورت بروز اشکال با مدیر سایت تماس بگیرید.',
155
+ ],
156
+ 'cancelled_massage' => [
157
+ 'title' => 'پیام انصراف از پرداخت',
158
+ 'type' => 'textarea',
159
+ 'description' => 'متن پیامی که میخواهید بعد از انصراف کاربر از پرداخت نمایش دهید را وارد نمایید. این پیام بعد از بازگشت از بانک نمایش داده خواهد شد.',
160
+ 'default' => 'پرداخت به دلیل انصراف شما ناتمام باقی ماند.',
161
+ ],
162
+ ];
163
+
164
+ $this->form_fields = array_merge( $main, $fields, $messages );
165
+ foreach ( array_merge( $main, $messages ) as $key => $value ) {
166
+ if ( isset( $fields[ $key ] ) ) {
167
+ $this->form_fields[ $key ] = $fields[ $key ];
168
+ }
169
+ }
170
+ $this->form_fields = array_filter( $this->form_fields );
171
+ }
172
+
173
+ public function process_payment( $order ) {
174
+
175
+ $order = $this->get_order( $order );
176
+
177
+ return [
178
+ 'result' => 'success',
179
+ 'redirect' => $order->get_checkout_payment_url( true ),
180
+ ];
181
+ }
182
+
183
+ public function process_payment_request( $order_id ) {
184
+
185
+ $this->order_id = $order_id;
186
+ $this->session( 'set', 'order_id', $order_id );
187
+ $order = $this->get_order( $order_id );
188
+ $form = $this->option( 'direct_redirect' ) != '1';
189
+
190
+ if ( $form ) {
191
+ $globalpaymentform = '<form action="" method="POST" class="pw-gateway-checkout-form" id="pw-gateway-checkout-form-' . $this->id . '">
192
+ <input type="submit" name="pw-gateway-submit" class="pw-gateway-submit button alt" value="پرداخت"/>
193
+ <a class="pw-gateway-cancel button cancel" href="' . $this->get_checkout_url() . '">بازگشت</a>
194
+ </form><br/>';
195
+
196
+ echo wp_kses($globalpaymentform,array(
197
+ 'form'=>array('action','method','class','id'),
198
+ 'input'=>array('type','name','class','value'),
199
+ 'a'=>array('class','href')
200
+
201
+ ));
202
+ }
203
+
204
+ if ( ! $form || isset( $_POST['pw-gateway-submit'] ) ) {
205
+ $error = $this->request( $order );
206
+ $this->set_message( 'failed', $error, true, false );
207
+ $order->add_order_note( sprintf( 'در هنگام اتصال به درگاه %s خطای زیر رخ داده است.', $this->title ) . "<br>{$error}" );
208
+ }
209
+ }
210
+
211
+ public function process_payment_verify() {
212
+
213
+ $redirect = $this->get_checkout_url();
214
+
215
+ $order_id = ! empty( $_GET['wc_order'] ) ? intval( $_GET['wc_order'] ) : $this->session( 'get', 'order_id' );
216
+
217
+ if ( empty( $order_id ) ) {
218
+ $this->set_message( 'failed', 'شماره سفارش وجود ندارد.', true, $redirect );
219
+ }
220
+
221
+ $order = $this->get_order( $order_id );
222
+
223
+ if ( ! $this->needs_payment( $order ) ) {
224
+ $this->set_message( 'failed', 'وضعیت تراکنش قبلا مشخص شده است.', true, $redirect, true );
225
+ }
226
+
227
+ $this->order_id = $order_id;
228
+
229
+ $result = $this->verify( $order );
230
+
231
+ if ( ! is_array( $result ) ) {
232
+ $error = is_string( $result ) && strlen( $result ) > 5 ? $result : 'اطلاعات صحت سنجی تراکنش صحیح نیست.';
233
+ $this->set_message( 'failed', $error, true, $redirect, true );
234
+ }
235
+
236
+ $error = '';
237
+ $status = ! empty( $result['status'] ) ? $result['status'] : '';
238
+ $transaction_id = ! empty( $result['transaction_id'] ) ? $result['transaction_id'] : '';
239
+
240
+ if ( $status == 'completed' ) {
241
+
242
+ $redirect = $this->get_return_url( $order );
243
+
244
+ $order->payment_complete( $transaction_id );
245
+ $this->empty_cart();
246
+ $this->set_verification();
247
+
248
+ $shortcodes = $this->get_shortcodes_values();
249
+ $note = [ 'تراکنش موفق بود.' ];
250
+ foreach ( $this->fields_shortcodes() as $key => $value ) {
251
+ $key = trim( $key, '\{\}' );
252
+ $note[] = "$value : {$shortcodes[$key]}";
253
+ }
254
+ $order->add_order_note( implode( "<br>", $note ), 1 );
255
+
256
+ } elseif ( $status == 'cancelled' ) {
257
+ $order->add_order_note( 'تراکنش به بعلت انصراف کاربر ناتمام باقی ماند.', 1 );
258
+ } else {
259
+ $error = ! empty( $result['error'] ) ? $result['error'] : 'در حین پرداخت خطایی رخ داده است.';
260
+ $order->add_order_note( sprintf( 'در هنگام بازگشت از درگاه %s خطای زیر رخ داده است.', $this->title ) . "<br>{$error}", 1 );
261
+ }
262
+
263
+ $this->set_message( $status, $error, true, $redirect );
264
+ exit;
265
+ }
266
+
267
+ /*
268
+ * ---------------------------------------------------
269
+ * */
270
+ protected function order_id( $order ) {
271
+
272
+ if ( is_numeric( $order ) ) {
273
+ $order_id = $order;
274
+ } elseif ( method_exists( $order, 'get_id' ) ) {
275
+ $order_id = $order->get_id();
276
+ } elseif ( ! ( $order_id = absint( get_query_var( 'order-pay' ) ) ) ) {
277
+ $order_id = $order->id;
278
+ }
279
+
280
+ if ( ! empty( $order_id ) ) {
281
+ $this->order_id = $order_id;
282
+ }
283
+
284
+ return $order_id;
285
+ }
286
+
287
+ protected function get_order( $order = 0 ) {
288
+
289
+ if ( empty( $order ) ) {
290
+ $order = $this->order_id;
291
+ }
292
+
293
+ if ( empty( $order ) ) {
294
+ return (object) [];
295
+ }
296
+
297
+ if ( is_numeric( $order ) ) {
298
+ $this->order_id = $order;
299
+
300
+ $order = new WC_Order( $order );
301
+ }
302
+
303
+ return $order;
304
+ }
305
+
306
+ protected function get_order_props( $prop, $default = '' ) {
307
+
308
+ if ( empty( $this->order_id ) ) {
309
+ return '';
310
+ }
311
+
312
+ $order = $this->get_order();
313
+
314
+ $method = 'get_' . $prop;
315
+
316
+ if ( method_exists( $order, $method ) ) {
317
+ $prop = $order->$method();
318
+ } elseif ( ! empty( $order->{$prop} ) ) {
319
+ $prop = $order->{$prop};
320
+ } else {
321
+ $prop = '';
322
+ }
323
+
324
+ return ! empty( $prop ) ? $prop : $default;
325
+ }
326
+
327
+ protected function get_order_items( $product = false ) {
328
+
329
+ if ( empty( $this->order_id ) ) {
330
+ return [];
331
+ }
332
+
333
+ $order = $this->get_order();
334
+ $items = $order->get_items();
335
+
336
+ if ( $product ) {
337
+ $products = [];
338
+ foreach ( (array) $items as $item ) {
339
+ $products[] = $item['name'] . ' (' . $item['qty'] . ') ';
340
+ }
341
+
342
+ return implode( ' - ', $products );
343
+ }
344
+
345
+ return $items;
346
+ }
347
+
348
+ protected function get_order_mobile() {
349
+
350
+ $Mobile = $this->get_order_props( 'billing_phone' );
351
+ $Mobile = $this->get_order_props( 'billing_mobile', $Mobile );
352
+
353
+ $Mobile = str_ireplace( [ '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ],
354
+ [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ], $Mobile ); //farsi
355
+
356
+ $Mobile = str_ireplace( [ '٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩' ],
357
+ [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ], $Mobile ); //arabi
358
+
359
+ $Mobile = preg_replace( '/\D/is', '', $Mobile );
360
+ $Mobile = ltrim( $Mobile, '0' );
361
+ $Mobile = substr( $Mobile, 0, 2 ) == '98' ? substr( $Mobile, 2 ) : $Mobile;
362
+
363
+ return '0' . $Mobile;
364
+ }
365
+
366
+ protected function get_currency() {
367
+
368
+ if ( empty( $this->order_id ) ) {
369
+ return '';
370
+ }
371
+
372
+ $order = $this->get_order();
373
+
374
+ $currency = method_exists( $order, 'get_currency' ) ? $order->get_currency() : $order->get_order_currency();
375
+
376
+ $irt = [ 'irt', 'toman', 'tomaan', 'iran toman', 'iranian toman', 'تومان', 'تومان ایران' ];
377
+ if ( in_array( strtolower( $currency ), $irt ) ) {
378
+ $currency = 'IRT';
379
+ }
380
+
381
+ $irr = [ 'irr', 'rial', 'iran rial', 'iranian rial', 'ریال', 'ریال ایران' ];
382
+ if ( in_array( strtolower( $currency ), $irr ) ) {
383
+ $currency = 'IRR';
384
+ }
385
+
386
+ return $currency;
387
+ }
388
+
389
+ protected function get_total( $to_currency = 'IRR' ) {
390
+
391
+ if ( empty( $this->order_id ) ) {
392
+ return 0;
393
+ }
394
+
395
+ $order = $this->get_order();
396
+
397
+ if ( method_exists( $order, 'get_total' ) ) {
398
+ $price = $order->get_total();
399
+ } else {
400
+ $price = intval( $order->order_total );
401
+ }
402
+
403
+ $currency = strtoupper( $this->get_currency() );
404
+ $to_currency = strtoupper( $to_currency );
405
+
406
+ if ( in_array( $currency, [ 'IRHR', 'IRHT' ] ) ) {
407
+ $currency = str_ireplace( 'H', '', $currency );
408
+ $price *= 1000;
409
+ }
410
+
411
+ if ( $currency == 'IRR' && $to_currency == 'IRT' ) {
412
+ $price /= 10;
413
+ }
414
+
415
+ if ( $currency == 'IRT' && $to_currency == 'IRR' ) {
416
+ $price *= 10;
417
+ }
418
+
419
+ return $price;
420
+ }
421
+
422
+ protected function needs_payment( $order = 0 ) {
423
+
424
+ if ( empty( $order ) && empty( $this->order_id ) ) {
425
+ return true;
426
+ }
427
+
428
+ $order = $this->get_order( $order );
429
+
430
+ if ( method_exists( $order, 'needs_payment' ) ) {
431
+ return $order->needs_payment();
432
+ }
433
+
434
+ if ( empty( $this->order_id ) && ! empty( $order ) ) {
435
+ $this->order_id = $this->order_id( $order );
436
+ }
437
+
438
+ return ! in_array( $this->get_order_props( 'status' ), [ 'completed', 'processing' ] );
439
+ }
440
+
441
+ protected function get_verify_url() {
442
+ return add_query_arg( 'wc_order', $this->order_id, WC()->api_request_url( get_class( $this ) ) );
443
+ }
444
+
445
+ protected function get_checkout_url() {
446
+ if ( function_exists( 'wc_get_checkout_url' ) ) {
447
+ return wc_get_checkout_url();
448
+ } else {
449
+ global $woocommerce;
450
+
451
+ return $woocommerce->cart->get_checkout_url();
452
+ }
453
+ }
454
+
455
+ protected function empty_cart() {
456
+ if ( function_exists( 'wc_empty_cart' ) ) {
457
+ wc_empty_cart();
458
+ } elseif ( function_exists( 'WC' ) && ! empty( WC()->cart ) && method_exists( WC()->cart, 'empty_cart' ) ) {
459
+ WC()->cart->empty_cart();
460
+ } else {
461
+ global $woocommerce;
462
+ $woocommerce->cart->empty_cart();
463
+ }
464
+ }
465
+
466
+ protected function fields_shortcodes( $fields = [] ) {
467
+
468
+ $fields = ! empty( $fields ) ? $fields : $this->fields();
469
+
470
+ return ! empty( $fields['shortcodes'] ) && is_array( $fields['shortcodes'] ) ? $fields['shortcodes'] : [];
471
+ }
472
+
473
+ protected function get_shortcodes_values() {
474
+
475
+ $shortcodes = [];
476
+ foreach ( $this->fields_shortcodes() as $key => $value ) {
477
+ $key = trim( $key, '\{\}' );
478
+ $shortcodes[ $key ] = get_post_meta( $this->order_id, '_' . $key, true );
479
+ }
480
+
481
+ return $shortcodes;
482
+ }
483
+
484
+ protected function set_shortcodes( $shortcodes ) {
485
+
486
+ $fields_shortcodes = $this->fields_shortcodes();
487
+
488
+ foreach ( $shortcodes as $key => $value ) {
489
+
490
+ if ( is_numeric( $key ) ) {
491
+ $key = $fields_shortcodes[ $key ];
492
+ }
493
+
494
+ if ( ! empty( $key ) && ! is_array( $key ) ) {
495
+ $key = trim( $key, '\{\}' );
496
+ update_post_meta( $this->order_id, '_' . $key, $value );
497
+ }
498
+ }
499
+ }
500
+
501
+ protected function set_message( $status, $error = '', $notice = true, $redirect = false, $failed_note = false ) {
502
+
503
+ if ( ! in_array( $status, [ 'completed', 'cancelled', 'failed' ] ) ) {
504
+ $status = 'failed';
505
+ }
506
+
507
+ if ( ! empty( $error ) && $failed_note && ( $order = $this->get_order() ) && ! empty( $order ) ) {
508
+ $order->add_order_note( 'خطا: ' . $error, 1 );
509
+ }
510
+
511
+ $shortcodes = array_merge( $this->get_shortcodes_values(), [ '{fault}' => $error ] );
512
+
513
+ $message = $this->option( $status . '_massage' );
514
+ $find = array_map( function ( $value ) {
515
+ return '{' . trim( $value, '\{\}' ) . '}';
516
+ }, array_keys( $shortcodes ) );
517
+ $message = str_ireplace( $find, array_values( $shortcodes ), $message );
518
+ $message = wpautop( wptexturize( trim( $message ) ) );
519
+
520
+ if ( $notice ) {
521
+ wc_add_notice( $message, $status == 'completed' ? 'success' : 'error' );
522
+ }
523
+
524
+ if ( $redirect ) {
525
+ wp_redirect( $redirect );
526
+ exit;
527
+ }
528
+
529
+ return $message;
530
+ }
531
+
532
+ protected function check_verification( $params ) {
533
+
534
+ if ( function_exists( 'func_get_args' ) ) {
535
+ $args = func_get_args();
536
+ if ( count( $args ) > 1 ) {
537
+ $params = array_merge( array_values( $args ), $params );
538
+ $params = implode( '_', array_unique( $params ) );
539
+ }
540
+ }
541
+
542
+ if ( is_array( $params ) ) {
543
+ $params = implode( '_', $params );
544
+ }
545
+ $params = $this->id . '_' . $params;
546
+
547
+ global $wpdb;
548
+ $query = "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key='_verification_params' AND meta_value='%s'";
549
+ $check = $wpdb->get_row( $wpdb->prepare( $query, $params ) );
550
+ if ( ! empty( $check ) ) {
551
+ return $this->set_message( 'failed', 'این تراکنش قبلا یکبار وریفای شده بود.', true, $this->get_checkout_url(), true );
552
+ }
553
+ $this->verification_params = $params;
554
+ }
555
+
556
+ protected function set_verification() {
557
+ if ( ! empty( $this->verification_params ) ) {
558
+ update_post_meta( $this->order_id, '_verification_params', $this->verification_params );
559
+ }
560
+ }
561
+
562
+ /*
563
+ * Helpers
564
+ * */
565
+ protected function option( $name ) {
566
+
567
+ $option = '';
568
+ if ( method_exists( $this, 'get_option' ) ) {
569
+ $option = $this->get_option( $name );
570
+ } elseif ( ! empty( $this->settings[ $name ] ) ) {
571
+ $option = $this->settings[ $name ];
572
+ }
573
+
574
+ if ( in_array( strtolower( $option ), [ 'yes', 'on', 'true' ] ) ) {
575
+ $option = '1';
576
+ }
577
+ if ( in_array( strtolower( $option ), [ 'no', 'off', 'false' ] ) ) {
578
+ $option = false;
579
+ }
580
+
581
+ return $option;
582
+ }
583
+
584
+ protected function get( $name, $default = '' ) {
585
+ return ! empty( $_GET[ $name ] ) ? sanitize_text_field( $_GET[ $name ] ) : $default;
586
+ }
587
+
588
+ protected function post( $name, $default = '' ) {
589
+ return ! empty( $_POST[ $name ] ) ? sanitize_text_field( $_POST[ $name ] ) : $default;
590
+ }
591
+
592
+ protected function store_date( $key, $value ) {
593
+ $this->session( 'set', $key, $value );
594
+ update_post_meta( $this->order_id, '_' . $this->id . '_' . $key, $value );
595
+ }
596
+
597
+ protected function get_stored( $key ) {
598
+
599
+ $value = get_post_meta( $this->order_id, '_' . $this->id . '_' . $key, true );
600
+
601
+ return ! empty( $value ) ? $value : $this->session( 'get', $key );
602
+ }
603
+
604
+ protected function session( $action, $name, $value = '' ) {
605
+
606
+ global $woocommerce;
607
+
608
+ $name = $this->id . '_' . $name;
609
+
610
+ $wc_session = function_exists( 'WC' ) && ! empty( WC()->session );
611
+
612
+ if ( $action == 'set' ) {
613
+
614
+ if ( $wc_session && method_exists( WC()->session, 'set' ) ) {
615
+ WC()->session->set( $name, $value );
616
+ } else {
617
+ $woocommerce->session->{$name} = $value;
618
+ }
619
+
620
+ } elseif ( $action == 'get' ) {
621
+
622
+ if ( $wc_session && method_exists( WC()->session, 'get' ) ) {
623
+ $value = WC()->session->get( $name );
624
+ unset( WC()->session->{$name} );
625
+ } else {
626
+ $value = $woocommerce->session->{$name};
627
+ unset( $woocommerce->session->{$name} );
628
+ }
629
+
630
+ return $value;
631
+ }
632
+
633
+ return '';
634
+ }
635
+
636
+ protected function redirect( $url ) {
637
+ if ( ! headers_sent() ) {
638
+ header( 'Location: ' . trim( $url ) );
639
+ } else {
640
+ $RedirectforPay = "<script type='text/javascript'>window.onload = function () { top.location.href = '" . $url . "'; };</script>";
641
+ echo strip_tags($RedirectforPay,"<script>");
642
+ }
643
+ exit;
644
+ }
645
+
646
+ protected function submit_form( $form ) {
647
+
648
+ $name = 'pw_gateway_name_' . $this->id;
649
+
650
+ $form = explode( '>', $form );
651
+ $form[0] = preg_replace( '/name=[\'\"].*?[\'\"]/i', '', $form[0] );
652
+ $form = implode( '>', $form );
653
+ $form = str_ireplace( "<form", "<form name=\"{$name}\"", $form );
654
+
655
+ echo 'در حال هدایت به درگاه ....';
656
+ $function = "document.{$name}.submit();";
657
+ if ( headers_sent() ) {
658
+ $script = "<script type=\"text/javascript\">function PWformSubmit(){ $function } PWformSubmit();";
659
+ $script .= $function;
660
+ $script .= "</script>";
661
+
662
+ echo strip_tags($script,"<script>");
663
+ echo strip_tags($form,"<form><input>");
664
+ } else {
665
+ $script = "<script type=\"text/javascript\">$function</script>";
666
+
667
+ echo strip_tags($form,"<form><input>");
668
+ echo strip_tags($script,"<script>");
669
+ }
670
+ die();
671
+ }
672
+
673
+ protected function nusoap() {
674
+ if ( ! class_exists( 'nusoap_client' ) ) {
675
+ include_once( 'lib/nusoap.php' );
676
+ }
677
+ }
678
+
679
+ /*
680
+ * Abstract methods and must be override
681
+ * */
682
+
683
+ abstract protected function fields();
684
+
685
+ abstract protected function request( $order );
686
+
687
+ abstract protected function verify( $order );
688
+
689
+ }
690
+ endif;
691
  include 'gateways/class-payir.php';
include/class-notice.php ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ defined( 'ABSPATH' ) || exit;
4
+
5
+ class Persian_Woocommerce_Notice {
6
+
7
+ public function __construct() {
8
+ add_action( 'admin_notices', [ $this, 'admin_notices' ], 10 );
9
+ add_action( 'wp_ajax_pw_dismiss_notice', [ $this, 'dismiss_notice' ] );
10
+ add_action( 'wp_ajax_pw_update_notice', [ $this, 'update_notice' ] );
11
+ }
12
+
13
+ public function admin_notices() {
14
+
15
+ if ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'manage_woocommerce' ) ) {
16
+ return;
17
+ }
18
+
19
+ if ( $this->is_dismiss( 'all' ) ) {
20
+ return;
21
+ }
22
+
23
+ foreach ( $this->notices() as $notice ) {
24
+
25
+ if ( $notice['condition'] == false || $this->is_dismiss( $notice['id'] ) ) {
26
+ continue;
27
+ }
28
+
29
+ $dismissible = $notice['dismiss'] ? 'is-dismissible' : '';
30
+
31
+ $notice_id = esc_attr( $notice['id'] );
32
+ $notice_content = strip_tags( $notice['content'], '<p><a><input><b><img><ul><ol><li>' );
33
+
34
+ printf( '<div class="notice pw_notice notice-success %s" id="pw_%s"><p>%s</p></div>', $dismissible, $notice_id, $notice_content );
35
+
36
+ break;
37
+ }
38
+
39
+ ?>
40
+ <script type="text/javascript">
41
+ jQuery(document).ready(function ($) {
42
+
43
+ $(document.body).on('click', '.notice-dismiss', function () {
44
+
45
+ let notice = $(this).closest('.pw_notice');
46
+ notice = notice.attr('id');
47
+
48
+ if (notice !== undefined && notice.indexOf('pw_') !== -1) {
49
+
50
+ notice = notice.replace('pw_', '');
51
+
52
+ $.ajax({
53
+ url: "<?php echo admin_url( 'admin-ajax.php' ) ?>",
54
+ type: 'post',
55
+ data: {
56
+ notice: notice,
57
+ action: 'pw_dismiss_notice',
58
+ nonce: "<?php echo wp_create_nonce( 'pw_dismiss_notice' ); ?>"
59
+ }
60
+ });
61
+ }
62
+
63
+ });
64
+
65
+ $.ajax({
66
+ url: "<?php echo admin_url( 'admin-ajax.php' ) ?>",
67
+ type: 'post',
68
+ data: {
69
+ action: 'pw_update_notice',
70
+ nonce: '<?php echo wp_create_nonce( 'pw_update_notice' ); ?>'
71
+ }
72
+ });
73
+ });
74
+ </script>
75
+ <?php
76
+ }
77
+
78
+ public function notices(): array {
79
+ global $pagenow;
80
+
81
+ $post_type = sanitize_text_field( $_GET['post_type'] ?? null );
82
+ $page = sanitize_text_field( $_GET['page'] ?? null );
83
+ $tab = sanitize_text_field( $_GET['tab'] ?? null );
84
+ $has_shipping = wc_shipping_enabled();
85
+
86
+ $notices = [
87
+ [
88
+ 'id' => 'tapin-orders',
89
+ 'content' => '<b>با افزونه حمل و نقل ووکامرس فارسی یک دفتر پستی اختصاصی داشته باش و بدون مراجعه به پست همه سفارشاتتو ارسال کن.</b>
90
+ <ul>
91
+ <li>- تولید فاکتور پست همراه با بارکد پستی به صورت آنلاین</li>
92
+ <li>- جمع آوری مرسولات از محل شما توسط ماموران پست</li>
93
+ <li>- ارسال کد رهگیری پستی برای مشتریان به صورت پیامکی</li>
94
+ <li>- بروزرسانی خودکار آخرین وضعیت مرسوله در پنل ووکامرس</li>
95
+ </ul>
96
+ <a href="https://yun.ir/pwto" target="_blank">
97
+ <input type="button" class="button button-primary" value="اطلاعات بیشتر">
98
+ </a>
99
+ <a href="' . admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) . '" target="_blank">
100
+ <input type="button" class="button" value="نصب افزونه پیشخوان پست">
101
+ </a>',
102
+ 'condition' => $pagenow == 'edit.php' && $post_type == 'shop_order' && $has_shipping,
103
+ 'dismiss' => 6 * MONTH_IN_SECONDS,
104
+ ],
105
+ [
106
+ 'id' => 'tapin-shipping',
107
+ 'content' => '<b>با افزونه حمل و نقل ووکامرس فارسی به رایگان هزینه پست سفارشی و پیشتاز رو بصورت دقیق و طبق آخرین تعرفه پست محاسبه کنید و سرویس پرداخت در محل رو در سراسر کشور فعال کنید.</b>
108
+ <ul>
109
+ <li>- محاسبه دقیق هزینه ارسال بر اساس وزن و شهر خریدار</li>
110
+ <li>- امکان تخفیف در هزینه ارسال بر اساس میزان خرید</li>
111
+ <li>- صدور آنلاین کد رهگیری پستی و تولید فاکتور</li>
112
+ <li>- ارسال کد رهگیری به خریدار به صورت پیامکی و در پنل کاربری</li>
113
+ </ul>
114
+ <a href="https://yun.ir/pwts" target="_blank">
115
+ <input type="button" class="button button-primary" value="اطلاعات بیشتر">
116
+ </a>
117
+ <a href="' . admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) . '" target="_blank">
118
+ <input type="button" class="button" value="نصب افزونه پیشخوان پست">
119
+ </a>',
120
+ 'condition' => $page == 'wc-settings' && $tab == 'shipping' && $has_shipping,
121
+ 'dismiss' => 6 * MONTH_IN_SECONDS,
122
+ ],
123
+ [
124
+ 'id' => 'tapin-tools',
125
+ 'content' => '
126
+ <a href="https://yun.ir/pwtt" target="_blank">
127
+ <img src="' . PW()->plugin_url( 'assets/images/tapin.jpg' ) . '" style="width: 100%">
128
+ </a>',
129
+ 'condition' => $page == 'persian-wc-tools' && $has_shipping,
130
+ 'dismiss' => 6 * MONTH_IN_SECONDS,
131
+ ],
132
+ [
133
+ 'id' => 'tapin-dashboard',
134
+ 'content' => '<b>پیشخوان وردپرس خود را رایگان به شرکت ملی پست متصل کنید و یک دفتر پستی اختصاصی داشته باشید.</b>
135
+ <ul>
136
+ <li>- محاسبه دقیق هزینه های پستی در سبد خرید</li>
137
+ <li>- جمع آری سفارشات از محل شما توسط ماموران پست در سراسر کشور</li>
138
+ <li>- صدور فاکتور استاندارد پست همراه با بارکد پست</li>
139
+ <li>- ارسال کد رهگیری پست به مشتری به صورت پیامکی و پنل کاربری</li>
140
+ </ul>
141
+ <a href="https://yun.ir/pwtd" target="_blank">
142
+ <input type="button" class="button button-primary" value="اطلاعات بیشتر">
143
+ </a>
144
+ <a href="' . admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) . '" target="_blank">
145
+ <input type="button" class="button" value="نصب افزونه پیشخوان پست">
146
+ </a>',
147
+ 'condition' => $pagenow == 'index.php' && $has_shipping,
148
+ 'dismiss' => 6 * MONTH_IN_SECONDS,
149
+ ],
150
+ [
151
+ 'id' => 'persian-date',
152
+ 'content' => '<b>ووکامرس فارسی با طعم ووکامرس شمسی!</b>
153
+ <ul>
154
+ <li>- شمسی سازی محیط وردپرس بدون نیاز به افزونه جانبی</li>
155
+ <li>- شمسی سازی ووکامرس در محصولات، سفارشات، کوپن ها و گزارشات</li>
156
+ <li>- افزودن DatePicker شمسی در پنل ووکامرس</li>
157
+ <li>- برای فعالسازی شمسی ساز ووکامرس روی کلید زیر کلیک کنید:</li>
158
+ </ul>
159
+ <a href="' . admin_url( 'admin.php?page=persian-wc-tools' ) . '" target="_blank">
160
+ <input type="button" class="button button-primary" value="فعالسازی شمسی ساز وردپرس و ووکامرس">
161
+ </a>',
162
+ 'condition' => PW()->get_options( 'enable_jalali_datepicker' ) !== 'yes',
163
+ 'dismiss' => 6 * MONTH_IN_SECONDS,
164
+ ],
165
+ [
166
+ 'id' => 'pws',
167
+ 'content' => sprintf( 'بنظر میرسه هنوز حمل و نقل (پست پیشتاز، سفارشی، پیک موتوری و...) فروشگاه رو پیکربندی نکردید؟ <a href="%s" target="_blank">نصب افزونه حمل و نقل فارسی ووکامرس و پیکربندی.</a>', admin_url( 'plugin-install.php?tab=plugin-information&plugin=persian-woocommerce-shipping' ) ),
168
+ 'condition' => is_plugin_inactive( 'persian-woocommerce-shipping/woocommerce-shipping.php' ) && $has_shipping,
169
+ 'dismiss' => 6 * MONTH_IN_SECONDS,
170
+ ],
171
+ ];
172
+
173
+ $_notices = get_option( 'pw_notices', [] );
174
+
175
+ foreach ( $_notices['notices'] ?? [] as $_notice ) {
176
+
177
+ $_notice['condition'] = 1;
178
+
179
+ $rules = $_notice['rules'];
180
+
181
+ if ( isset( $rules['pagenow'] ) && $rules['pagenow'] != $pagenow ) {
182
+ $_notice['condition'] = 0;
183
+ }
184
+
185
+ if ( isset( $rules['page'] ) && $rules['page'] != $page ) {
186
+ $_notice['condition'] = 0;
187
+ }
188
+
189
+ if ( isset( $rules['tab'] ) && $rules['tab'] != $tab ) {
190
+ $_notice['condition'] = 0;
191
+ }
192
+
193
+ if ( isset( $rules['active'] ) && is_plugin_inactive( $rules['active'] ) ) {
194
+ $_notice['condition'] = 0;
195
+ }
196
+
197
+ if ( isset( $rules['inactive'] ) && is_plugin_active( $rules['inactive'] ) ) {
198
+ $_notice['condition'] = 0;
199
+ }
200
+
201
+ if ( isset( $rules['has_shipping'] ) && $rules['has_shipping'] != $has_shipping ) {
202
+ $_notice['condition'] = 0;
203
+ }
204
+
205
+ unset( $_notice['rules'] );
206
+
207
+ array_unshift( $notices, $_notice );
208
+ }
209
+
210
+ return $notices;
211
+ }
212
+
213
+ public function dismiss_notice() {
214
+
215
+ check_ajax_referer( 'pw_dismiss_notice', 'nonce' );
216
+
217
+ $this->set_dismiss( $_POST['notice'] );
218
+
219
+ die();
220
+ }
221
+
222
+ public function update_notice() {
223
+
224
+ $update = get_transient( 'pw_update_notices' );
225
+
226
+ if ( $update ) {
227
+ return;
228
+ }
229
+
230
+ set_transient( 'pw_update_notices', 1, DAY_IN_SECONDS / 4 );
231
+
232
+ check_ajax_referer( 'pw_update_notice', 'nonce' );
233
+
234
+ $notices = wp_remote_get( 'https://woonotice.ir/pw.json', [ 'timeout' => 5, ] );
235
+ $sign = wp_remote_get( 'https://woohash.ir/pw.hash', [ 'timeout' => 5, ] );
236
+
237
+ if ( is_wp_error( $notices ) || is_wp_error( $sign ) ) {
238
+ die();
239
+ }
240
+
241
+ if ( ! is_array( $notices ) || ! is_array( $sign ) ) {
242
+ die();
243
+ }
244
+
245
+ $notices = trim( $notices['body'] );
246
+ $sign = trim( $sign['body'] );
247
+
248
+ if ( sha1( $notices ) !== $sign ) {
249
+ die();
250
+ }
251
+
252
+ $notices = json_decode( $notices, JSON_OBJECT_AS_ARRAY );
253
+
254
+ if ( empty( $notices ) || ! is_array( $notices ) ) {
255
+ die();
256
+ }
257
+
258
+ foreach ( $notices['notices'] as &$_notice ) {
259
+
260
+ $doc = new DOMDocument();
261
+ $content = strip_tags( $_notice['content'], '<p><a><b><img><ul><ol><li>' );
262
+ $content = str_replace( [ 'javascript', 'java', 'script' ], '', $content );
263
+ $doc->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
264
+
265
+ foreach ( $doc->getElementsByTagName( '*' ) as $element ) {
266
+
267
+ $href = null;
268
+ $src = null;
269
+ $style = $element->getAttribute( 'style' );
270
+
271
+ if ( $element->nodeName == 'a' ) {
272
+ $href = $element->getAttribute( 'href' );
273
+ }
274
+
275
+ if ( $element->nodeName == 'img' ) {
276
+ $src = $element->getAttribute( 'src' );
277
+ }
278
+
279
+ foreach ( $element->attributes as $attribute ) {
280
+ $element->removeAttribute( $attribute->name );
281
+ }
282
+
283
+ if ( $href && filter_var( $href, FILTER_VALIDATE_URL ) ) {
284
+ $element->setAttribute( 'href', $href );
285
+ $element->setAttribute( 'target', '_blank' );
286
+ }
287
+
288
+ if ( $src && filter_var( $src, FILTER_VALIDATE_URL ) && strpos( $src, 'https://woonotice.ir' ) === 0 ) {
289
+ $element->setAttribute( 'src', $src );
290
+ }
291
+
292
+ if ( $style ) {
293
+ $element->setAttribute( 'style', $style );
294
+ }
295
+ }
296
+
297
+ $_notice['content'] = $doc->saveHTML();
298
+ }
299
+
300
+ update_option( 'pw_notices', $notices );
301
+
302
+ die();
303
+ }
304
+
305
+ public function set_dismiss( $notice_id ) {
306
+
307
+ $notices = wp_list_pluck( $this->notices(), 'dismiss', 'id' );
308
+
309
+ if ( isset( $notices[ $notice_id ] ) && $notices[ $notice_id ] ) {
310
+ set_transient( 'pw_notice_' . $notice_id, 'DISMISS', intval( $notices[ $notice_id ] ) );
311
+ set_transient( 'pw_notice_all', 'DISMISS', HOUR_IN_SECONDS );
312
+ }
313
+ }
314
+
315
+ public function is_dismiss( $notice_id ): bool {
316
+ return get_transient( 'pw_notice_' . $notice_id ) !== false;
317
+ }
318
+
319
+ }
320
+
321
+ new Persian_Woocommerce_Notice();
include/class-tools.php CHANGED
@@ -1,461 +1,490 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
 
5
- if ( ! class_exists( 'Persian_Woocommerce_Tools' ) ) :
 
 
 
 
 
6
 
7
- class Persian_Woocommerce_Tools extends Persian_Woocommerce_Core {
 
 
 
 
8
 
9
- public function __construct() {
10
- add_action( 'admin_init', array( $this, 'tools_save' ) );
11
- add_filter( 'woocommerce_admin_field_multi_select_states', array( $this, 'specific_states_field' ) );
12
  }
13
 
14
- public function tools_tabs( $current = 'general', $current_section = "" ) {
15
- $active = array(
16
- 'tab' => '',
17
- 'section' => '',
18
- );
19
 
20
- if ( empty( $current ) ) {
21
- $current = 'general';
22
- }
23
 
24
- $tabs = apply_filters( "PW_Tools_tabs", array(
25
- 'general' => 'گزینه های اصلی',
26
- 'price' => 'گزینه های قیمت',
27
- 'checkout' => 'تسویه حساب',
28
- ) );
29
 
30
- $sections['fields'] = apply_filters( "PW_Tools_sections", array() );
 
31
 
32
- $html_sections = array();
33
 
34
- echo '<div id="icon-themes" class="icon32"><br></div>';
35
- echo '<h2 class="nav-tab-wrapper">';
36
 
37
- foreach ( $tabs as $tab => $name ) {
38
- if ( $tab == $current ) {
39
- $active['tab'] = $tab;
40
- $class = ' nav-tab-active';
41
- } else {
42
- $class = "";
43
- }
44
- echo sprintf( "<a class='nav-tab%s' href='?page=persian-wc-tools&tab=%s'>%s</a>", $class, $tab, $name );
45
-
46
- if ( $tab == $current && isset( $sections[ $tab ] ) ) {
47
- foreach ( $sections[ $tab ] as $section => $name ) {
48
- if ( $section == $current_section || ! count( $html_sections ) ) {
49
- $active['section'] = $section;
50
- $class = 'current';
51
- } else {
52
- $class = '';
53
- }
54
- $html_sections[] = sprintf( "<li><a href='?page=persian-wc-tools&tab=%s&section=%s' class='%s'>%s</a></li>", $tab, $section, $class, $name );
55
- }
56
- }
57
  }
58
 
59
- echo '</h2>';
60
 
61
- if ( count( $html_sections ) ) {
62
- echo sprintf( '<ul class="subsubsub">%s</ul><br>', implode( $html_sections, " | " ) );
 
 
 
 
 
 
 
 
 
 
63
  }
 
64
 
65
- return array_values( $active );
 
 
 
66
  }
67
 
68
- public function tools_sections() {
 
 
 
69
 
70
- $tools = [
71
 
72
- "general" => [
73
- [
74
- 'title' => 'همگانی',
75
- 'type' => 'title',
76
- 'id' => 'general_options'
77
- ],
78
- [
79
- 'title' => 'مرتب سازی لیست سفارشات',
80
- 'id' => 'PW_Options[fix_orders_list]',
81
- 'type' => 'checkbox',
82
- 'default' => 'no',
83
- 'desc' => 'برای مرتب سازی لیست سفارشات بر اساس تاریخ پرداخت تیک بزنید (قبل از فعالسازی این گزینه، حتما <a href="https://forum.persianscript.ir/threads/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1-%D9%85%D8%B1%D8%AA%D8%A8-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%84%DB%8C%D8%B3%D8%AA-%D8%B3%D9%81%D8%A7%D8%B1%D8%B4%D8%A7%D8%AA.26864/" target="_blank">اینجا</a> را کامل مطالعه نمایید)',
84
- ],
85
- [
86
- 'title' => 'تاریخ شمسی',
87
- 'id' => 'PW_Options[enable_jalali_datepicker]',
88
- 'type' => 'checkbox',
89
- 'default' => 'no',
90
- 'desc' => 'فعالسازی تاریخ شمسی در وردپرس و ووکامرس (محصولات، سفارشات، کوپن ها و گزارشات)<br>
91
  <p><b>پیشنهاد:</b> برای کارکردن صحیح افزونه و عملکرد مناسب این ابزار، پیشنهاد می کنیم هیچ افزونه شمسی ساز دیگری را همزمان فعال نکنید.</p>',
92
- ],
93
- [
94
- 'type' => 'sectionend',
95
- 'id' => 'general_options'
96
- ],
97
  ],
 
 
 
 
 
98
 
99
- 'price' => [
100
- [
101
- 'title' => 'تماس بگیرید',
102
- 'type' => 'title',
103
- 'id' => 'call_for_price_options'
104
- ],
105
- [
106
- 'title' => 'فعالسازی تماس برای قیمت',
107
- 'desc' => 'فعالسازی برچسب "تماس بگیرید" بجای قیمت در صورتی که قیمت محصول وارد نشده باشد',
108
- 'desc_tip' => 'دقت کنید که قیمت 0 به معنای رایگان بودن محصول می باشد. قسمت قیمت را خالی بگذارید.',
109
- 'id' => 'PW_Options[enable_call_for_price]',
110
- 'type' => 'checkbox',
111
- 'default' => 'no',
112
- ],
113
- [
114
- 'title' => 'برچسب در صفحه محصول',
115
- // 'desc' => 'این مورد بجای قیمت محصول در صفحه محصول نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
116
- // 'desc_tip' => true,
117
- 'id' => 'PW_Options[call_for_price_text]',
118
- 'default' => '<strong>تماس بگیرید</strong>',
119
- 'type' => 'textarea',
120
- 'css' => 'width:50%;min-width:300px;',
121
- ],
122
- [
123
- 'title' => 'برچسب در قسمت آرشیو ها',
124
- // 'desc' => 'این مورد بجای قیمت محصول در آرشیو ها نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
125
- // 'desc_tip' => true,
126
- 'id' => 'PW_Options[call_for_price_text_on_archive]',
127
- 'default' => '<strong>تماس بگیرید</strong>',
128
- 'type' => 'textarea',
129
- 'css' => 'width:50%;min-width:300px;',
130
- ],
131
- [
132
- 'title' => 'برچسب در صفحه اصلی',
133
- // 'desc' => 'این مورد بجای قیمت محصول در صفحه اصلی نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
134
- // 'desc_tip' => true,
135
- 'id' => 'PW_Options[call_for_price_text_on_home]',
136
- 'default' => '<strong>تماس بگیرید</strong>',
137
- 'type' => 'textarea',
138
- 'css' => 'width:50%;min-width:300px;',
139
- ],
140
- [
141
- 'title' => 'برچسب در محصولات مرتبط',
142
- // 'desc' => 'این مورد بجای قیمت محصول در محصولات مرتبط نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
143
- // 'desc_tip' => true,
144
- 'id' => 'PW_Options[call_for_price_text_on_related]',
145
- 'default' => '<strong>تماس بگیرید</strong>',
146
- 'type' => 'textarea',
147
- 'css' => 'width:50%;min-width:300px;',
148
- ],
149
- [
150
- 'title' => 'برچسب "فروش ویژه"',
151
- 'desc' => 'حذف برچسب فروش ویژه',
152
- 'id' => 'PW_Options[call_for_price_hide_sale_sign]',
153
- 'default' => 'no',
154
- 'type' => 'checkbox',
155
- ],
156
- [
157
- 'type' => 'sectionend',
158
- 'id' => 'call_for_price_options'
159
- ],
160
-
161
- [
162
- 'title' => 'قیمت فارسی',
163
- 'type' => 'title',
164
- 'id' => 'persian_price_option'
165
- ],
166
- [
167
- 'title' => 'فارسی سازی قیمت ها',
168
- 'desc' => 'استفاده از اعداد فارسی در قیمت ها',
169
- 'id' => 'PW_Options[persian_price]',
170
- 'default' => 'no',
171
- 'type' => 'checkbox',
172
- ],
173
- [
174
- 'type' => 'sectionend',
175
- 'id' => 'persian_price_option'
176
- ],
177
 
178
- [
179
- 'title' => 'سایر',
180
- 'type' => 'title',
181
- 'id' => 'other_price_option'
182
- ],
183
- [
184
- 'title' => 'حداقل مبلغ سفارش',
185
- 'id' => 'PW_Options[minimum_order_amount]',
186
- 'default' => 0,
187
- 'type' => 'number',
188
- ],
189
- [
190
- 'type' => 'sectionend',
191
- 'id' => 'other_price_option'
 
 
 
 
 
 
 
 
 
 
192
  ],
193
  ],
 
 
 
 
194
 
195
- 'checkout' => [
196
- [
197
- 'title' => 'استان ها و شهرها',
198
- 'type' => 'title',
199
- 'id' => 'address_options'
200
- ],
201
- [
202
- 'title' => 'فروش به استان های',
203
- 'id' => 'PW_Options[allowed_states]',
204
- 'default' => 'all',
205
- 'type' => 'select',
206
- 'class' => 'wc-enhanced-select',
207
- 'css' => 'width: 350px;',
208
- 'options' => [
209
- 'all' => 'فروش به همه استان ها',
210
- 'specific' => 'فروش به استان های خاص'
211
- ]
212
- ],
213
- [
214
- 'title' => 'استان های خاص',
215
- 'desc' => '',
216
- 'id' => 'PW_Options[specific_allowed_states]',
217
- 'css' => 'min-width: 350px;',
218
- 'default' => '',
219
- 'class' => 'wc-enhanced-select',
220
- 'type' => 'multi_select_states'
221
- ],
222
- [
223
- 'title' => 'فعالسازی شهرهای ایران',
224
- 'id' => 'PW_Options[enable_iran_cities]',
225
- 'type' => 'checkbox',
226
- 'default' => 'yes',
227
- 'desc' => 'فعالسازی شهرهای ایران در صفحه تسویه حساب',
228
- ],
229
- [
230
- 'title' => 'جابجایی فیلد استان و شهر',
231
- 'id' => 'PW_Options[flip_state_city]',
232
- 'type' => 'checkbox',
233
- 'default' => 'no',
234
- 'desc' => 'در صورتی که گزینه "فعالسازی شهر های ایران" را انتخاب نمایید، در برخی قالب ها ممکن است فیلد شهر قبل از فیلد استان قرار بگیرد که با فعالسازی این گزینه میتوانید جایگاه آنها را با هم عوض نمایید.',
235
- ],
236
- [
237
- 'title' => 'حل مشکل لیست استان ها',
238
- 'id' => 'PW_Options[fix_load_states]',
239
- 'type' => 'checkbox',
240
- 'default' => 'no',
241
- 'desc' => 'برای حل مشکل بارگذاری لیست استان ها در صفحه تسویه حساب تیک بزنید.',
242
- ],
243
- [
244
- 'type' => 'sectionend',
245
- 'id' => 'address_options'
246
- ],
247
 
248
- [
249
- 'title' => 'کدپستی',
250
- 'type' => 'title',
251
- 'id' => 'postcode_options'
252
- ],
253
- [
254
- 'title' => 'اعداد فارسی در کدپستی',
255
- 'id' => 'PW_Options[fix_postcode_persian_number]',
256
- 'type' => 'checkbox',
257
- 'default' => 'no',
258
- 'desc' => 'برای تبدیل اعداد فارسی به انگلیسی در کدپستی تیک بزنید.',
259
- ],
260
- [
261
- 'title' => 'بررسی صحت کدپستی',
262
- 'id' => 'PW_Options[postcode_validation]',
263
- 'type' => 'checkbox',
264
- 'default' => 'no',
265
- 'desc' => 'برای بررسی صحت کدپستی و ده رقمی بودن آن تیک بزنید.',
266
- ],
267
- [
268
- 'type' => 'sectionend',
269
- 'id' => 'postcode_options'
270
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
 
272
- [
273
- 'title' => 'تلفن همراه',
274
- 'type' => 'title',
275
- 'id' => 'phone_options'
276
- ],
277
- [
278
- 'title' => 'اعداد فارسی در تلفن همراه',
279
- 'id' => 'PW_Options[fix_phone_persian_number]',
280
- 'type' => 'checkbox',
281
- 'default' => 'no',
282
- 'desc' => 'برای تبدیل اعداد فارسی به انگلیسی در تلفن همراه تیک بزنید.',
283
- ],
284
- [
285
- 'title' => 'بررسی صحت تلفن همراه',
286
- 'id' => 'PW_Options[phone_validation]',
287
- 'type' => 'checkbox',
288
- 'default' => 'no',
289
- 'desc' => 'برای بررسی صحت تلفن همراه و یازده رقمی بودن آن تیک بزنید.',
290
- ],
291
- [
292
- 'type' => 'sectionend',
293
- 'id' => 'phone_options'
294
- ],
295
 
296
- [
297
- 'title' => 'سایر',
298
- 'type' => 'title',
299
- 'id' => 'other_options'
300
- ],
301
- [
302
- 'title' => 'حذف فیلدهای غیرضروری',
303
- 'id' => 'PW_Options[remove_extra_field_physical]',
304
- 'type' => 'checkbox',
305
- 'default' => 'no',
306
- 'desc' => 'برای حذف فیلدهای غیرضروری از محصولات دانلودی ووکامرس تیک بزنید.',
307
- ],
308
- [
309
- 'type' => 'sectionend',
310
- 'id' => 'other_options'
311
- ],
312
- ]
 
 
 
 
 
 
313
 
314
- ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
 
316
- return apply_filters( "PW_Tools_settings", $tools );
317
- }
318
 
319
- public function tools_page() {
320
- global $pagenow;
321
- $settings = $this->tools_sections();
322
- wp_enqueue_style( 'woocommerce_admin_styles' );
323
- wp_enqueue_script( 'wc-enhanced-select' );
324
- wp_enqueue_script( 'pw-admin-script' );
325
- ?>
326
 
327
- <div class="wrap persian-woocommerce">
328
- <h2>ابزارهای ووکامرس فارسی</h2>
329
 
330
- <?php
331
- if ( isset( $_GET['updated'] ) && 'true' == esc_attr( $_GET['updated'] ) ) {
332
- echo '<div class="updated" ><p>تنظیمات با موفقیت ذخیره شد.</p></div>';
333
- }
 
334
 
335
- list( $tab, $section ) = $this->tools_tabs( isset( $_GET['tab'] ) ? $_GET['tab'] : "", isset( $_GET['section'] ) ? $_GET['section'] : "" );
336
- ?>
337
 
338
- <div id="poststuff">
339
- <form method="post" action="<?php admin_url( 'themes.php?page=persian-wc-tools' ); ?>">
340
- <?php
341
- wp_nonce_field( "persian-wc-tools" );
342
-
343
- if ( $pagenow == 'admin.php' && $_GET['page'] == 'persian-wc-tools' && isset( $settings[ $tab ] ) ) {
344
-
345
-
346
- WC_Admin_Settings::output_fields( empty( $section ) ? $settings[ $tab ] : $settings[ $tab ][ $section ] );
347
- }
348
-
349
- ?>
350
- <p class="submit" style="clear: both;">
351
- <input type="submit" name="Submit" class="button-primary" value="ذخیره تنظیمات"/>
352
- <input type="hidden" name="pw-settings-submit" value="Y"/>
353
- <input type="hidden" name="pw-tab" value="<?php echo $tab; ?>"/>
354
- <input type="hidden" name="pw-section" value="<?php echo $section; ?>"/>
355
- </p>
356
- </form>
357
- </div>
358
-
359
- </div>
360
- <script type="text/javascript">
361
- jQuery(document).ready(function ( $ ) {
362
- $('.persian-woocommerce').on('click', '.select_all', function () {
363
- jQuery(this).closest('td').find('select option').attr('selected', 'selected');
364
- jQuery(this).closest('td').find('select').trigger('change');
365
- return false;
366
- }).on('click', '.select_none', function () {
367
- jQuery(this).closest('td').find('select option').removeAttr('selected');
368
- jQuery(this).closest('td').find('select').trigger('change');
369
- return false;
370
- });
371
-
372
- $('select#PW_Options\\[allowed_states\\]').change(function () {
373
- if( jQuery(this).val() === 'specific' ) {
374
- jQuery(this).parent().parent().next('tr').show();
375
- } else {
376
- jQuery(this).parent().parent().next('tr').hide();
377
- }
378
- }).change();
379
- });
380
- </script>
381
  <?php
382
- }
383
-
384
- public function tools_save() {
385
 
386
- if ( empty( $_GET['page'] ) || $_GET['page'] != 'persian-wc-tools' ) {
387
- return;
388
  }
389
 
390
- if ( isset( $_POST["pw-settings-submit"] ) && $_POST["pw-settings-submit"] == 'Y' ) {
391
- $settings = $this->tools_sections();
392
- $tab = $_POST['pw-tab'];
393
- $section = $_POST['pw-section'];
394
- check_admin_referer( "persian-wc-tools" );
395
- do_action( "PW_before_save_tools", $_POST, $settings, $tab, $section );
396
- WC_Admin_Settings::save_fields( empty( $section ) ? $settings[ $tab ] : $settings[ $tab ][ $section ] );
397
- do_action( "PW_after_save_tools", $_POST, $settings, $tab, $section );
398
- $url_parameters = empty( $section ) ? 'updated=true&tab=' . $tab : 'updated=true&tab=' . $tab . '&section=' . $section;
399
- wp_redirect( admin_url( 'admin.php?page=persian-wc-tools&' . $url_parameters ) );
400
- exit;
401
- }
402
- }
403
 
404
- public function specific_states_field( $value ) {
405
-
406
- $selections = (array) PW()->get_options( 'specific_allowed_states' );
407
  ?>
408
- <tr valign="top">
409
- <th scope="row" class="titledesc">
410
- <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
411
- </th>
412
- <td class="forminp">
413
- <select multiple="multiple" name="<?php echo esc_attr( $value['id'] ); ?>[]" style="width:350px"
414
- data-placeholder="استان (ها) مورد نظر خود را انتخاب کنید ..." title="استان"
415
- class="wc-enhanced-select">
416
  <?php
417
- if ( ! empty( PW()->address->states ) ) {
418
- foreach ( PW()->address->states as $key => $val ) {
419
- echo '<option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $selections ), true, false ) . '>' . $val . '</option>';
420
- }
421
  }
 
422
  ?>
423
- </select> <br/><a class="select_all button" href="#"><?php _e( 'Select all', 'woocommerce' ); ?></a> <a
424
- class="select_none button" href="#"><?php _e( 'Select none', 'woocommerce' ); ?></a>
425
- </td>
426
- </tr><?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  }
428
 
429
- public function get_tools_default( $tools = null ) {
430
 
431
- if ( is_null( $tools ) ) {
432
- $tools = $this->tools_sections();
433
- }
 
 
 
 
 
 
 
 
434
 
435
- $output = array();
436
 
437
- foreach ( $tools as $tool => $tool_name ) {
438
- if ( isset( $tool_name['id'], $tool_name['default'] ) ) {
439
- $output[ $tool_name['id'] ] = $tool_name['default'];
440
- } elseif ( is_array( $tool_name ) ) {
441
- $array = $this->get_tools_default( $tool_name );
442
- if ( count( $array ) ) {
443
- $output += $array;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  }
445
  }
446
- }
 
 
 
 
 
 
 
447
 
448
- return $output;
 
449
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
  }
451
- endif;
452
 
453
  PW()->tools = new Persian_Woocommerce_Tools();
454
 
455
  do_action( 'PW_Tools_load', PW()->get_options() );
456
 
457
- include( "tools/general.php" );
458
- include( "tools/class-price.php" );
459
- include( "tools/class-datepicker.php" );
460
- include( "tools/class-date.php" );
461
- include( "tools/class-checkout.php" );
1
+ <?php
2
+
3
+ defined( 'ABSPATH' ) || exit;
4
 
5
+ class Persian_Woocommerce_Tools extends Persian_Woocommerce_Core {
6
+
7
+ public function __construct() {
8
+ add_action( 'admin_init', [ $this, 'tools_save' ] );
9
+ add_filter( 'woocommerce_admin_field_multi_select_states', [ $this, 'specific_states_field' ] );
10
+ }
11
 
12
+ public function tools_tabs( $current_tab = 'general', $current_section = '' ): array {
13
+ $active = [
14
+ 'tab' => '',
15
+ 'section' => '',
16
+ ];
17
 
18
+ if ( empty( $current_tab ) ) {
19
+ $current_tab = 'general';
 
20
  }
21
 
22
+ $tabs = apply_filters( 'PW_Tools_tabs', [
23
+ 'general' => 'گزینه های اصلی',
24
+ 'price' => 'گزینه های قیمت',
25
+ 'checkout' => 'تسویه حساب',
26
+ ] );
27
 
28
+ $sections['fields'] = apply_filters( 'PW_Tools_sections', [] );
 
 
29
 
30
+ $html_sections = [];
 
 
 
 
31
 
32
+ echo '<div id="icon-themes" class="icon32"><br></div>';
33
+ echo '<h2 class="nav-tab-wrapper">';
34
 
35
+ foreach ( $tabs as $tab => $tab_name ) {
36
 
37
+ $class = '';
 
38
 
39
+ if ( $tab == $current_tab ) {
40
+ $active['tab'] = $tab;
41
+ $class = ' nav-tab-active';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
43
 
44
+ printf( "<a class='nav-tab%s' href='?page=persian-wc-tools&tab=%s'>%s</a>", $class, $tab, $tab_name );
45
 
46
+ if ( $tab == $current_tab && isset( $sections[ $tab ] ) ) {
47
+ foreach ( $sections[ $tab ] as $section => $section_name ) {
48
+
49
+ $class = '';
50
+
51
+ if ( $section == $current_section || ! count( $html_sections ) ) {
52
+ $active['section'] = $section;
53
+ $class = 'current';
54
+ }
55
+
56
+ $html_sections[] = sprintf( "<li><a href='?page=persian-wc-tools&tab=%s&section=%s' class='%s'>%s</a></li>", $tab, $section, $class, $section_name );
57
+ }
58
  }
59
+ }
60
 
61
+ echo '</h2>';
62
+
63
+ if ( count( $html_sections ) ) {
64
+ printf( '<ul class="subsubsub">%s</ul><br>', implode( $html_sections, " | " ) );
65
  }
66
 
67
+ return array_values( $active );
68
+ }
69
+
70
+ public function tools_sections() {
71
 
72
+ $tools = [
73
 
74
+ 'general' => [
75
+ [
76
+ 'title' => 'همگانی',
77
+ 'type' => 'title',
78
+ 'id' => 'general_options',
79
+ ],
80
+ [
81
+ 'title' => 'مرتب سازی لیست سفارشات',
82
+ 'id' => 'PW_Options[fix_orders_list]',
83
+ 'type' => 'checkbox',
84
+ 'default' => 'no',
85
+ 'desc' => 'برای مرتب سازی لیست سفارشات بر اساس تاریخ پرداخت تیک بزنید (قبل از فعالسازی این گزینه، حتما <a href="https://forum.persianscript.ir/threads/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1-%D9%85%D8%B1%D8%AA%D8%A8-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%84%DB%8C%D8%B3%D8%AA-%D8%B3%D9%81%D8%A7%D8%B1%D8%B4%D8%A7%D8%AA.26864/" target="_blank">اینجا</a> را کامل مطالعه نمایید)',
86
+ ],
87
+ [
88
+ 'title' => 'تاریخ شمسی',
89
+ 'id' => 'PW_Options[enable_jalali_datepicker]',
90
+ 'type' => 'checkbox',
91
+ 'default' => 'no',
92
+ 'desc' => 'فعالسازی تاریخ شمسی در وردپرس و ووکامرس (محصولات، سفارشات، کوپن ها و گزارشات)<br>
93
  <p><b>پیشنهاد:</b> برای کارکردن صحیح افزونه و عملکرد مناسب این ابزار، پیشنهاد می کنیم هیچ افزونه شمسی ساز دیگری را همزمان فعال نکنید.</p>',
 
 
 
 
 
94
  ],
95
+ [
96
+ 'type' => 'sectionend',
97
+ 'id' => 'general_options',
98
+ ],
99
+ ],
100
 
101
+ 'price' => [
102
+ [
103
+ 'title' => 'تماس بگیرید',
104
+ 'type' => 'title',
105
+ 'id' => 'call_for_price_options',
106
+ ],
107
+ [
108
+ 'title' => 'فعالسازی تماس برای قیمت',
109
+ 'desc' => 'فعالسازی برچسب "تماس بگیرید" بجای قیمت در صورتی که قیمت محصول وارد نشده باشد',
110
+ 'desc_tip' => 'دقت کنید که قیمت 0 به معنای رایگان بودن محصول می باشد. قسمت قیمت را خالی بگذارید.',
111
+ 'id' => 'PW_Options[enable_call_for_price]',
112
+ 'type' => 'checkbox',
113
+ 'default' => 'no',
114
+ ],
115
+ [
116
+ 'title' => 'برچسب در صفحه محصول',
117
+ // 'desc' => 'این مورد بجای قیمت محصول در صفحه محصول نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
118
+ // 'desc_tip' => true,
119
+ 'id' => 'PW_Options[call_for_price_text]',
120
+ 'default' => '<strong>تماس بگیرید</strong>',
121
+ 'type' => 'textarea',
122
+ 'css' => 'width:50%;min-width:300px;',
123
+ ],
124
+ [
125
+ 'title' => 'برچسب در قسمت آرشیو ها',
126
+ // 'desc' => 'این مورد بجای قیمت محصول در آرشیو ها نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
127
+ // 'desc_tip' => true,
128
+ 'id' => 'PW_Options[call_for_price_text_on_archive]',
129
+ 'default' => '<strong>تماس بگیرید</strong>',
130
+ 'type' => 'textarea',
131
+ 'css' => 'width:50%;min-width:300px;',
132
+ ],
133
+ [
134
+ 'title' => 'برچسب در صفحه اصلی',
135
+ // 'desc' => 'این مورد بجای قیمت محصول در صفحه اصلی نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
136
+ // 'desc_tip' => true,
137
+ 'id' => 'PW_Options[call_for_price_text_on_home]',
138
+ 'default' => '<strong>تماس بگیرید</strong>',
139
+ 'type' => 'textarea',
140
+ 'css' => 'width:50%;min-width:300px;',
141
+ ],
142
+ [
143
+ 'title' => 'برچسب در محصولات مرتبط',
144
+ // 'desc' => 'این مورد بجای قیمت محصول در محصولات مرتبط نمایش داده می شود. برای غیرفعال کردن خالی بگذارید.',
145
+ // 'desc_tip' => true,
146
+ 'id' => 'PW_Options[call_for_price_text_on_related]',
147
+ 'default' => '<strong>تماس بگیرید</strong>',
148
+ 'type' => 'textarea',
149
+ 'css' => 'width:50%;min-width:300px;',
150
+ ],
151
+ [
152
+ 'title' => 'برچسب "فروش ویژه"',
153
+ 'desc' => 'حذف برچسب فروش ویژه',
154
+ 'id' => 'PW_Options[call_for_price_hide_sale_sign]',
155
+ 'default' => 'no',
156
+ 'type' => 'checkbox',
157
+ ],
158
+ [
159
+ 'type' => 'sectionend',
160
+ 'id' => 'call_for_price_options',
161
+ ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ [
164
+ 'title' => 'نمایش قیمت',
165
+ 'type' => 'title',
166
+ 'id' => 'price_option',
167
+ ],
168
+ [
169
+ 'title' => 'فارسی سازی قیمت ها',
170
+ 'desc' => 'استفاده از اعداد فارسی در قیمت ها',
171
+ 'id' => 'PW_Options[persian_price]',
172
+ 'default' => 'no',
173
+ 'type' => 'checkbox',
174
+ ],
175
+ [
176
+ 'title' => 'قیمت محصولات متغیر',
177
+ 'desc' => 'نحوه نمایش قیمت محصولات متغیر در صفحات لیست محصولات',
178
+ 'id' => 'PW_Options[variable_price]',
179
+ 'default' => 'range',
180
+ 'type' => 'select',
181
+ 'options' => [
182
+ 'range' => 'بازه قیمتی (پیشفرض)',
183
+ 'min_regular' => 'حداقل قیمت اصلی',
184
+ 'max_regular' => 'حداکثر قیمت اصلی',
185
+ 'min_sale' => 'حداقل قیمت فروش فوق العاده',
186
+ 'max_sale' => 'حداکثر قیمت فروش فوق العاده',
187
  ],
188
  ],
189
+ [
190
+ 'type' => 'sectionend',
191
+ 'id' => 'price_option',
192
+ ],
193
 
194
+ [
195
+ 'title' => 'سایر',
196
+ 'type' => 'title',
197
+ 'id' => 'other_price_option',
198
+ ],
199
+ [
200
+ 'title' => 'حداقل مبلغ سفارش',
201
+ 'id' => 'PW_Options[minimum_order_amount]',
202
+ 'default' => 0,
203
+ 'desc' => 'در صورتی که قصد دارید برای امکان ثبت سفارشات در فروشگاه خود یک حداقل مبلغ مشخص کنید میتوانید مبلغ را در اینجا وارد نمایید در غیر اینصورت تنظیمات را دستکاری نکنید.',
204
+ 'type' => 'number',
205
+ ],
206
+ [
207
+ 'type' => 'sectionend',
208
+ 'id' => 'other_price_option',
209
+ ],
210
+ ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
 
212
+ 'checkout' => [
213
+ [
214
+ 'title' => 'استان ها و شهرها',
215
+ 'type' => 'title',
216
+ 'id' => 'address_options',
217
+ ],
218
+ [
219
+ 'title' => 'فروش به استان های',
220
+ 'id' => 'PW_Options[allowed_states]',
221
+ 'default' => 'all',
222
+ 'type' => 'select',
223
+ 'class' => 'wc-enhanced-select',
224
+ 'css' => 'width: 350px;',
225
+ 'options' => [
226
+ 'all' => 'فروش به همه استان ها',
227
+ 'specific' => 'فروش به استان های خاص',
 
 
 
 
 
 
228
  ],
229
+ ],
230
+ [
231
+ 'title' => 'استان های خاص',
232
+ 'desc' => '',
233
+ 'id' => 'PW_Options[specific_allowed_states]',
234
+ 'css' => 'min-width: 350px;',
235
+ 'default' => '',
236
+ 'class' => 'wc-enhanced-select',
237
+ 'type' => 'multi_select_states',
238
+ ],
239
+ [
240
+ 'title' => 'فعالسازی شهرهای ایران',
241
+ 'id' => 'PW_Options[enable_iran_cities]',
242
+ 'type' => 'checkbox',
243
+ 'default' => 'yes',
244
+ 'desc' => 'فعالسازی شهرهای ایران در صفحه تسویه حساب',
245
+ ],
246
+ [
247
+ 'title' => 'جابجایی فیلد استان و شهر',
248
+ 'id' => 'PW_Options[flip_state_city]',
249
+ 'type' => 'checkbox',
250
+ 'default' => 'no',
251
+ 'desc' => 'در صورتی که گزینه "فعالسازی شهر های ایران" را انتخاب نمایید، در برخی قالب ها ممکن است فیلد شهر قبل از فیلد استان قرار بگیرد که با فعالسازی این گزینه میتوانید جایگاه آنها را با هم عوض نمایید.',
252
+ ],
253
+ [
254
+ 'title' => 'حل مشکل لیست استان ها',
255
+ 'id' => 'PW_Options[fix_load_states]',
256
+ 'type' => 'checkbox',
257
+ 'default' => 'no',
258
+ 'desc' => 'برای حل مشکل بارگذاری لیست استان ها در صفحه تسویه حساب تیک بزنید.',
259
+ ],
260
+ [
261
+ 'type' => 'sectionend',
262
+ 'id' => 'address_options',
263
+ ],
264
 
265
+ [
266
+ 'title' => 'کدپستی',
267
+ 'type' => 'title',
268
+ 'id' => 'postcode_options',
269
+ ],
270
+ [
271
+ 'title' => 'اعداد فارسی در کدپستی',
272
+ 'id' => 'PW_Options[fix_postcode_persian_number]',
273
+ 'type' => 'checkbox',
274
+ 'default' => 'no',
275
+ 'desc' => 'برای تبدیل اعداد فارسی به انگلیسی در کدپستی تیک بزنید.',
276
+ ],
277
+ [
278
+ 'title' => 'بررسی صحت کدپستی',
279
+ 'id' => 'PW_Options[postcode_validation]',
280
+ 'type' => 'checkbox',
281
+ 'default' => 'no',
282
+ 'desc' => 'برای بررسی صحت کدپستی و ده رقمی بودن آن تیک بزنید.',
283
+ ],
284
+ [
285
+ 'type' => 'sectionend',
286
+ 'id' => 'postcode_options',
287
+ ],
288
 
289
+ [
290
+ 'title' => 'تلفن همراه',
291
+ 'type' => 'title',
292
+ 'id' => 'phone_options',
293
+ ],
294
+ [
295
+ 'title' => 'اعداد فارسی در تلفن همراه',
296
+ 'id' => 'PW_Options[fix_phone_persian_number]',
297
+ 'type' => 'checkbox',
298
+ 'default' => 'no',
299
+ 'desc' => 'برای تبدیل اعداد فارسی به انگلیسی در تلفن همراه تیک بزنید.',
300
+ ],
301
+ [
302
+ 'title' => 'بررسی صحت تلفن همراه',
303
+ 'id' => 'PW_Options[phone_validation]',
304
+ 'type' => 'checkbox',
305
+ 'default' => 'no',
306
+ 'desc' => 'برای بررسی صحت تلفن همراه و یازده رقمی بودن آن تیک بزنید.',
307
+ ],
308
+ [
309
+ 'type' => 'sectionend',
310
+ 'id' => 'phone_options',
311
+ ],
312
 
313
+ [
314
+ 'title' => 'سایر',
315
+ 'type' => 'title',
316
+ 'id' => 'other_options',
317
+ ],
318
+ [
319
+ 'title' => 'حذف فیلدهای غیرضروری',
320
+ 'id' => 'PW_Options[remove_extra_field_physical]',
321
+ 'type' => 'checkbox',
322
+ 'default' => 'no',
323
+ 'desc' => 'برای حذف فیلدهای غیرضروری از محصولات دانلودی ووکامرس تیک بزنید.',
324
+ ],
325
+ [
326
+ 'type' => 'sectionend',
327
+ 'id' => 'other_options',
328
+ ],
329
+ ],
330
 
331
+ ];
 
332
 
333
+ return apply_filters( 'PW_Tools_settings', $tools );
334
+ }
 
 
 
 
 
335
 
336
+ public function tools_page() {
337
+ global $pagenow;
338
 
339
+ $settings = $this->tools_sections();
340
+ wp_enqueue_style( 'woocommerce_admin_styles' );
341
+ wp_enqueue_script( 'wc-enhanced-select' );
342
+ wp_enqueue_script( 'pw-admin-script' );
343
+ ?>
344
 
345
+ <div class="wrap persian-woocommerce">
346
+ <h2>ابزارهای ووکامرس فارسی</h2>
347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  <?php
349
+ $updated = intval( $_GET['updated'] ?? 0 );
 
 
350
 
351
+ if ( $updated ) {
352
+ echo '<div class="updated" ><p>تنظیمات با موفقیت ذخیره شد.</p></div>';
353
  }
354
 
355
+ $current_tab = sanitize_text_field( $_GET['tab'] ?? null );
356
+ $current_section = sanitize_text_field( $_GET['section'] ?? null );
 
 
 
 
 
 
 
 
 
 
 
357
 
358
+ [ $tab, $section ] = $this->tools_tabs( $current_tab, $current_section );
 
 
359
  ?>
360
+
361
+ <div id="poststuff">
362
+ <form method="post" action="<?php admin_url( 'themes.php?page=persian-wc-tools' ); ?>">
 
 
 
 
 
363
  <?php
364
+ wp_nonce_field( "persian-wc-tools" );
365
+
366
+ if ( $pagenow == 'admin.php' && $_GET['page'] == 'persian-wc-tools' && isset( $settings[ $tab ] ) ) {
367
+ WC_Admin_Settings::output_fields( empty( $section ) ? $settings[ $tab ] : $settings[ $tab ][ $section ] );
368
  }
369
+
370
  ?>
371
+ <p class="submit" style="clear: both;">
372
+ <input type="submit" name="Submit" class="button-primary" value="ذخیره تنظیمات"/>
373
+ <input type="hidden" name="pw-settings-submit" value="Y"/>
374
+ <input type="hidden" name="pw-tab" value="<?php echo esc_attr( $tab ); ?>"/>
375
+ <input type="hidden" name="pw-section" value="<?php echo esc_attr( $section ); ?>"/>
376
+ </p>
377
+ </form>
378
+ </div>
379
+
380
+ </div>
381
+ <script type="text/javascript">
382
+ jQuery(document).ready(function ($) {
383
+ $('.persian-woocommerce').on('click', '.select_all', function () {
384
+ jQuery(this).closest('td').find('select option').attr('selected', 'selected');
385
+ jQuery(this).closest('td').find('select').trigger('change');
386
+ return false;
387
+ }).on('click', '.select_none', function () {
388
+ jQuery(this).closest('td').find('select option').removeAttr('selected');
389
+ jQuery(this).closest('td').find('select').trigger('change');
390
+ return false;
391
+ });
392
+
393
+ $('select#PW_Options\\[allowed_states\\]').change(function () {
394
+ if (jQuery(this).val() === 'specific') {
395
+ jQuery(this).parent().parent().next('tr').show();
396
+ } else {
397
+ jQuery(this).parent().parent().next('tr').hide();
398
+ }
399
+ }).change();
400
+ });
401
+ </script>
402
+ <?php
403
+ }
404
+
405
+ public function tools_save() {
406
+
407
+ $page = sanitize_text_field( $_GET['page'] ?? null );
408
+
409
+ if ( $page != 'persian-wc-tools' ) {
410
+ return;
411
  }
412
 
413
+ if ( isset( $_POST['pw-settings-submit'] ) && $_POST['pw-settings-submit'] == 'Y' ) {
414
 
415
+ $settings = $this->tools_sections();
416
+ $tab = sanitize_text_field( $_POST['pw-tab'] );
417
+ $section = sanitize_text_field( $_POST['pw-section'] );
418
+
419
+ check_admin_referer( 'persian-wc-tools' );
420
+
421
+ do_action( 'PW_before_save_tools', $_POST, $settings, $tab, $section );
422
+
423
+ WC_Admin_Settings::save_fields( empty( $section ) ? $settings[ $tab ] : $settings[ $tab ][ $section ] );
424
+
425
+ do_action( 'PW_after_save_tools', $_POST, $settings, $tab, $section );
426
 
427
+ $url_parameters = empty( $section ) ? $tab : $tab . '&section=' . $section;
428
 
429
+ wp_redirect( admin_url( 'admin.php?page=persian-wc-tools&updated=1&tab=' . $url_parameters ) );
430
+ exit;
431
+ }
432
+ }
433
+
434
+ public function specific_states_field( $value ) {
435
+
436
+ $selections = (array) PW()->get_options( 'specific_allowed_states' );
437
+ ?>
438
+ <tr valign="top">
439
+ <th scope="row" class="titledesc">
440
+ <label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
441
+ </th>
442
+ <td class="forminp">
443
+ <select multiple="multiple" name="<?php echo esc_attr( $value['id'] ); ?>[]" style="width:350px"
444
+ data-placeholder="استان (ها) مورد نظر خود را انتخاب کنید ..." title="استان"
445
+ class="wc-enhanced-select">
446
+ <?php
447
+ if ( ! empty( PW()->address->states ) ) {
448
+ foreach ( PW()->address->states as $key => $val ) {
449
+ echo '<option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $selections ), true, false ) . '>' . esc_attr( $val ) . '</option>';
450
  }
451
  }
452
+ ?>
453
+ </select> <br/><a class="select_all button" href="#"><?php _e( 'Select all', 'woocommerce' ); ?></a> <a
454
+ class="select_none button" href="#"><?php _e( 'Select none', 'woocommerce' ); ?></a>
455
+ </td>
456
+ </tr><?php
457
+ }
458
+
459
+ public function get_tools_default( $tools = null ): array {
460
 
461
+ if ( is_null( $tools ) ) {
462
+ $tools = $this->tools_sections();
463
  }
464
+
465
+ $output = [];
466
+
467
+ foreach ( $tools as $tool => $tool_name ) {
468
+ if ( isset( $tool_name['id'], $tool_name['default'] ) ) {
469
+ $output[ $tool_name['id'] ] = $tool_name['default'];
470
+ } elseif ( is_array( $tool_name ) ) {
471
+ $array = $this->get_tools_default( $tool_name );
472
+ if ( count( $array ) ) {
473
+ $output += $array;
474
+ }
475
+ }
476
+ }
477
+
478
+ return $output;
479
  }
480
+ }
481
 
482
  PW()->tools = new Persian_Woocommerce_Tools();
483
 
484
  do_action( 'PW_Tools_load', PW()->get_options() );
485
 
486
+ require_once 'tools/class-general.php';
487
+ require_once 'tools/class-price.php';
488
+ require_once 'tools/class-datepicker.php';
489
+ require_once 'tools/class-date.php';
490
+ require_once 'tools/class-checkout.php';
include/class-translate.php CHANGED
@@ -1,247 +1,254 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
-
5
- if ( ! class_exists( 'Persian_Woocommerce_Translate' ) ) :
6
 
7
- class Persian_Woocommerce_Translate extends Persian_Woocommerce_Core {
8
 
9
- public $table, $translates;
10
 
11
- public function __construct() {
12
 
13
- $this->translates();
14
 
15
- add_filter( 'override_unload_textdomain', array( $this, 'unload_textdomain' ), 9999, 2 );
16
- add_filter( 'load_textdomain_mofile', array( $this, 'load_textdomain' ), 10, 2 );
17
 
18
- add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
19
- add_action( 'admin_init', array( $this, 'search_delete' ) );
20
 
21
- add_action( 'wp_ajax_woocommerce_persian_save_translates', array( $this, 'save_translates' ) );
22
- add_action( 'wp_ajax_nopriv_woocommerce_persian_save_translates', array( $this, 'save_translates' ) );
23
- }
24
 
25
- public function unload_textdomain( $override, $domain ) {
26
- return get_locale() == 'fa_IR' && $domain === 'woocommerce' ? true : $override;
27
- }
28
 
29
- public function load_textdomain( $mo_file, $domain ) {
30
- if ( get_locale() == 'fa_IR' && $domain === 'woocommerce' ) {
31
- $mo_file = dirname( plugin_dir_path( __FILE__ ) ) . '/languages/woocommerce-fa_IR.mo';
32
- }
33
 
34
- return $mo_file;
 
 
35
  }
36
 
37
- public function translates() {
38
- global $wpdb;
39
 
40
- $this->table = $wpdb->prefix . 'woocommerce_ir';
 
41
 
42
- if ( ! is_array( $this->translates ) ) {
43
- $wpdb->suppress_errors = true;
44
- $result = $wpdb->get_results( "SELECT * FROM {$this->table};" );
45
- $wpdb->suppress_errors = false;
46
 
47
- if ( ! $wpdb->last_error ) {
48
- $this->translates = wp_list_pluck( $result, 'text2', 'text1' );
49
- }
50
- }
51
 
52
- if ( is_array( $this->translates ) && count( $this->translates ) ) {
53
- add_filter( 'gettext_with_context', array( $this, 'gettext' ) );
54
- add_filter( 'ngettext_with_context', array( $this, 'gettext' ) );
55
- add_filter( 'gettext', array( $this, 'gettext' ) );
56
- add_filter( 'ngettext', array( $this, 'gettext' ) );
57
  }
58
  }
59
 
60
- public function gettext( $text ) {
61
- return isset( $this->translates[ $text ] ) ? $this->translates[ $text ] : $text;
 
 
 
62
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
- public function translate_page() {
65
- do_action( 'add_meta_boxes', 'woocommerce_persian_translate', 0 );
66
- ?>
67
- <div class="wrap">
68
- <h2 id="title">حلقه های ترجمه</h2>
69
- <div class="fx-settings-meta-box-wrap">
70
- <div id="poststuff">
71
- <div id="post-body" class="metabox-holder columns-2">
72
- <div id="postbox-container-1" class="postbox-container">
73
- <?php do_meta_boxes( 'woocommerce_persian_translate', 'side', null ); ?>
74
- </div>
75
-
76
- <div id="postbox-container-2" class="postbox-container">
77
- <?php settings_errors();
78
- echo '<form method="POST" id="list-project">';
79
- echo '<input type="hidden" name="page" value="persian-wc" />';
80
- wp_nonce_field( 'delete_item', 'woocommerce_persian_translate_nonce' );
81
- $list = new Persian_Woocommerce_Translate_List_Table();
82
- $list->search_box( 'جستجو', 'PW-search-input' );
83
- $list->prepare_items();
84
- $list->display();
85
- echo '</form>';
86
- ?>
87
- <div class="clear"></div>
88
- </div>
89
- </div>
90
- <br class="clear">
91
- </div>
92
- </div>
93
- </div>
94
- <script type="text/javascript">
95
- jQuery(document).ready(function ( $ ) {
96
- $("#woocommerce_persian_translate").submit(function () {
97
- $("#save_loop_button").val("در حال ذخیره ...");
98
- jQuery.post(ajaxurl, $("#woocommerce_persian_translate").serialize(), function ( response ) {
99
- var obj = jQuery.parseJSON(response);
100
- if( obj.success ) {
101
- $("#the-list").prepend(obj.code);
102
- $(".displaying-num").html(obj.count);
103
- document.getElementById("woocommerce_persian_translate").reset();
104
- if( obj.count === "1 مورد" ) {
105
- $("tr.no-items").remove();
106
- $(".tablenav-pages").removeClass("no-pages").addClass("one-page");
107
- }
108
- }
109
- setTimeout(function () {
110
- $("#setting-error-pw_msg_" + obj.rand).slideUp('slow', function () {
111
- $("#setting-error-pw_msg_" + obj.rand).remove();
112
- })
113
- }, 3000);
114
- $(".wrap h2#title").after(obj.message);
115
- });
116
- setTimeout(function () {
117
- $("#save_loop_button").val("ذخیره حلقه");
118
- }, 2000);
119
- return false;
120
- });
121
- });
122
- </script>
123
- <?php
124
  }
125
 
126
- public function add_meta_box() {
127
- add_meta_box( 'add_form', 'افزودن حلقه ترجمه', array(
128
- $this,
129
- 'meta_box_form'
130
- ), 'woocommerce_persian_translate', 'side', 'high' );
 
 
131
  }
132
 
133
- public function meta_box_form() {
134
- ?>
135
- <form action="" method="post" id="woocommerce_persian_translate">
136
- <input type="hidden" name="s"
137
- value="<?php echo isset( $_GET['s'] ) && ! empty( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : ''; ?>"/>
138
- <input type="hidden" name="action" value="woocommerce_persian_save_translates"/>
139
- <input type="hidden" name="security"
140
- value="<?php echo wp_create_nonce( 'woocommerce_persian_save_translates' ); ?>"/>
141
- <label for="input_text_1">کلمه‌ی مورد نظر :</label>
142
- <input type="text" class="widefat" id="input_text_1" name="text1"/>
143
- <br>
144
- <label for="input_text_2">جایگزین شود با :</label>
145
- <input type="text" class="widefat" id="input_text_2" name="text2"/>
146
- <?php echo '</div>'; ?>
147
- <div id="major-publishing-actions">
148
- <div id="publishing-action">
149
- <span class="spinner"></span>
150
- <?php submit_button( esc_attr( 'ذخیره حلقه' ), 'primary', 'submit', false, array( 'id' => 'save_loop_button' ) ); ?>
151
- </div>
152
- <div class="clear"></div>
153
- </form>
154
- <?php
155
  }
156
 
157
- public function save_translates() {
158
- global $wpdb;
159
 
160
- check_ajax_referer( 'woocommerce_persian_save_translates', 'security' );
161
 
162
- $json = [
163
- 'success' => false,
164
- 'message' => 'مشکلی هنگام افزودن حلقه رخ داده است. لطفا مجددا تلاش کنید.',
165
- 'rand' => mt_rand()
166
- ];
 
167
 
168
- if ( isset( $_POST['text1'], $_POST['text2'], $_POST['s'] ) ) {
169
 
170
- if ( ! empty( $_POST['text1'] ) ) {
171
 
172
- $insert = $wpdb->insert( $this->table, [
173
- 'text1' => $_POST['text1'],
174
- 'text2' => $_POST['text2']
175
- ] );
176
 
177
- if ( $insert ) {
 
178
 
179
- $json['success'] = true;
180
- $json['message'] = sprintf( '<div id="setting-error-pw_msg_%d" class="updated settings-error notice is-dismissible"><p><strong>حلقه (%s => %s) با موفقیت افزوده شد.</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">بستن این اعلان.</span></button></div>', $json['rand'], $_POST['text1'], $_POST['text2'] );
181
 
182
- $json['code'] = '';
 
 
183
 
184
- if ( empty( $_POST['s'] ) || array_search( $_POST['s'], [
185
- $_POST['text1'],
186
- $_POST['text2']
187
- ] ) !== false ) {
188
- $json['code'] = sprintf( '<tr id="PW_item_%1$d" data-id="%1$d"><th scope="row" class="check-column"><input name="text_delete_id[]" value="%1$d" type="checkbox"></th><td class="text1 column-text1 has-row-actions column-primary" data-colname="حلقه‌ی اصلی">%2$s<button type="button" class="toggle-row"><span class="screen-reader-text">نمایش جزئیات بیشتر</span></button></td><td class="text2 column-text2" data-colname="حلقه‌ی جایگزین شده">%3$s</td></tr>', $wpdb->insert_id, $_POST['text1'], $_POST['text2'] );
189
- }
190
 
191
- $search = empty( $_POST['s'] ) ? '' : sprintf( ' WHERE text1 LIKE "%%%1$s%%" OR text2 LIKE "%%%1$s%%"', sanitize_text_field( $_POST['s'] ) );
192
 
193
- $json['count'] = $wpdb->get_var( "SELECT COUNT(*) FROM $this->table{$search}" ) . " مورد";
194
 
195
- } else {
196
- $json['message'] = sprintf( '<div id="setting-error-pw_msg_%d" class="error settings-error notice is-dismissible"><p><strong>خطایی در زمان افزودن حلقه (%s => %s) به دیتابیس رخ داده است. لطفا مجددا تلاش کنید</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">بستن این اعلان.</span></button></div>', $json['rand'], $_POST['text1'], $_POST['text2'] );
197
- }
198
  } else {
199
- $json['message'] = sprintf( '<div id="setting-error-pw_msg_%d" class="error settings-error notice is-dismissible"><p><strong>پر کردن فیلد کلمه‌ی مورد نظر اجباری می باشد.</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">بستن این اعلان.</span></button></div>', $json['rand'] );
200
  }
201
  }
202
 
203
- die( json_encode( $json ) );
204
- }
205
-
206
- public function search_delete() {
207
-
208
- if ( empty( $_GET['page'] ) || $_GET['page'] != 'persian-wc' ) {
209
- return;
210
  }
211
 
212
- if ( isset( $_POST['s'] ) ) {
213
- if ( empty( $_POST['s'] ) && isset( $_GET['s'] ) ) {
214
- wp_redirect( remove_query_arg( array( 's' ), stripslashes( $_SERVER['REQUEST_URI'] ) ) );
215
- exit;
216
- } else if ( ! empty( $_POST['s'] ) ) {
217
- wp_redirect( add_query_arg( array( 's' => $_POST['s'] ), stripslashes( $_SERVER['REQUEST_URI'] ) ) );
218
- exit;
219
- }
220
  }
 
221
 
222
- if ( isset( $_POST['action'], $_POST['text_delete_id'] ) && check_admin_referer( 'delete_item', 'woocommerce_persian_translate_nonce' ) ) {
223
- $success = $failed = 0;
224
- foreach ( $_POST['text_delete_id'] as $delete_id ) {
225
- global $wpdb;
226
- $delete = $wpdb->delete( $wpdb->prefix . 'woocommerce_ir', array( 'id' => intval( $delete_id ) ) );
227
- if ( $delete ) {
228
- $success ++;
229
- } else {
230
- $failed ++;
231
- }
232
- }
233
 
234
- if ( $success ) {
235
- add_settings_error( 'delete_text', 'pw_msg', sprintf( '%d حلقه با موفقیت حذف شد.', $success ), 'updated' );
236
- }
237
-
238
- if ( $failed ) {
239
- add_settings_error( 'delete_text', 'pw_msg', sprintf( 'حذف %d حلقه با شکست مواجه شد.', $failed ) );
240
- }
241
  }
 
 
242
  }
243
  }
244
- endif;
 
245
  PW()->translate = new Persian_Woocommerce_Translate();
246
 
247
  if ( ! class_exists( 'WP_List_Table' ) ) {
@@ -250,7 +257,7 @@ if ( ! class_exists( 'WP_List_Table' ) ) {
250
 
251
  class Persian_Woocommerce_Translate_List_Table extends WP_List_Table {
252
 
253
- private $data = array();
254
 
255
  public function __construct() {
256
 
@@ -267,56 +274,48 @@ class Persian_Woocommerce_Translate_List_Table extends WP_List_Table {
267
 
268
  $this->data = $wpdb->get_results( "SELECT * FROM `{$wpdb->prefix}woocommerce_ir`{$search} ORDER BY id DESC LIMIT $db_page, $perPage;", ARRAY_A );
269
 
270
- $this->set_pagination_args( array(
271
  'total_items' => $wpdb->get_var( "SELECT COUNT(*) FROM `{$wpdb->prefix}woocommerce_ir`{$search};" ),
272
- 'per_page' => $perPage
273
- ) );
274
 
275
- parent::__construct( array(
276
  'singular' => 'text',
277
  'plural' => 'texts',
278
- 'ajax' => false
279
- ) );
280
  }
281
 
282
- public function column_default( $item, $column_name ) {
283
- return isset( $item[ $column_name ] ) ? $item[ $column_name ] : '';
284
  }
285
 
286
- public function get_columns() {
287
- return array(
288
  'cb' => '<input type="checkbox" />',
289
  'text1' => 'کلمه اصلی',
290
  'text2' => 'کلمه جایگزین شده',
291
- );
292
  }
293
 
294
- public function column_cb( $item ) {
295
- return sprintf( '<input type="checkbox" name="text_delete_id[]" value="%s" />', $item['id'] );
296
  }
297
 
298
  public function prepare_items() {
299
- $this->_column_headers = array( $this->get_columns(), array(), array() );
300
  $this->items = $this->data;;
301
  }
302
 
303
  public function single_row( $item ) {
304
- echo "<tr id='PW_item_{$item['id']}' data-id='{$item['id']}' >";
305
  $this->single_row_columns( $item );
306
  echo '</tr>';
307
  }
308
 
309
- public function get_bulk_actions() {
310
- return array( 'delete' => 'حذف' );
311
- }
312
-
313
- public function search_box( $text, $input_id ) {
314
- ?>
315
- <p class="search-box">
316
- <label class="screen-reader-text" for="<?php echo $input_id; ?>"><?php echo $text; ?>:</label>
317
- <input type="search" id="<?php echo $input_id; ?>" name="s" value="<?php _admin_search_query(); ?>"/>
318
- <?php submit_button( $text, 'button', '', false, array( 'id' => 'search-submit' ) ); ?>
319
- </p>
320
- <?php
321
  }
322
  }
1
+ <?php
 
 
 
 
2
 
3
+ defined( 'ABSPATH' ) || exit;
4
 
5
+ class Persian_Woocommerce_Translate extends Persian_Woocommerce_Core {
6
 
7
+ public $table, $translates;
8
 
9
+ public function __construct() {
10
 
11
+ $this->translates();
 
12
 
13
+ add_filter( 'override_unload_textdomain', [ $this, 'unload_textdomain' ], 9999, 2 );
14
+ add_filter( 'load_textdomain_mofile', [ $this, 'load_textdomain' ], 10, 2 );
15
 
16
+ add_action( 'add_meta_boxes', [ $this, 'add_meta_box' ] );
17
+ add_action( 'admin_init', [ $this, 'search_delete' ] );
 
18
 
19
+ add_action( 'wp_ajax_pw_save_translates', [ $this, 'save_translates' ] );
20
+ add_action( 'wp_ajax_nopriv_pw_save_translates', [ $this, 'save_translates' ] );
21
+ }
22
 
23
+ public function unload_textdomain( $override, $domain ) {
24
+ return get_locale() == 'fa_IR' && $domain === 'woocommerce' ? true : $override;
25
+ }
 
26
 
27
+ public function load_textdomain( $mo_file, $domain ) {
28
+ if ( get_locale() == 'fa_IR' && $domain === 'woocommerce' ) {
29
+ $mo_file = dirname( plugin_dir_path( __FILE__ ) ) . '/languages/woocommerce-fa_IR.mo';
30
  }
31
 
32
+ return $mo_file;
33
+ }
34
 
35
+ public function translates() {
36
+ global $wpdb;
37
 
38
+ $this->table = $wpdb->prefix . 'woocommerce_ir';
 
 
 
39
 
40
+ if ( ! is_array( $this->translates ) ) {
41
+ $wpdb->suppress_errors = true;
42
+ $result = $wpdb->get_results( "SELECT * FROM {$this->table};" );
43
+ $wpdb->suppress_errors = false;
44
 
45
+ if ( ! $wpdb->last_error ) {
46
+ $this->translates = wp_list_pluck( $result, 'text2', 'text1' );
 
 
 
47
  }
48
  }
49
 
50
+ if ( is_array( $this->translates ) && count( $this->translates ) ) {
51
+ add_filter( 'gettext_with_context', [ $this, 'gettext' ] );
52
+ add_filter( 'ngettext_with_context', [ $this, 'gettext' ] );
53
+ add_filter( 'gettext', [ $this, 'gettext' ] );
54
+ add_filter( 'ngettext', [ $this, 'gettext' ] );
55
  }
56
+ }
57
+
58
+ public function gettext( $text ) {
59
+ return $this->translates[ $text ] ?? $text;
60
+ }
61
+
62
+ public function translate_page() {
63
+ do_action( 'add_meta_boxes', 'woocommerce_persian_translate', 0 );
64
+ ?>
65
+ <div class="wrap">
66
+ <h2 id="title">حلقه های ترجمه</h2>
67
+ <div class="fx-settings-meta-box-wrap">
68
+ <div id="poststuff">
69
+ <div id="post-body" class="metabox-holder columns-2">
70
+ <div id="postbox-container-1" class="postbox-container">
71
+ <?php do_meta_boxes( 'woocommerce_persian_translate', 'side', null ); ?>
72
+ </div>
73
+
74
+ <div id="postbox-container-2" class="postbox-container">
75
+ <?php settings_errors();
76
+ echo '<form method="POST" id="list-project">';
77
+ echo '<input type="hidden" name="page" value="persian-wc" />';
78
+ wp_nonce_field( 'delete_item', 'pw_translate_nonce' );
79
+ $list = new Persian_Woocommerce_Translate_List_Table();
80
+ $list->prepare_items();
81
+ $list->search_box( 'جستجو', 'PW-search-input' );
82
+ $list->display();
83
+ echo '</form>';
84
+ ?>
85
+ <div class="clear"></div>
86
+ </div>
87
+ </div>
88
+ <br class="clear">
89
+ </div>
90
+ </div>
91
+ </div>
92
+ <script type="text/javascript">
93
+ jQuery(document).ready(function ($) {
94
+ $("#woocommerce_persian_translate").submit(function () {
95
+ $("#save_loop_button").val("در حال ذخیره ...");
96
+ jQuery.post(ajaxurl, $("#woocommerce_persian_translate").serialize(), function (response) {
97
+ var obj = jQuery.parseJSON(response);
98
+ if (obj.success) {
99
+ $("#the-list").prepend(obj.code);
100
+ $(".displaying-num").html(obj.count);
101
+ document.getElementById("woocommerce_persian_translate").reset();
102
+ if (obj.count === "1 مورد") {
103
+ $("tr.no-items").remove();
104
+ $(".tablenav-pages").removeClass("no-pages").addClass("one-page");
105
+ }
106
+ }
107
+ setTimeout(function () {
108
+ $("#setting-error-pw_msg_" + obj.rand).slideUp('slow', function () {
109
+ $("#setting-error-pw_msg_" + obj.rand).remove();
110
+ })
111
+ }, 3000);
112
+ $(".wrap h2#title").after(obj.message);
113
+ });
114
+ setTimeout(function () {
115
+ $("#save_loop_button").val("ذخیره حلقه");
116
+ }, 2000);
117
+ return false;
118
+ });
119
+ });
120
+ </script>
121
+ <?php
122
+ }
123
+
124
+ public function add_meta_box() {
125
+ add_meta_box( 'add_form', 'افزودن حلقه ترجمه', [
126
+ $this,
127
+ 'meta_box_form',
128
+ ], 'woocommerce_persian_translate', 'side', 'high' );
129
+ }
130
+
131
+ public function meta_box_form() {
132
+ ?>
133
+ <form action="" method="post" id="woocommerce_persian_translate">
134
+ <input type="hidden" name="s" value="<?php echo esc_attr( $_GET['s'] ?? null ); ?>"/>
135
+ <input type="hidden" name="action" value="pw_save_translates"/>
136
+ <input type="hidden" name="security"
137
+ value="<?php echo wp_create_nonce( 'pw_save_translates' ); ?>"/>
138
+ <label for="input_text_1">کلمه‌ی مورد نظر:</label>
139
+ <input type="text" class="widefat" id="input_text_1" name="text1"/>
140
+ <br>
141
+ <label for="input_text_2">جایگزین شود با:</label>
142
+ <input type="text" class="widefat" id="input_text_2" name="text2"/>
143
+ <?php echo '</div>'; ?>
144
+ <div id="major-publishing-actions">
145
+ <div id="publishing-action">
146
+ <span class="spinner"></span>
147
+ <?php submit_button( 'ذخیره حلقه', 'primary', 'submit', false, [ 'id' => 'save_loop_button' ] ); ?>
148
+ </div>
149
+ <div class="clear"></div>
150
+ </form>
151
+ <?php
152
+ }
153
+
154
+ public function save_translates() {
155
+ global $wpdb;
156
+
157
+ check_ajax_referer( 'pw_save_translates', 'security' );
158
 
159
+ $json = [
160
+ 'success' => false,
161
+ 'message' => 'مشکلی هنگام افزودن حلقه رخ داده است. لطفا مجددا تلاش کنید.',
162
+ 'rand' => mt_rand(),
163
+ ];
164
+
165
+ if ( ! isset( $_POST['text1'], $_POST['text2'], $_POST['s'] ) ) {
166
+ die( json_encode( $json ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
 
169
+ $text1 = wp_kses_data( $_POST['text1'] );
170
+ $text2 = wp_kses_data( $_POST['text2'] );
171
+ $s = sanitize_text_field( $_POST['s'] );
172
+
173
+ if ( empty( $text1 ) ) {
174
+ $json['message'] = sprintf( '<div id="setting-error-pw_msg_%d" class="error settings-error notice is-dismissible"><p><strong>پر کردن فیلد کلمه‌ی مورد نظر اجباری می باشد.</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">بستن این اعلان.</span></button></div>', $json['rand'] );
175
+ die( json_encode( $json ) );
176
  }
177
 
178
+ $insert = $wpdb->insert( $this->table, [
179
+ 'text1' => esc_html( $text1 ),
180
+ 'text2' => esc_html( $text2 ),
181
+ ] );
182
+
183
+ if ( ! $insert ) {
184
+ $json['message'] = sprintf( '<div id="setting-error-pw_msg_%d" class="error settings-error notice is-dismissible"><p><strong>خطایی در زمان افزودن حلقه (%s => %s) به دیتابیس رخ داده است. لطفا مجددا تلاش کنید</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">بستن این اعلان.</span></button></div>', $json['rand'], $text1, $text2 );
185
+ die( json_encode( $json ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  }
187
 
188
+ $json['success'] = true;
189
+ $json['message'] = sprintf( '<div id="setting-error-pw_msg_%d" class="updated settings-error notice is-dismissible"><p><strong>حلقه (%s => %s) با موفقیت افزوده شد.</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">بستن این اعلان.</span></button></div>', $json['rand'], $text1, $text2 );
190
 
191
+ $json['code'] = '';
192
 
193
+ if ( empty( $s ) || array_search( $s, [
194
+ $text1,
195
+ $text2,
196
+ ] ) !== false ) {
197
+ $json['code'] = sprintf( '<tr id="PW_item_%1$d" data-id="%1$d"><th scope="row" class="check-column"><input name="text_delete_id[]" value="%1$d" type="checkbox"></th><td class="text1 column-text1 has-row-actions column-primary" data-colname="حلقه‌ی اصلی">%2$s<button type="button" class="toggle-row"><span class="screen-reader-text">نمایش جزئیات بیشتر</span></button></td><td class="text2 column-text2" data-colname="حلقه‌ی جایگزین شده">%3$s</td></tr>', $wpdb->insert_id, $text1, $text2 );
198
+ }
199
 
200
+ $search = empty( $s ) ? '' : sprintf( ' WHERE text1 LIKE "%%%1$s%%" OR text2 LIKE "%%%1$s%%"', $s );
201
 
202
+ $json['count'] = $wpdb->get_var( "SELECT COUNT(*) FROM $this->table{$search}" ) . " مورد";
203
 
204
+ die( json_encode( $json ) );
205
+ }
 
 
206
 
207
+ public function search_delete() {
208
+ global $wpdb;
209
 
210
+ $page = sanitize_text_field( $_GET['page'] ?? null );
 
211
 
212
+ if ( $page != 'persian-wc' ) {
213
+ return;
214
+ }
215
 
216
+ if ( isset( $_POST['action'], $_POST['text_delete_id'] ) && check_admin_referer( 'delete_item', 'pw_translate_nonce' ) ) {
217
+ $success = $failed = 0;
 
 
 
 
218
 
219
+ foreach ( (array) $_POST['text_delete_id'] as $delete_id ) {
220
 
221
+ $delete = $wpdb->delete( $wpdb->prefix . 'woocommerce_ir', [ 'id' => intval( $delete_id ) ] );
222
 
223
+ if ( $delete ) {
224
+ $success ++;
 
225
  } else {
226
+ $failed ++;
227
  }
228
  }
229
 
230
+ if ( $success ) {
231
+ add_settings_error( 'delete_text', 'pw_msg', sprintf( '%d حلقه با موفقیت حذف شد.', $success ), 'updated' );
 
 
 
 
 
232
  }
233
 
234
+ if ( $failed ) {
235
+ add_settings_error( 'delete_text', 'pw_msg', sprintf( 'حذف %d حلقه با شکست مواجه شد.', $failed ) );
 
 
 
 
 
 
236
  }
237
+ }
238
 
239
+ if ( isset( $_POST['s'] ) ) {
 
 
 
 
 
 
 
 
 
 
240
 
241
+ if ( empty( $_POST['s'] ) ) {
242
+ wp_redirect( remove_query_arg( [ 's' ], stripslashes( $_SERVER['REQUEST_URI'] ) ) );
243
+ } else {
244
+ wp_redirect( add_query_arg( [ 's' => urlencode( $_POST['s'] ) ], stripslashes( $_SERVER['REQUEST_URI'] ) ) );
 
 
 
245
  }
246
+
247
+ exit;
248
  }
249
  }
250
+ }
251
+
252
  PW()->translate = new Persian_Woocommerce_Translate();
253
 
254
  if ( ! class_exists( 'WP_List_Table' ) ) {
257
 
258
  class Persian_Woocommerce_Translate_List_Table extends WP_List_Table {
259
 
260
+ private $data;
261
 
262
  public function __construct() {
263
 
274
 
275
  $this->data = $wpdb->get_results( "SELECT * FROM `{$wpdb->prefix}woocommerce_ir`{$search} ORDER BY id DESC LIMIT $db_page, $perPage;", ARRAY_A );
276
 
277
+ $this->set_pagination_args( [
278
  'total_items' => $wpdb->get_var( "SELECT COUNT(*) FROM `{$wpdb->prefix}woocommerce_ir`{$search};" ),
279
+ 'per_page' => $perPage,
280
+ ] );
281
 
282
+ parent::__construct( [
283
  'singular' => 'text',
284
  'plural' => 'texts',
285
+ 'ajax' => false,
286
+ ] );
287
  }
288
 
289
+ public function column_default( $item, $column_name ): string {
290
+ return esc_html( $item[ $column_name ] ?? null );
291
  }
292
 
293
+ public function get_columns(): array {
294
+ return [
295
  'cb' => '<input type="checkbox" />',
296
  'text1' => 'کلمه اصلی',
297
  'text2' => 'کلمه جایگزین شده',
298
+ ];
299
  }
300
 
301
+ public function column_cb( $item ): string {
302
+ return sprintf( '<input type="checkbox" name="text_delete_id[]" value="%d" />', $item['id'] );
303
  }
304
 
305
  public function prepare_items() {
306
+ $this->_column_headers = [ $this->get_columns(), [], [] ];
307
  $this->items = $this->data;;
308
  }
309
 
310
  public function single_row( $item ) {
311
+ printf( "<tr id='PW_item_$1%d' data-id='$1%d'>", $item['id'] );
312
  $this->single_row_columns( $item );
313
  echo '</tr>';
314
  }
315
 
316
+ public function get_bulk_actions(): array {
317
+ return [
318
+ 'delete' => 'حذف',
319
+ ];
 
 
 
 
 
 
 
 
320
  }
321
  }
include/class-widget.php CHANGED
@@ -1,77 +1,75 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
 
5
- if ( ! class_exists( 'Persian_Woocommerce_Widget' ) ) :
6
 
7
- class Persian_Woocommerce_Widget extends Persian_Woocommerce_Core {
8
 
9
- public function __construct() {
10
- add_action( 'wp_dashboard_setup', array( $this, 'widget_setup' ) );
11
- }
12
 
13
- public function widget_setup() {
14
- wp_add_dashboard_widget( 'persian_woocommerce_feed',
15
- 'آخرین اخبار و اطلاعیه های ووکامرس پارسی',
16
- array( $this, 'widget_render' ),
17
- array( $this, 'widget_settings' ) );
18
- }
19
 
20
- public function widget_render() { ?>
21
 
22
- <div class="rss-widget">
23
 
24
- <?php $widget_options = $this->widget_options();
25
 
26
- wp_widget_rss_output( array(
27
- 'url' => 'http://woocommerce.ir/feed/',
28
- 'title' => 'آخرین اخبار و اطلاعیه های ووکامرس پارسی',
29
- 'meta' => array( 'target' => '_new' ),
30
- 'items' => $widget_options['posts_number'],
31
- 'show_summary' => 1,
32
- 'show_author' => 0,
33
- 'show_date' => 1
34
- ) );
35
- ?>
36
 
37
- <div style="border-top: 1px solid #e7e7e7; padding-top: 12px !important; font-size: 12px;">
38
- <?php echo '<img src="' . PW()->plugin_url( 'assets/images/feed.png' ) . '" width="16" height="16" > '; ?>
39
- <a href="http://woocommerce.ir" target="_new" title="خانه">وب سایت پشتیبان ووکامرس پارسی</a>
40
- </div>
41
- </div>
42
- <?php
43
- }
44
 
45
- public function widget_settings() {
46
 
47
- $options = $this->widget_options();
48
 
49
- if ( 'post' == strtolower( $_SERVER['REQUEST_METHOD'] ) && isset( $_POST['widget_id'] ) && 'persian_woocommerce_feed' == $_POST['widget_id'] ) {
50
- $options['posts_number'] = $_POST['posts_number'];
51
- update_option( 'persian_woocommerce_feed', $options );
52
- }
53
- ?>
54
- <p>
55
- <label for="posts_number">تعداد نوشته های قابل نمایش در ابزارک ووکامرس پارسی:
56
- <select id="posts_number" name="posts_number">
57
- <?php for ( $i = 3; $i <= 20; $i ++ ) {
58
- echo "<option value='$i'" . ' ' . selected( $options['posts_number'], $i, false ) . ">$i</option>";
59
- }
60
- ?>
61
- </select>
62
- </label>
63
- </p>
64
- <?php
65
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
- public function widget_options() {
68
- $defaults = array( 'posts_number' => 5 );
69
- if ( ( ! $options = get_option( 'persian_woocommerce_feed' ) ) || ! is_array( $options ) ) {
70
- $options = array();
71
- }
72
-
73
- return array_merge( $defaults, $options );
74
  }
 
 
75
  }
76
- endif;
77
- PW()->widget = new Persian_Woocommerce_Widget();
 
1
+ <?php
 
 
2
 
3
+ defined( 'ABSPATH' ) || exit;
4
 
5
+ class Persian_Woocommerce_Widget extends Persian_Woocommerce_Core {
6
 
7
+ public function __construct() {
8
+ add_action( 'wp_dashboard_setup', [ $this, 'widget_setup' ] );
9
+ }
10
 
11
+ public function widget_setup() {
12
+ wp_add_dashboard_widget( 'persian_woocommerce_feed',
13
+ 'آخرین اخبار و اطلاعیه های ووکامرس پارسی',
14
+ [ $this, 'widget_render' ],
15
+ [ $this, 'widget_settings' ] );
16
+ }
17
 
18
+ public function widget_render() { ?>
19
 
20
+ <div class="rss-widget">
21
 
22
+ <?php $widget_options = $this->widget_options();
23
 
24
+ wp_widget_rss_output( [
25
+ 'url' => 'http://woocommerce.ir/feed/',
26
+ 'title' => 'آخرین اخبار و اطلاعیه های ووکامرس پارسی',
27
+ 'meta' => [ 'target' => '_new' ],
28
+ 'items' => intval( $widget_options['posts_number'] ),
29
+ 'show_summary' => 1,
30
+ 'show_author' => 0,
31
+ 'show_date' => 1,
32
+ ] );
33
+ ?>
34
 
35
+ <div style="border-top: 1px solid #e7e7e7; padding-top: 12px !important; font-size: 12px;">
36
+ <img src="<?php echo PW()->plugin_url( 'assets/images/feed.png' ); ?>" width="16" height="16">
37
+ <a href="http://woocommerce.ir" target="_new" title="خانه">وب سایت پشتیبان ووکامرس پارسی</a>
38
+ </div>
39
+ </div>
40
+ <?php
41
+ }
42
 
43
+ public function widget_settings() {
44
 
45
+ $options = $this->widget_options();
46
 
47
+ if ( 'post' == strtolower( $_SERVER['REQUEST_METHOD'] ) && isset( $_POST['widget_id'] ) && 'persian_woocommerce_feed' == $_POST['widget_id'] ) {
48
+ $options['posts_number'] = intval( $_POST['posts_number'] );
49
+ update_option( 'persian_woocommerce_feed', $options );
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
51
+ ?>
52
+ <p>
53
+ <label for="posts_number">تعداد نوشته های قابل نمایش در ابزارک ووکامرس پارسی:
54
+ <select id="posts_number" name="posts_number">
55
+ <?php for ( $i = 3; $i <= 20; $i ++ ) {
56
+ printf( '<option value="%d" %s>%d</option>', $i, selected( $options['posts_number'], $i, false ), $i );
57
+ }
58
+ ?>
59
+ </select>
60
+ </label>
61
+ </p>
62
+ <?php
63
+ }
64
 
65
+ public function widget_options() {
66
+ $defaults = [ 'posts_number' => 5 ];
67
+ if ( ( ! $options = get_option( 'persian_woocommerce_feed' ) ) || ! is_array( $options ) ) {
68
+ $options = [];
 
 
 
69
  }
70
+
71
+ return array_merge( $defaults, $options );
72
  }
73
+ }
74
+
75
+ new Persian_Woocommerce_Widget();
include/gateways/class-payir.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
- if ( ! defined( 'ABSPATH' ) ) {
3
- exit;
4
- }
5
 
6
  if ( ! class_exists( 'Woocommerce_Ir_Gateway_PayIr' ) ) :
7
 
@@ -19,35 +18,31 @@ if ( ! class_exists( 'Woocommerce_Ir_Gateway_PayIr' ) ) :
19
 
20
  public function fields() {
21
 
22
- return array(
23
- 'api' => array(
24
  'title' => 'API',
25
  'type' => 'text',
26
  'description' => 'API درگاه Pay.ir',
27
  'default' => '',
28
- 'desc_tip' => true
29
- ),
30
- 'sandbox' => array(
31
  'title' => 'فعالسازی حالت آزمایشی',
32
  'type' => 'checkbox',
33
  'label' => 'فعالسازی حالت آزمایشی Pay.ir',
34
  'description' => 'برای فعال سازی حالت آزمایشی Pay.ir چک باکس را تیک بزنید.',
35
  'default' => 'no',
36
  'desc_tip' => true,
37
- ),
38
- 'cancelled_massage' => array(),
39
- 'shortcodes' => array(
40
  'transaction_id' => 'شماره تراکنش',
41
- )
42
- );
43
  }
44
 
45
  public function request( $order ) {
46
 
47
- if ( ! extension_loaded( 'curl' ) ) {
48
- return 'تابع cURL روی هاست شما فعال نیست.';
49
- }
50
-
51
  $amount = $this->get_total( 'IRR' );
52
  $callback = $this->get_verify_url();
53
  $mobile = $this->get_order_mobile();
@@ -55,56 +50,73 @@ if ( ! class_exists( 'Woocommerce_Ir_Gateway_PayIr' ) ) :
55
  $description = 'شماره سفارش #' . $order_number;
56
  $apiID = $this->option( 'sandbox' ) == '1' ? 'test' : $this->option( 'api' );
57
 
58
- $ch = curl_init();
59
- curl_setopt( $ch, CURLOPT_URL, 'https://pay.ir/payment/send' );
60
- curl_setopt( $ch, CURLOPT_POSTFIELDS, "api=$apiID&amount=$amount&redirect=$callback&factorNumber=$order_number&mobile=$mobile&description=$description&resellerId=1000000800" );
61
- curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
62
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
63
- $result = curl_exec( $ch );
64
- curl_close( $ch );
65
- $result = json_decode( $result );
66
-
67
- if ( ! empty( $result->status ) && $result->status ) {
68
- return $this->redirect( 'https://pay.ir/payment/gateway/' . $result->transId );
 
 
 
 
 
 
 
 
 
 
 
69
  } else {
70
- return ! empty( $result->errorMessage ) ? $result->errorMessage : ( ! empty( $result->errorCode ) ? $this->errors( $result->errorCode ) : '' );
71
  }
72
  }
73
 
74
  public function verify( $order ) {
75
 
76
- $apiID = $this->option( 'sandbox' ) == '1' ? 'test' : $this->option( 'api' );
77
- $transaction_id = $this->post( 'transId' );
78
- //$factorNumber = $this->post( 'factorNumber' );
79
 
80
- $this->check_verification( $transaction_id );
81
 
82
  $error = '';
83
  $status = 'failed';
84
- if ( $apiID == 'test' || $this->post( 'status' ) ) {
85
-
86
- $ch = curl_init();
87
- curl_setopt( $ch, CURLOPT_URL, 'https://pay.ir/payment/verify' );
88
- curl_setopt( $ch, CURLOPT_POSTFIELDS, "api=$apiID&transId=$transaction_id" );
89
- curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
90
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
91
- $result = curl_exec( $ch );
92
- curl_close( $ch );
93
- $result = json_decode( $result );
94
-
95
- if ( ! empty( $result->status ) && $result->status ) {
96
- $status = 'completed';
97
- } else {
98
- $error = ! empty( $result->errorMessage ) ? $result->errorMessage : ( ! empty( $result->errorCode ) ? $this->errors( ( $result->errorCode . '1' ) ) : '' );
 
 
 
 
 
 
 
99
  }
100
 
101
  } else {
102
  $error = $this->post( 'message' );
103
  }
104
 
105
- $this->set_shortcodes( array( 'transaction_id' => $transaction_id ) );
106
 
107
- return compact( 'status', 'transaction_id', 'error' );
108
  }
109
 
110
  private function errors( $error ) {
@@ -152,7 +164,7 @@ if ( ! class_exists( 'Woocommerce_Ir_Gateway_PayIr' ) ) :
152
  break;
153
 
154
  case '-21' :
155
- $message = 'ارسال TransId الزامی می باشد.';
156
  break;
157
 
158
  case '-31' :
1
  <?php
2
+
3
+ defined( 'ABSPATH' ) || exit;
 
4
 
5
  if ( ! class_exists( 'Woocommerce_Ir_Gateway_PayIr' ) ) :
6
 
18
 
19
  public function fields() {
20
 
21
+ return [
22
+ 'api' => [
23
  'title' => 'API',
24
  'type' => 'text',
25
  'description' => 'API درگاه Pay.ir',
26
  'default' => '',
27
+ 'desc_tip' => true,
28
+ ],
29
+ 'sandbox' => [
30
  'title' => 'فعالسازی حالت آزمایشی',
31
  'type' => 'checkbox',
32
  'label' => 'فعالسازی حالت آزمایشی Pay.ir',
33
  'description' => 'برای فعال سازی حالت آزمایشی Pay.ir چک باکس را تیک بزنید.',
34
  'default' => 'no',
35
  'desc_tip' => true,
36
+ ],
37
+ 'cancelled_massage' => [],
38
+ 'shortcodes' => [
39
  'transaction_id' => 'شماره تراکنش',
40
+ ],
41
+ ];
42
  }
43
 
44
  public function request( $order ) {
45
 
 
 
 
 
46
  $amount = $this->get_total( 'IRR' );
47
  $callback = $this->get_verify_url();
48
  $mobile = $this->get_order_mobile();
50
  $description = 'شماره سفارش #' . $order_number;
51
  $apiID = $this->option( 'sandbox' ) == '1' ? 'test' : $this->option( 'api' );
52
 
53
+ $pay = wp_remote_post( 'https://pay.ir/pg/send', [
54
+ 'body' => [
55
+ 'api' => $apiID,
56
+ 'amount' => $amount,
57
+ 'redirect' => urlencode( $callback ),
58
+ 'mobile' => $mobile,
59
+ 'factorNumber' => $order_number,
60
+ 'description' => $description,
61
+ 'resellerId' => '1000000800',
62
+ ],
63
+ ] );
64
+
65
+ $pay = wp_remote_retrieve_body( $pay );
66
+
67
+ if ( empty( $pay ) ) {
68
+ return 'خطایی در اتصال به درگاه رخ داده است!';
69
+ }
70
+
71
+ $pay = json_decode( $pay );
72
+
73
+ if ( $pay->status ) {
74
+ $this->redirect( 'https://pay.ir/pg/' . $pay->token );
75
  } else {
76
+ return ! empty( $pay->errorMessage ) ? $pay->errorMessage : ( ! empty( $pay->errorCode ) ? $this->errors( $pay->errorCode ) : '' );
77
  }
78
  }
79
 
80
  public function verify( $order ) {
81
 
82
+ $apiID = $this->option( 'sandbox' ) == '1' ? 'test' : $this->option( 'api' );
83
+ $token = $this->get( 'token' );
 
84
 
85
+ $this->check_verification( $token );
86
 
87
  $error = '';
88
  $status = 'failed';
89
+
90
+ if ( $this->get( 'status' ) ) {
91
+
92
+ $pay = wp_remote_post( 'https://pay.ir/pg/verify', [
93
+ 'body' => [
94
+ 'api' => $apiID,
95
+ 'token' => $token,
96
+ ],
97
+ ] );
98
+
99
+ $pay = wp_remote_retrieve_body( $pay );
100
+
101
+ if ( ! empty( $pay ) ) {
102
+
103
+ $pay = json_decode( $pay );
104
+
105
+ if ( $pay->status ) {
106
+ $status = 'completed';
107
+ } else {
108
+ $error = ! empty( $pay->errorMessage ) ? $pay->errorMessage : ( ! empty( $pay->errorCode ) ? $this->errors( ( $pay->errorCode . '1' ) ) : '' );
109
+ }
110
+
111
  }
112
 
113
  } else {
114
  $error = $this->post( 'message' );
115
  }
116
 
117
+ $this->set_shortcodes( [ 'token' => $token ] );
118
 
119
+ return compact( 'status', 'token', 'error' );
120
  }
121
 
122
  private function errors( $error ) {
164
  break;
165
 
166
  case '-21' :
167
+ $message = 'ارسال token الزامی می باشد.';
168
  break;
169
 
170
  case '-31' :
include/tools/class-checkout.php CHANGED
@@ -1,6 +1,6 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
 
5
  if ( ! class_exists( 'PW_Tools_Checkout' ) ) :
6
 
@@ -9,34 +9,14 @@ if ( ! class_exists( 'PW_Tools_Checkout' ) ) :
9
  public function __construct() {
10
 
11
  if ( PW()->get_options( 'remove_extra_field_physical' ) == 'yes' ) {
12
- add_filter( 'woocommerce_checkout_fields', array( $this, 'remove_extra_field_physical' ) );
13
  }
14
-
15
  }
16
 
17
  public function remove_extra_field_physical( $fields ) {
18
 
19
- $has_physical_product = false;
20
-
21
- if ( ! empty( WC()->cart->cart_contents ) ) {
22
-
23
- $cart = WC()->cart->get_cart();
24
-
25
- foreach ( $cart as $key => $values ) {
26
-
27
- /** @var WC_Product $_product */
28
- $_product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] );
29
-
30
- if ( ! empty( $_product ) && $_product->exists() && $values['quantity'] > 0 ) {
31
- if ( $_product->virtual == 'no' && $_product->downloadable == 'no' ) {
32
- $has_physical_product = true;
33
- break;
34
- }
35
- }
36
- }
37
- }
38
-
39
- if ( ! $has_physical_product ) {
40
  unset( $fields['billing']['billing_address_1'] );
41
  unset( $fields['billing']['billing_address_2'] );
42
  unset( $fields['billing']['billing_company'] );
@@ -44,6 +24,7 @@ if ( ! class_exists( 'PW_Tools_Checkout' ) ) :
44
  unset( $fields['billing']['billing_postcode'] );
45
  unset( $fields['billing']['billing_country'] );
46
  unset( $fields['billing']['billing_state'] );
 
47
  add_filter( 'woocommerce_enable_order_notes_field', '__return_false' );
48
  }
49
 
1
+ <?php
2
+
3
+ defined( 'ABSPATH' ) || exit;
4
 
5
  if ( ! class_exists( 'PW_Tools_Checkout' ) ) :
6
 
9
  public function __construct() {
10
 
11
  if ( PW()->get_options( 'remove_extra_field_physical' ) == 'yes' ) {
12
+ add_filter( 'woocommerce_checkout_fields', [ $this, 'remove_extra_field_physical' ] );
13
  }
14
+
15
  }
16
 
17
  public function remove_extra_field_physical( $fields ) {
18
 
19
+ if ( ! WC()->cart->needs_shipping() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  unset( $fields['billing']['billing_address_1'] );
21
  unset( $fields['billing']['billing_address_2'] );
22
  unset( $fields['billing']['billing_company'] );
24
  unset( $fields['billing']['billing_postcode'] );
25
  unset( $fields['billing']['billing_country'] );
26
  unset( $fields['billing']['billing_state'] );
27
+
28
  add_filter( 'woocommerce_enable_order_notes_field', '__return_false' );
29
  }
30
 
include/tools/class-date.php CHANGED
@@ -12,7 +12,7 @@ use Morilog\Jalali\Jalalian;
12
  /**
13
  * Class Persian_Woocommerce_Date
14
  *
15
- * @author mahdiy
16
  * @package https://wordpress.org/plugins/persian-date/
17
  */
18
  class Persian_Woocommerce_Date {
@@ -45,11 +45,11 @@ class Persian_Woocommerce_Date {
45
  /** @var WC_Order $order */
46
  $order = wc_get_order( $order_id );
47
 
48
- $hour = str_pad( $_POST['order_date_hour'], 2, 0, STR_PAD_LEFT );
49
- $minute = str_pad( $_POST['order_date_minute'], 2, 0, STR_PAD_LEFT );
50
- $second = str_pad( $_POST['order_date_second'], 2, 0, STR_PAD_LEFT );
51
 
52
- $timestamp = $_POST['order_date'] . " {$hour}:{$minute}:{$second}";
53
 
54
  $jDate = Jalalian::fromFormat( 'Y-m-d H:i:s', self::en( $timestamp ) );
55
 
@@ -178,9 +178,9 @@ class Persian_Woocommerce_Date {
178
  $expiry_date = $jDate->toCarbon()->format( 'Y-m-d' );
179
  }
180
 
181
- $coupon->set_props( array(
182
  'date_expires' => $expiry_date,
183
- ) );
184
 
185
  $coupon->save();
186
  }
@@ -200,9 +200,11 @@ class Persian_Woocommerce_Date {
200
 
201
  public function wp_date( $date, $format, $timestamp, $timezone ) {
202
 
 
 
203
  try {
204
  return Jalalian::fromDateTime( $timestamp, $timezone )->format( $format );
205
- } catch( Exception $e ) {
206
  return $date;
207
  }
208
  }
@@ -215,7 +217,7 @@ class Persian_Woocommerce_Date {
215
  * @return mixed
216
  */
217
  private static function en( $number ) {
218
- return str_replace( array( '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ), range( 0, 9 ), $number );
219
  }
220
  }
221
 
12
  /**
13
  * Class Persian_Woocommerce_Date
14
  *
15
+ * @author mahdiy
16
  * @package https://wordpress.org/plugins/persian-date/
17
  */
18
  class Persian_Woocommerce_Date {
45
  /** @var WC_Order $order */
46
  $order = wc_get_order( $order_id );
47
 
48
+ $hour = str_pad( intval( $_POST['order_date_hour'] ), 2, 0, STR_PAD_LEFT );
49
+ $minute = str_pad( intval( $_POST['order_date_minute'] ), 2, 0, STR_PAD_LEFT );
50
+ $second = str_pad( intval( $_POST['order_date_second'] ), 2, 0, STR_PAD_LEFT );
51
 
52
+ $timestamp = wc_clean( $_POST['order_date'] ) . " {$hour}:{$minute}:{$second}";
53
 
54
  $jDate = Jalalian::fromFormat( 'Y-m-d H:i:s', self::en( $timestamp ) );
55
 
178
  $expiry_date = $jDate->toCarbon()->format( 'Y-m-d' );
179
  }
180
 
181
+ $coupon->set_props( [
182
  'date_expires' => $expiry_date,
183
+ ] );
184
 
185
  $coupon->save();
186
  }
200
 
201
  public function wp_date( $date, $format, $timestamp, $timezone ) {
202
 
203
+ $format = str_replace( 'M', 'F', $format );
204
+
205
  try {
206
  return Jalalian::fromDateTime( $timestamp, $timezone )->format( $format );
207
+ } catch ( Exception $e ) {
208
  return $date;
209
  }
210
  }
217
  * @return mixed
218
  */
219
  private static function en( $number ) {
220
+ return str_replace( [ '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ], range( 0, 9 ), $number );
221
  }
222
  }
223
 
include/tools/class-datepicker.php CHANGED
@@ -1,7 +1,5 @@
1
  <?php
2
- if ( ! defined( 'ABSPATH' ) ) {
3
- exit;
4
- } // Exit if accessed directly
5
 
6
  if ( ! class_exists( 'PW_Tools_DatePicker' ) ) :
7
 
@@ -11,14 +9,14 @@ if ( ! class_exists( 'PW_Tools_DatePicker' ) ) :
11
  'product' => 'product',
12
  'shop_order' => 'shop_order',
13
  'shop_coupon' => 'shop_coupon',
14
- 'ووکامرس_page_wc-reports' => 'report'
15
  ];
16
 
17
  public function __construct() {
18
 
19
  if ( PW()->get_options( 'enable_jalali_datepicker' ) == 'yes' ) {
20
- add_action( 'admin_enqueue_scripts', array( $this, 'datepicker' ), 1000 );
21
- add_action( 'admin_print_footer_scripts', array( $this, 'inline_js' ) );
22
  }
23
 
24
  }
@@ -42,11 +40,11 @@ if ( ! class_exists( 'PW_Tools_DatePicker' ) ) :
42
  $method_name = "inline_js_" . self::SCREENS[ urldecode( $screen ) ];
43
 
44
  ?>
45
- <style type="text/css">
46
  #ui-datepicker-div {
47
  display: none !important;
48
  }
49
- </style>
50
  <?php
51
 
52
  $this->{$method_name}();
@@ -54,68 +52,68 @@ if ( ! class_exists( 'PW_Tools_DatePicker' ) ) :
54
 
55
  public function inline_js_product() {
56
  ?>
57
- <script type="text/javascript">
58
- jQuery(function ( $ ) {
59
 
60
- let _sale_price_dates_from = $("#_sale_price_dates_from").val();
61
 
62
- $("#_sale_price_dates_from").persianDatepicker({
63
- formatDate: "YYYY-0M-0D",
64
- selectedBefore: _sale_price_dates_from.length ? 1 : 0,
65
- selectedDate: _sale_price_dates_from.length ? _sale_price_dates_from.replace(/-/gi, "/") : null
66
- });
67
 
68
- let _sale_price_dates_to = $("#_sale_price_dates_to").val();
69
 
70
- $("#_sale_price_dates_to").persianDatepicker({
71
- formatDate: "YYYY-0M-0D",
72
- selectedBefore: _sale_price_dates_to.length ? 1 : 0,
73
- selectedDate: _sale_price_dates_to.length ? _sale_price_dates_to.replace(/-/gi, "/") : null
74
- });
75
 
76
- $("div.woocommerce_variations").on("click", "a.sale_schedule", function () {
77
- let el_to = $(this).parent().parent().next().find("input[name*=to]");
78
 
79
- let el_date_to = el_to.val();
80
 
81
- el_to.persianDatepicker({
82
- formatDate: "YYYY-0M-0D",
83
- selectedBefore: el_date_to.length ? 1 : 0,
84
- selectedDate: el_date_to.length ? el_date_to.replace(/-/gi, "/") : null
85
- });
86
 
87
- let el_from = $(this).parent().parent().next().find("input[name*=from]");
88
 
89
- let el_date_from = el_from.val();
90
 
91
- el_from.persianDatepicker({
92
- formatDate: "YYYY-0M-0D",
93
- selectedBefore: el_date_from.length ? 1 : 0,
94
- selectedDate: el_date_from.length ? el_date_from.replace(/-/gi, "/") : null
95
- });
96
 
97
- });
98
 
99
- });
100
- </script>
101
  <?php
102
  }
103
 
104
  public function inline_js_shop_order() {
105
  ?>
106
- <script type="text/javascript">
107
- jQuery(function ( $ ) {
108
 
109
- let order_date = $("input[name=order_date]").val();
110
 
111
- $("input[name=order_date]").persianDatepicker({
112
- formatDate: "YYYY-0M-0D",
113
- selectedBefore: 1,
114
- selectedDate: order_date.length ? order_date.replace(/-/gi, "/") : null
115
- });
116
 
117
- });
118
- </script>
119
  <?php
120
  }
121
 
@@ -126,40 +124,45 @@ if ( ! class_exists( 'PW_Tools_DatePicker' ) ) :
126
  $expiry_date = $coupon->get_date_expires( 'edit' ) ? $coupon->get_date_expires( 'edit' )->date_i18n( 'Y/m/d' ) : '';
127
 
128
  ?>
129
- <script type="text/javascript">
130
- jQuery(function ( $ ) {
131
 
132
- $("input[name=expiry_date]").val('<?php echo $expiry_date; ?>');
133
- let expiry_date = $("input[name=expiry_date]").val();
134
 
135
- $("input[name=expiry_date]").persianDatepicker({
136
- formatDate: "YYYY-0M-0D",
137
- selectedBefore: 1,
138
- selectedDate: expiry_date.length ? expiry_date.replace(/-/gi, "/") : null
139
- });
140
 
141
- });
142
- </script>
 
 
 
 
 
 
143
  <?php
144
  }
145
 
146
  public function inline_js_report() {
147
  ?>
148
- <script type="text/javascript">
149
- jQuery(function ( $ ) {
150
 
151
- $("input[name=start_date]").persianDatepicker({
152
- formatDate: "YYYY-0M-0D",
153
- showGregorianDate: 1,
154
- });
155
 
156
- $("input[name=end_date]").persianDatepicker({
157
- formatDate: "YYYY-0M-0D",
158
- showGregorianDate: 1,
159
- });
160
 
161
- });
162
- </script>
163
  <?php
164
  }
165
  }
1
  <?php
2
+ defined( 'ABSPATH' ) || exit;
 
 
3
 
4
  if ( ! class_exists( 'PW_Tools_DatePicker' ) ) :
5
 
9
  'product' => 'product',
10
  'shop_order' => 'shop_order',
11
  'shop_coupon' => 'shop_coupon',
12
+ 'ووکامرس_page_wc-reports' => 'report',
13
  ];
14
 
15
  public function __construct() {
16
 
17
  if ( PW()->get_options( 'enable_jalali_datepicker' ) == 'yes' ) {
18
+ add_action( 'admin_enqueue_scripts', [ $this, 'datepicker' ], 1000 );
19
+ add_action( 'admin_print_footer_scripts', [ $this, 'inline_js' ] );
20
  }
21
 
22
  }
40
  $method_name = "inline_js_" . self::SCREENS[ urldecode( $screen ) ];
41
 
42
  ?>
43
+ <style type="text/css">
44
  #ui-datepicker-div {
45
  display: none !important;
46
  }
47
+ </style>
48
  <?php
49
 
50
  $this->{$method_name}();
52
 
53
  public function inline_js_product() {
54
  ?>
55
+ <script type="text/javascript">
56
+ jQuery(function ($) {
57
 
58
+ let _sale_price_dates_from = $("#_sale_price_dates_from").val();
59
 
60
+ $("#_sale_price_dates_from").persianDatepicker({
61
+ formatDate: "YYYY-0M-0D",
62
+ selectedBefore: _sale_price_dates_from.length ? 1 : 0,
63
+ selectedDate: _sale_price_dates_from.length ? _sale_price_dates_from.replace(/-/gi, "/") : null
64
+ });
65
 
66
+ let _sale_price_dates_to = $("#_sale_price_dates_to").val();
67
 
68
+ $("#_sale_price_dates_to").persianDatepicker({
69
+ formatDate: "YYYY-0M-0D",
70
+ selectedBefore: _sale_price_dates_to.length ? 1 : 0,
71
+ selectedDate: _sale_price_dates_to.length ? _sale_price_dates_to.replace(/-/gi, "/") : null
72
+ });
73
 
74
+ $("div.woocommerce_variations").on("click", "a.sale_schedule", function () {
75
+ let el_to = $(this).parent().parent().next().find("input[name*=to]");
76
 
77
+ let el_date_to = el_to.val();
78
 
79
+ el_to.persianDatepicker({
80
+ formatDate: "YYYY-0M-0D",
81
+ selectedBefore: el_date_to.length ? 1 : 0,
82
+ selectedDate: el_date_to.length ? el_date_to.replace(/-/gi, "/") : null
83
+ });
84
 
85
+ let el_from = $(this).parent().parent().next().find("input[name*=from]");
86
 
87
+ let el_date_from = el_from.val();
88
 
89
+ el_from.persianDatepicker({
90
+ formatDate: "YYYY-0M-0D",
91
+ selectedBefore: el_date_from.length ? 1 : 0,
92
+ selectedDate: el_date_from.length ? el_date_from.replace(/-/gi, "/") : null
93
+ });
94
 
95
+ });
96
 
97
+ });
98
+ </script>
99
  <?php
100
  }
101
 
102
  public function inline_js_shop_order() {
103
  ?>
104
+ <script type="text/javascript">
105
+ jQuery(function ($) {
106
 
107
+ let order_date = $("input[name=order_date]").val();
108
 
109
+ $("input[name=order_date]").persianDatepicker({
110
+ formatDate: "YYYY-0M-0D",
111
+ selectedBefore: 1,
112
+ selectedDate: order_date.length ? order_date.replace(/-/gi, "/") : null
113
+ });
114
 
115
+ });
116
+ </script>
117
  <?php
118
  }
119
 
124
  $expiry_date = $coupon->get_date_expires( 'edit' ) ? $coupon->get_date_expires( 'edit' )->date_i18n( 'Y/m/d' ) : '';
125
 
126
  ?>
127
+ <script type="text/javascript">
128
+ jQuery(function ($) {
129
 
130
+ $("input[name=expiry_date]").val('<?php echo esc_attr( $expiry_date ); ?>');
131
+ let expiry_date = $("input[name=expiry_date]").val();
132
 
133
+ let args = {
134
+ formatDate: "YYYY-0M-0D",
135
+ selectedDate: null
136
+ };
 
137
 
138
+ if (expiry_date.length) {
139
+ args.selectedBefore = 1;
140
+ args.selectedDate = expiry_date.replace(/-/gi, "/");
141
+ }
142
+
143
+ $("input[name=expiry_date]").persianDatepicker(args);
144
+ });
145
+ </script>
146
  <?php
147
  }
148
 
149
  public function inline_js_report() {
150
  ?>
151
+ <script type="text/javascript">
152
+ jQuery(function ($) {
153
 
154
+ $("input[name=start_date]").persianDatepicker({
155
+ formatDate: "YYYY-0M-0D",
156
+ showGregorianDate: 1,
157
+ });
158
 
159
+ $("input[name=end_date]").persianDatepicker({
160
+ formatDate: "YYYY-0M-0D",
161
+ showGregorianDate: 1,
162
+ });
163
 
164
+ });
165
+ </script>
166
  <?php
167
  }
168
  }
include/tools/class-general.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class PW_Tools_General {
4
+
5
+ public function __construct() {
6
+ add_filter( 'pre_get_posts', [ $this, 'fix_arabic_characters' ] );
7
+
8
+ if ( PW()->get_options( 'fix_load_states' ) != 'no' ) {
9
+ add_action( 'wp_footer', [ $this, 'checkout_state_dropdown_fix' ], 50 );
10
+ }
11
+
12
+ if ( is_admin() && PW()->get_options( 'fix_orders_list' ) != 'no' ) {
13
+ add_filter( 'pre_get_posts', [ $this, 'sort_orders_list_by_pay_date' ] );
14
+ }
15
+
16
+ if ( PW()->get_options( 'fix_postcode_persian_number' ) != 'no' ) {
17
+ add_filter( 'woocommerce_checkout_process', [ $this, 'checkout_process_postcode' ], 20, 1 );
18
+ }
19
+
20
+ if ( PW()->get_options( 'postcode_validation' ) != 'no' ) {
21
+ add_filter( 'woocommerce_validate_postcode', [ $this, 'validate_postcode' ], 10, 3 );
22
+ }
23
+
24
+ if ( PW()->get_options( 'fix_phone_persian_number' ) != 'no' ) {
25
+ add_filter( 'woocommerce_checkout_process', [ $this, 'checkout_process_phone' ], 20, 1 );
26
+ }
27
+ }
28
+
29
+ function fix_arabic_characters( $query ) {
30
+
31
+ if ( $query->is_search ) {
32
+ $query->set( 's', str_replace( [ 'ك', 'ي', ], [ 'ک', 'ی' ], $query->get( 's' ) ) );
33
+ }
34
+
35
+ return $query;
36
+ }
37
+
38
+ function checkout_state_dropdown_fix() {
39
+
40
+ if ( function_exists( 'is_checkout' ) && ! is_checkout() ) {
41
+ return;
42
+ }
43
+
44
+ ?>
45
+ <script>
46
+ jQuery(function () {
47
+ // Snippets.ir
48
+ jQuery('#billing_country').trigger('change');
49
+ jQuery('#billing_state_field').removeClass('woocommerce-invalid');
50
+ });
51
+ </script>
52
+ <?php
53
+ }
54
+
55
+ function sort_orders_list_by_pay_date( $query ) {
56
+
57
+ if ( ! function_exists( 'get_current_screen' ) ) {
58
+ return $query;
59
+ }
60
+
61
+ $screen = get_current_screen();
62
+
63
+ if ( is_null( $screen ) || $screen->id != 'edit-shop_order' ) {
64
+ return $query;
65
+ }
66
+
67
+ $query->set( 'order', 'DESC' );
68
+ $query->set( 'meta_key', '_paid_date' );
69
+ $query->set( 'orderby', 'meta_value' );
70
+
71
+ return $query;
72
+ }
73
+
74
+ function checkout_process_postcode() {
75
+
76
+ if ( isset( $_POST['billing_postcode'] ) ) {
77
+ $_POST['billing_postcode'] = self::en( sanitize_text_field( $_POST['billing_postcode'] ) );
78
+ }
79
+
80
+ if ( isset( $_POST['shipping_postcode'] ) ) {
81
+ $_POST['shipping_postcode'] = self::en( sanitize_text_field( $_POST['shipping_postcode'] ) );
82
+ }
83
+
84
+ if ( PW()->get_options( 'phone_validation' ) != 'no' ) {
85
+ add_action( 'woocommerce_after_checkout_validation', 'validate_phone', 10, 3 );
86
+ }
87
+ }
88
+
89
+ function validate_postcode( $valid, $postcode, $country ): bool {
90
+
91
+ if ( $country != 'IR' ) {
92
+ return $valid;
93
+ }
94
+
95
+ return (bool) preg_match( '/^([13456789]{5}[0-9]{5})$/', $postcode );
96
+ }
97
+
98
+ function checkout_process_phone() {
99
+
100
+ if ( isset( $_POST['billing_phone'] ) ) {
101
+ $_POST['billing_phone'] = self::en( sanitize_text_field( $_POST['billing_phone'] ) );
102
+ }
103
+
104
+ if ( isset( $_POST['shipping_phone'] ) ) {
105
+ $_POST['shipping_phone'] = self::en( sanitize_text_field( $_POST['shipping_phone'] ) );
106
+ }
107
+
108
+ }
109
+
110
+ function validate_phone( $data, $errors ) {
111
+
112
+ if ( (bool) preg_match( '/^(09[0-9]{9})$/', $data['billing_phone'] ) ) {
113
+ return false;
114
+ }
115
+
116
+ $errors->add( 'validation', '<b>تلفن همراه</b> وارد شده، معتبر نمی باشد.' );
117
+ }
118
+
119
+ private static function en( $number ) {
120
+ return str_replace( [ '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ], range( 0, 9 ), $number );
121
+ }
122
+ }
123
+
124
+ new PW_Tools_General();
include/tools/class-price.php CHANGED
@@ -1,6 +1,6 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
 
5
  if ( ! class_exists( 'PW_Tools_Price' ) ) :
6
 
@@ -9,25 +9,34 @@ if ( ! class_exists( 'PW_Tools_Price' ) ) :
9
  public function __construct() {
10
 
11
  if ( PW()->get_options( 'enable_call_for_price' ) == 'yes' ) {
12
- add_filter( 'woocommerce_empty_price_html', array( $this, 'on_empty_price' ), PHP_INT_MAX - 1 );
13
- add_filter( 'woocommerce_sale_flash', array( $this, 'hide_sales_flash' ), PHP_INT_MAX, 3 );
14
  }
15
 
16
  if ( PW()->get_options( 'persian_price' ) == 'yes' ) {
17
- add_filter( 'wc_price', array( $this, 'persian_number' ) );
18
- add_filter( 'woocommerce_get_price_html', array( $this, 'persian_number' ) );
19
-
20
- add_filter( 'woocommerce_cart_item_price', array( $this, 'persian_number' ) );
21
- add_filter( 'woocommerce_cart_item_subtotal', array( $this, 'persian_number' ) );
22
- add_filter( 'woocommerce_cart_subtotal', array( $this, 'persian_number' ) );
23
- add_filter( 'woocommerce_cart_totals_coupon_html', array( $this, 'persian_number' ) );
24
- add_filter( 'woocommerce_cart_shipping_method_full_label', array( $this, 'persian_number' ) );
25
- add_filter( 'woocommerce_cart_total', array( $this, 'persian_number' ) );
26
  }
27
 
28
  if ( PW()->get_options( 'minimum_order_amount' ) != 0 ) {
29
- add_action( 'woocommerce_checkout_process', array( $this, 'wc_minimum_order_amount' ) );
30
- add_action( 'woocommerce_before_cart', array( $this, 'wc_minimum_order_amount' ) );
 
 
 
 
 
 
 
 
 
31
  }
32
  }
33
 
@@ -58,7 +67,7 @@ if ( ! class_exists( 'PW_Tools_Price' ) ) :
58
  }
59
 
60
  public function persian_number( $price ) {
61
- return str_replace( range( 0, 9 ), array( '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ), $price );
62
  }
63
 
64
  public function wc_minimum_order_amount() {
@@ -80,6 +89,23 @@ if ( ! class_exists( 'PW_Tools_Price' ) ) :
80
  }
81
  }
82
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
 
85
  endif;
1
+ <?php
2
+
3
+ defined( 'ABSPATH' ) || exit;
4
 
5
  if ( ! class_exists( 'PW_Tools_Price' ) ) :
6
 
9
  public function __construct() {
10
 
11
  if ( PW()->get_options( 'enable_call_for_price' ) == 'yes' ) {
12
+ add_filter( 'woocommerce_empty_price_html', [ $this, 'on_empty_price' ], PHP_INT_MAX - 1 );
13
+ add_filter( 'woocommerce_sale_flash', [ $this, 'hide_sales_flash' ], PHP_INT_MAX, 3 );
14
  }
15
 
16
  if ( PW()->get_options( 'persian_price' ) == 'yes' ) {
17
+ add_filter( 'wc_price', [ $this, 'persian_number' ] );
18
+ add_filter( 'woocommerce_get_price_html', [ $this, 'persian_number' ] );
19
+
20
+ add_filter( 'woocommerce_cart_item_price', [ $this, 'persian_number' ] );
21
+ add_filter( 'woocommerce_cart_item_subtotal', [ $this, 'persian_number' ] );
22
+ add_filter( 'woocommerce_cart_subtotal', [ $this, 'persian_number' ] );
23
+ add_filter( 'woocommerce_cart_totals_coupon_html', [ $this, 'persian_number' ] );
24
+ add_filter( 'woocommerce_cart_shipping_method_full_label', [ $this, 'persian_number' ] );
25
+ add_filter( 'woocommerce_cart_total', [ $this, 'persian_number' ] );
26
  }
27
 
28
  if ( PW()->get_options( 'minimum_order_amount' ) != 0 ) {
29
+ add_action( 'woocommerce_checkout_process', [ $this, 'wc_minimum_order_amount' ] );
30
+ add_action( 'woocommerce_before_cart', [ $this, 'wc_minimum_order_amount' ] );
31
+ }
32
+
33
+ if ( PW()->get_options( 'variable_price', 'range' ) != 'range' ) {
34
+ add_action( 'woocommerce_variable_sale_price_html', [ $this, 'get_variation_price_format' ], 10, 2 );
35
+ add_action( 'woocommerce_variable_price_html', [ $this, 'get_variation_price_format' ], 10, 2 );
36
+ add_action( 'woocommerce_dropdown_variation_attribute_options_args', [
37
+ $this,
38
+ 'remove_dropdown_variation_options',
39
+ ] );
40
  }
41
  }
42
 
67
  }
68
 
69
  public function persian_number( $price ) {
70
+ return str_replace( range( 0, 9 ), [ '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ], $price );
71
  }
72
 
73
  public function wc_minimum_order_amount() {
89
  }
90
  }
91
  }
92
+
93
+ public function get_variation_price_format( string $price, WC_Product $product ): string {
94
+
95
+ [ $min_or_max, $type ] = explode( '_', PW()->get_options( 'variable_price' ) );
96
+
97
+ // Validation
98
+ $min_or_max = $min_or_max == 'min' ? 'min' : 'max';
99
+ $type = $type == 'regular' ? 'regular' : 'sale';
100
+
101
+ return wc_price( $product->{"get_variation_{$type}_price"}( $min_or_max ) );
102
+ }
103
+
104
+ public function remove_dropdown_variation_options( array $args ): array {
105
+ $args['show_option_none'] = false;
106
+
107
+ return $args;
108
+ }
109
  }
110
 
111
  endif;
include/tools/general.php DELETED
@@ -1,111 +0,0 @@
1
- <?php
2
-
3
- if ( PW()->get_options( 'fix_load_states' ) != 'no' ) {
4
- add_action( 'wp_footer', 'pw_checkout_state_dropdown_fix', 50 );
5
- }
6
-
7
- function pw_checkout_state_dropdown_fix() {
8
-
9
- if ( function_exists( 'is_checkout' ) && ! is_checkout() ) {
10
- return false;
11
- }
12
-
13
- ?>
14
- <script>
15
- jQuery(function () {
16
- // Snippets.ir
17
- jQuery('#billing_country').trigger('change');
18
- jQuery('#billing_state_field').removeClass('woocommerce-invalid');
19
- });
20
- </script>
21
- <?php
22
- }
23
-
24
- if ( is_admin() && PW()->get_options( 'fix_orders_list' ) != 'no' ) {
25
- add_filter( 'pre_get_posts', 'pw_sort_orders_list_by_pay_date' );
26
- }
27
-
28
- function pw_sort_orders_list_by_pay_date( $query ) {
29
-
30
- if ( ! function_exists( 'get_current_screen' ) ) {
31
- return $query;
32
- }
33
-
34
- $screen = get_current_screen();
35
-
36
- if ( is_null( $screen ) || $screen->id != 'edit-shop_order' ) {
37
- return $query;
38
- }
39
-
40
- $query->set( 'order', 'DESC' );
41
- $query->set( 'meta_key', '_date_paid' );
42
- $query->set( 'orderby', 'meta_value' );
43
-
44
- return $query;
45
- }
46
-
47
- if ( ! function_exists( 'pw_convert_number' ) ) {
48
-
49
- function pw_convert_number( $num ) {
50
- return str_replace( array( '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹' ), range( 0, 9 ), $num );
51
- }
52
-
53
- }
54
-
55
- if ( PW()->get_options( 'fix_postcode_persian_number' ) != 'no' ) {
56
- add_filter( 'woocommerce_checkout_process', 'pw_checkout_process_postcode', 20, 1 );
57
- }
58
-
59
- function pw_checkout_process_postcode() {
60
-
61
- if ( isset( $_POST['billing_postcode'] ) ) {
62
- $_POST['billing_postcode'] = pw_convert_number( $_POST['billing_postcode'] );
63
- }
64
-
65
- if ( isset( $_POST['shipping_postcode'] ) ) {
66
- $_POST['shipping_postcode'] = pw_convert_number( $_POST['shipping_postcode'] );
67
- }
68
-
69
- }
70
-
71
- if ( PW()->get_options( 'postcode_validation' ) != 'no' ) {
72
- add_filter( 'woocommerce_validate_postcode', 'pw_validate_postcode', 10, 3 );
73
- }
74
-
75
- function pw_validate_postcode( $valid, $postcode, $country ) {
76
-
77
- if ( $country != 'IR' ) {
78
- return $valid;
79
- }
80
-
81
- return (bool) preg_match( '/^([0-9]{10})$/', $postcode );
82
- }
83
-
84
- if ( PW()->get_options( 'fix_phone_persian_number' ) != 'no' ) {
85
- add_filter( 'woocommerce_checkout_process', 'pw_checkout_process_phone', 20, 1 );
86
- }
87
-
88
- function pw_checkout_process_phone() {
89
-
90
- if ( isset( $_POST['billing_phone'] ) ) {
91
- $_POST['billing_phone'] = pw_convert_number( $_POST['billing_phone'] );
92
- }
93
-
94
- if ( isset( $_POST['shipping_phone'] ) ) {
95
- $_POST['shipping_phone'] = pw_convert_number( $_POST['shipping_phone'] );
96
- }
97
-
98
- }
99
-
100
- if ( PW()->get_options( 'phone_validation' ) != 'no' ) {
101
- add_action( 'woocommerce_after_checkout_validation', 'pw_validate_phone', 10, 3 );
102
- }
103
-
104
- function pw_validate_phone( $data, $errors ) {
105
-
106
- if ( (bool) preg_match( '/^(09[0-9]{9})$/', $data['billing_phone'] ) ) {
107
- return false;
108
- }
109
-
110
- $errors->add( 'validation', '<b>تلفن همراه</b> وارد شده، معتبر نمی باشد.' );
111
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
include/view/html-admin-page-plugins.php CHANGED
@@ -1,108 +1,108 @@
1
- <?php
2
- /**
3
- * Admin View: Gateways
4
- */
5
- if ( ! defined( 'ABSPATH' ) ) {
6
- exit;
7
- }
8
-
9
- for ( $i = 0; $i < 3; $i ++ ) {
10
- $response = wp_remote_get( 'http://woocommerce.ir/api/gateways.json' );
11
- if ( empty( $response->errors ) ) {
12
- break;
13
- }
14
- }
15
-
16
- if ( ! empty( $response->errors ) ) {
17
- echo '<br><h1>در اتصال به سرور خطایی رخ داده است. لطفا چند دقیقه دیگر تلاش کنید.</h1>';
18
-
19
- return;
20
- }
21
-
22
- if ( is_array( $response ) ) {
23
- $response = json_decode( $response['body'] );
24
- }
25
-
26
- $count = 0;
27
- ?>
28
- <div class="wrap woocommerce wc_addons_wrap">
29
- <h1><?php echo get_admin_page_title(); ?></h1>
30
-
31
-
32
- <div class="addons-featured">
33
- <div class="addons-banner-block">
34
- <h1>افزونه های ووکامرس فارسی</h1>
35
- <h3>ارائه افزونه های معتبر و فارسی با امنیت بالا و پشتیبانی 24 ساعته</h3>
36
- <p>ارائه برترین افزونه ها با پشتیبانی دائمی و امنیت بالا برای ووکامرس فارسی ، پیاده سازی و توسعه توسط
37
- متخصصین ووکامرس در ایران. افزونه های معتبر و اصلی تنها در ووکامرس فارسی عرضه می گردند. برای اطلاع از
38
- آخرین تخفیف ها و اطلاعیه های ووکامرس ، <a target="_blank" href="https://t.me/woocommerce_ir">کانال
39
- تلگرام ووکامرس فارسی</a> را دنبال کنید</p>
40
-
41
- <?php foreach ( $response as $item ) : ?>
42
- <?php if ( $count ++ % 3 == 0 ) {
43
- echo '<div class="addons-banner-block-items">';
44
- } ?>
45
- <div class="addons-banner-block-item">
46
- <div class="addons-banner-block-item-icon"
47
- style="background: linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url('<?php echo esc_url( $item->image ); ?>')!important;">
48
- <img class="addons-img" src="<?php echo esc_url( $item->image ); ?>">
49
-
50
- </div>
51
- <div class="addons-banner-block-item-content">
52
- <h3><?php echo esc_html( $item->title ); ?></h3>
53
-
54
- <p><?php
55
-
56
- $string = strip_tags( $item->desc );
57
-
58
- if ( strlen( $string ) > 220 ) {
59
- $stringCut = substr( $string, 0, 220 );
60
- $string = substr( $stringCut, 0, strrpos( $stringCut, ' ' ) ) . '... <a href="' . esc_url( $item->url ) . '">اطلاعات بیشتر</a>';
61
- }
62
- echo $string; ?></p>
63
- <a class="addons-button addons-button-solid"
64
- href="<?php echo esc_url( $item->url ); ?>"><?php echo esc_html( $item->price ); ?> / اطلاعات
65
- بیشتر</a>
66
- </div>
67
- </div>
68
- <?php if ( $count % 3 == 0 ) {
69
- echo '</div>';
70
- } ?>
71
- <?php endforeach; ?>
72
-
73
- </div>
74
- </div>
75
- </div>
76
-
77
-
78
- <style type="text/css">
79
- .ver {
80
- -webkit-transform: rotate(-45deg);
81
- -moz-transform: rotate(-45deg);
82
- -o-transform: rotate(-45deg);
83
- -ms-transform: rotate(-45deg);
84
- transform: rotate(-45deg);
85
- position: relative;
86
- top: 0px;
87
- left: -40px;
88
- }
89
-
90
- img.addons-img {
91
- height: 100% !important;
92
- opacity: 1.0;
93
- border-right: 1px solid #e4e4e4;
94
- border-left: 1px solid #e4e4e4;
95
- }
96
-
97
- .addons-banner-block-item-icon {
98
- height: 200px;
99
- }
100
-
101
- .addons-button {
102
- width: auto !important;
103
- }
104
-
105
- .addons-banner-block-item-content p {
106
- text-align: justify;
107
- }
108
- </style>
1
+ <?php
2
+ /**
3
+ * Admin View: Gateways
4
+ */
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ }
8
+
9
+ for ( $i = 0; $i < 3; $i ++ ) {
10
+ $response = wp_remote_get( 'http://woocommerce.ir/api/gateways.json' );
11
+ if ( empty( $response->errors ) ) {
12
+ break;
13
+ }
14
+ }
15
+
16
+ if ( ! empty( $response->errors ) ) {
17
+ echo '<br><h1>در اتصال به سرور خطایی رخ داده است. لطفا چند دقیقه دیگر تلاش کنید.</h1>';
18
+
19
+ return;
20
+ }
21
+
22
+ if ( is_array( $response ) ) {
23
+ $response = json_decode( $response['body'] );
24
+ }
25
+
26
+ $count = 0;
27
+ ?>
28
+ <div class="wrap woocommerce wc_addons_wrap">
29
+ <h1><?php echo get_admin_page_title(); ?></h1>
30
+
31
+
32
+ <div class="addons-featured">
33
+ <div class="addons-banner-block">
34
+ <h1>افزونه های ووکامرس فارسی</h1>
35
+ <h3>ارائه افزونه های معتبر و فارسی با امنیت بالا و پشتیبانی 24 ساعته</h3>
36
+ <p>ارائه برترین افزونه ها با پشتیبانی دائمی و امنیت بالا برای ووکامرس فارسی ، پیاده سازی و توسعه توسط
37
+ متخصصین ووکامرس در ایران. افزونه های معتبر و اصلی تنها در ووکامرس فارسی عرضه می گردند. برای اطلاع از
38
+ آخرین تخفیف ها و اطلاعیه های ووکامرس ، <a target="_blank" href="https://t.me/woocommerce_ir">کانال
39
+ تلگرام ووکامرس فارسی</a> را دنبال کنید</p>
40
+
41
+ <?php foreach ( $response as $item ) : ?>
42
+ <?php if ( $count ++ % 3 == 0 ) {
43
+ echo '<div class="addons-banner-block-items">';
44
+ } ?>
45
+ <div class="addons-banner-block-item">
46
+ <div class="addons-banner-block-item-icon"
47
+ style="background: linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url('<?php echo esc_url( $item->image ); ?>')!important;">
48
+ <img class="addons-img" src="<?php echo esc_url( $item->image ); ?>">
49
+
50
+ </div>
51
+ <div class="addons-banner-block-item-content">
52
+ <h3><?php echo esc_html( $item->title ); ?></h3>
53
+
54
+ <p><?php
55
+
56
+ $string = strip_tags( $item->desc );
57
+
58
+ if ( strlen( $string ) > 220 ) {
59
+ $stringCut = substr( $string, 0, 220 );
60
+ $string = substr( $stringCut, 0, strrpos( $stringCut, ' ' ) ) . '... <a href="' . esc_url( $item->url ) . '">اطلاعات بیشتر</a>';
61
+ }
62
+ echo wp_kses_data( $string ); ?></p>
63
+ <a class="addons-button addons-button-solid"
64
+ href="<?php echo esc_url( $item->url ); ?>"><?php echo esc_html( $item->price ); ?> / اطلاعات
65
+ بیشتر</a>
66
+ </div>
67
+ </div>
68
+ <?php if ( $count % 3 == 0 ) {
69
+ echo '</div>';
70
+ } ?>
71
+ <?php endforeach; ?>
72
+
73
+ </div>
74
+ </div>
75
+ </div>
76
+
77
+
78
+ <style type="text/css">
79
+ .ver {
80
+ -webkit-transform: rotate(-45deg);
81
+ -moz-transform: rotate(-45deg);
82
+ -o-transform: rotate(-45deg);
83
+ -ms-transform: rotate(-45deg);
84
+ transform: rotate(-45deg);
85
+ position: relative;
86
+ top: 0px;
87
+ left: -40px;
88
+ }
89
+
90
+ img.addons-img {
91
+ height: 100% !important;
92
+ opacity: 1.0;
93
+ border-right: 1px solid #e4e4e4;
94
+ border-left: 1px solid #e4e4e4;
95
+ }
96
+
97
+ .addons-banner-block-item-icon {
98
+ height: 200px;
99
+ }
100
+
101
+ .addons-button {
102
+ width: auto !important;
103
+ }
104
+
105
+ .addons-banner-block-item-content p {
106
+ text-align: justify;
107
+ }
108
+ </style>
include/view/html-admin-page-themes.php CHANGED
@@ -1,109 +1,109 @@
1
- <?php
2
- /**
3
- * Admin View: Themes
4
- */
5
- if ( ! defined( 'ABSPATH' ) ) {
6
- exit;
7
- }
8
-
9
- for ( $i = 0; $i < 3; $i ++ ) {
10
- $response = wp_remote_get( 'http://woocommerce.ir/api/themes.json' );
11
- if ( empty( $response->errors ) ) {
12
- break;
13
- }
14
- }
15
-
16
- if ( ! empty( $response->errors ) ) {
17
- echo '<br><h1>در اتصال به سرور خطایی رخ داده است. لطفا چند دقیقه دیگر تلاش کنید.</h1>';
18
-
19
- return;
20
- }
21
-
22
- if ( is_array( $response ) ) {
23
- $response = json_decode( $response['body'] );
24
- }
25
-
26
- $count = 0;
27
-
28
- ?>
29
- <div class="wrap woocommerce wc_addons_wrap">
30
- <h1><?php echo get_admin_page_title(); ?></h1>
31
-
32
-
33
- <div class="addons-featured">
34
- <div class="addons-banner-block">
35
- <h1>پوسته های فروشگاه ساز ووکامرس</h1>
36
- <h3>ارائه برترین پوسته ها توسط ووکامرس فارسی همراه با پشتیبانی</h3>
37
- <p>انتخاب یک قالب خوب ، رابطه مستقیمی با فروش و ارتباط بیشتر با مخاطبان شما دارد. همچنین انتخاب یک قالب ایده
38
- آل و استاندارد باعث بهبود رتبه در موتور های جستجو می گردد. در انتخاب پوسته فروشگاه خود دقت کنید! برای
39
- اطلاع از آخرین تخفیف ها و اطلاعیه های ووکامرس ، <a target="_blank" href="https://t.me/woocommerce_ir">کانال
40
- تلگرام ووکامرس فارسی</a> را دنبال کنید</p>
41
-
42
- <?php foreach ( $response as $item ) : ?>
43
- <?php if ( $count ++ % 3 == 0 ) {
44
- echo '<div class="addons-banner-block-items">';
45
- } ?>
46
- <div class="addons-banner-block-item">
47
- <div class="addons-banner-block-item-icon"
48
- style="background: linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url('<?php echo esc_url( $item->image ); ?>')!important;">
49
- <img class="addons-img" src="<?php echo esc_url( $item->image ); ?>">
50
-
51
- </div>
52
- <div class="addons-banner-block-item-content">
53
- <h3><?php echo esc_html( $item->title ); ?></h3>
54
-
55
- <p><?php
56
-
57
- $string = strip_tags( $item->desc );
58
-
59
- if ( strlen( $string ) > 220 ) {
60
- $stringCut = substr( $string, 0, 220 );
61
- $string = substr( $stringCut, 0, strrpos( $stringCut, ' ' ) ) . '... <a href="' . esc_url( $item->url ) . '">اطلاعات بیشتر</a>';
62
- }
63
- echo $string; ?></p>
64
- <a class="addons-button addons-button-solid"
65
- href="<?php echo esc_url( $item->url ); ?>"><?php echo esc_html( $item->price ); ?> / اطلاعات
66
- بیشتر</a>
67
- </div>
68
- </div>
69
- <?php if ( $count % 3 == 0 ) {
70
- echo '</div>';
71
- } ?>
72
- <?php endforeach; ?>
73
-
74
- </div>
75
- </div>
76
-
77
- </div>
78
-
79
- <style type="text/css">
80
- .ver {
81
- -webkit-transform: rotate(-45deg);
82
- -moz-transform: rotate(-45deg);
83
- -o-transform: rotate(-45deg);
84
- -ms-transform: rotate(-45deg);
85
- transform: rotate(-45deg);
86
- position: relative;
87
- top: 0px;
88
- left: -40px;
89
- }
90
-
91
- img.addons-img {
92
- height: 100% !important;
93
- opacity: 1.0;
94
- border-right: 1px solid #e4e4e4;
95
- border-left: 1px solid #e4e4e4;
96
- }
97
-
98
- .addons-banner-block-item-icon {
99
- height: 200px;
100
- }
101
-
102
- .addons-button {
103
- width: auto !important;
104
- }
105
-
106
- .addons-banner-block-item-content p {
107
- text-align: justify;
108
- }
109
- </style>
1
+ <?php
2
+ /**
3
+ * Admin View: Themes
4
+ */
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ }
8
+
9
+ for ( $i = 0; $i < 3; $i ++ ) {
10
+ $response = wp_remote_get( 'http://woocommerce.ir/api/themes.json' );
11
+ if ( empty( $response->errors ) ) {
12
+ break;
13
+ }
14
+ }
15
+
16
+ if ( ! empty( $response->errors ) ) {
17
+ echo '<br><h1>در اتصال به سرور خطایی رخ داده است. لطفا چند دقیقه دیگر تلاش کنید.</h1>';
18
+
19
+ return;
20
+ }
21
+
22
+ if ( is_array( $response ) ) {
23
+ $response = json_decode( $response['body'] );
24
+ }
25
+
26
+ $count = 0;
27
+
28
+ ?>
29
+ <div class="wrap woocommerce wc_addons_wrap">
30
+ <h1><?php echo get_admin_page_title(); ?></h1>
31
+
32
+
33
+ <div class="addons-featured">
34
+ <div class="addons-banner-block">
35
+ <h1>پوسته های فروشگاه ساز ووکامرس</h1>
36
+ <h3>ارائه برترین پوسته ها توسط ووکامرس فارسی همراه با پشتیبانی</h3>
37
+ <p>انتخاب یک قالب خوب ، رابطه مستقیمی با فروش و ارتباط بیشتر با مخاطبان شما دارد. همچنین انتخاب یک قالب ایده
38
+ آل و استاندارد باعث بهبود رتبه در موتور های جستجو می گردد. در انتخاب پوسته فروشگاه خود دقت کنید! برای
39
+ اطلاع از آخرین تخفیف ها و اطلاعیه های ووکامرس ، <a target="_blank" href="https://t.me/woocommerce_ir">کانال
40
+ تلگرام ووکامرس فارسی</a> را دنبال کنید</p>
41
+
42
+ <?php foreach ( $response as $item ) : ?>
43
+ <?php if ( $count ++ % 3 == 0 ) {
44
+ echo '<div class="addons-banner-block-items">';
45
+ } ?>
46
+ <div class="addons-banner-block-item">
47
+ <div class="addons-banner-block-item-icon"
48
+ style="background: linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url('<?php echo esc_url( $item->image ); ?>')!important;">
49
+ <img class="addons-img" src="<?php echo esc_url( $item->image ); ?>">
50
+
51
+ </div>
52
+ <div class="addons-banner-block-item-content">
53
+ <h3><?php echo esc_html( $item->title ); ?></h3>
54
+
55
+ <p><?php
56
+
57
+ $string = strip_tags( $item->desc );
58
+
59
+ if ( strlen( $string ) > 220 ) {
60
+ $stringCut = substr( $string, 0, 220 );
61
+ $string = substr( $stringCut, 0, strrpos( $stringCut, ' ' ) ) . '... <a href="' . esc_url( $item->url ) . '">اطلاعات بیشتر</a>';
62
+ }
63
+ echo wp_kses_data( $string ); ?></p>
64
+ <a class="addons-button addons-button-solid"
65
+ href="<?php echo esc_url( $item->url ); ?>"><?php echo esc_html( $item->price ); ?> / اطلاعات
66
+ بیشتر</a>
67
+ </div>
68
+ </div>
69
+ <?php if ( $count % 3 == 0 ) {
70
+ echo '</div>';
71
+ } ?>
72
+ <?php endforeach; ?>
73
+
74
+ </div>
75
+ </div>
76
+
77
+ </div>
78
+
79
+ <style type="text/css">
80
+ .ver {
81
+ -webkit-transform: rotate(-45deg);
82
+ -moz-transform: rotate(-45deg);
83
+ -o-transform: rotate(-45deg);
84
+ -ms-transform: rotate(-45deg);
85
+ transform: rotate(-45deg);
86
+ position: relative;
87
+ top: 0px;
88
+ left: -40px;
89
+ }
90
+
91
+ img.addons-img {
92
+ height: 100% !important;
93
+ opacity: 1.0;
94
+ border-right: 1px solid #e4e4e4;
95
+ border-left: 1px solid #e4e4e4;
96
+ }
97
+
98
+ .addons-banner-block-item-icon {
99
+ height: 200px;
100
+ }
101
+
102
+ .addons-button {
103
+ width: auto !important;
104
+ }
105
+
106
+ .addons-banner-block-item-content p {
107
+ text-align: justify;
108
+ }
109
+ </style>
readme.txt CHANGED
@@ -1,12 +1,13 @@
1
- === Persian Woocommerce ===
2
  author: ووکامرس فارسی
3
- Contributors: Persianscript, hannanstd, mahdiy
4
  author URI: https://www.woosupport.ir/
5
  plugin URI: https://www.woosupport.ir/download/
6
- Tags: persian,parsi,parsian,persians,farsi,iran,woocommerce, persian woocommerce, woocommerce farsi, iran, iranian, rtl, fa_IR,states,iranian rials,iranian tomans, woocommerce.ir,affiliate, cart, checkout, commerce, configurable, digital, download, downloadable, e-commerce, ecommerce, inventory, reports, sales, sell, shipping, shop, shopping, stock, store, tax, variable, widgets, woothemes, wordpress ecommerce
7
  Requires at least: 5.0
8
- Tested up to: 5.7.1
9
  Requires PHP: 7.1
 
10
 
11
  بسته ووکامرس پارسی به راحتی سیستم فروشگاه ساز ووکامرس را فارسی می کند و امکانات جدید متناسب با ایران را به ووکامرس اضافه میکند.
12
 
@@ -27,15 +28,17 @@ Requires PHP: 7.1
27
  * واحد های پولی تومان، ریال، هزار تومان و هزار ریال
28
  * شمسی سازی محیط وردپرس و ووکامرس
29
  * لیست استان های ایران
30
- * بخش کاربری و مدیریت ووکامرس به صورت فارسی
31
  * لیست شهر های ایران (جدید)
32
- * راست چین سازی بخش مدیریت فروشگاه
33
  * ابزار جایگزین کننده عبارات و ترجمه ها (جدید)
34
  * ابزار محدودیت فروش در استان های خاص (جدید)
35
  * ابزار متن دلخواه جایگزین قیمت محصولات (جدید)
36
  * ابزار پذیرش اعداد فارسی در بخش شماره موبایل و کد پستی (جدید)
37
  * ابزار تایید صحت شماره موبایل
38
  * ابزار تایید کدپستی
 
 
 
 
39
  * و...
40
 
41
  == Installation ==
@@ -44,11 +47,46 @@ Requires PHP: 7.1
44
 
45
  == Frequently asked questions ==
46
 
47
- = Where can I find more information and documentation about the plug-in? =
48
 
49
- You can read complete documentations on the [WooSupport.ir](https://www.woosupport.ir)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  == Changelog ==
 
 
 
 
 
 
 
 
 
52
  = 5.2.2 =
53
  * بروزرسانی ترجمه
54
  = 4.0.5 =
@@ -195,7 +233,7 @@ You can read complete documentations on the [WooSupport.ir](https://www.woosuppo
195
  * نسخه اولیه
196
 
197
  == Upgrade Notice ==
198
- = 5.2.2 =
199
- * بروزرسانی فایل زبان و سازگاری با ووکامرس 5.2.2
200
  == Traducciones ==
201
  پشتیبانی در سایت [WooSupport.ir](https://www.woosupport.ir) انجام میشود.
1
+ === ووکامرس فارسی ===
2
  author: ووکامرس فارسی
3
+ Contributors: Persianscript, mahdiy
4
  author URI: https://www.woosupport.ir/
5
  plugin URI: https://www.woosupport.ir/download/
6
+ Tags: ووکامرس,ووکامرس فارسی,persian woocommerce,woocommerce,iran,persian,farsi,jalali,shamsi
7
  Requires at least: 5.0
8
+ Tested up to: 5.8.2
9
  Requires PHP: 7.1
10
+ Stable tag: 5.8.0
11
 
12
  بسته ووکامرس پارسی به راحتی سیستم فروشگاه ساز ووکامرس را فارسی می کند و امکانات جدید متناسب با ایران را به ووکامرس اضافه میکند.
13
 
28
  * واحد های پولی تومان، ریال، هزار تومان و هزار ریال
29
  * شمسی سازی محیط وردپرس و ووکامرس
30
  * لیست استان های ایران
 
31
  * لیست شهر های ایران (جدید)
 
32
  * ابزار جایگزین کننده عبارات و ترجمه ها (جدید)
33
  * ابزار محدودیت فروش در استان های خاص (جدید)
34
  * ابزار متن دلخواه جایگزین قیمت محصولات (جدید)
35
  * ابزار پذیرش اعداد فارسی در بخش شماره موبایل و کد پستی (جدید)
36
  * ابزار تایید صحت شماره موبایل
37
  * ابزار تایید کدپستی
38
+ * ابزار نمایش کمترین قیمت برای محصولات متغیر
39
+ * ابزار مشخص نمودن حداقل میزان مبلغ برای ثبت سفارش
40
+ * ابزار حذف خودکار فیلد های اضافه تسویه حساب برای محصولات دانلودی
41
+ * تبدیل حروف عربی به فارسی در هنگام جستجو در فروشگاه
42
  * و...
43
 
44
  == Installation ==
47
 
48
  == Frequently asked questions ==
49
 
50
+ = آیا با نصب ووکامرس فارسی از هسته اصلی ووکامرس بی نیاز می شوم؟ =
51
 
52
+ خیر! شما باید هسته اصلی وردپرس را از [اینجا](https://wordpress.org/plugins/woocommerce/) دانلود کنید و در کنار ووکامرس فارسی استفاده نمایید.
53
+
54
+ = من ووکامرس رو نصب کردم و فارسی هست چرا باید بسته بومی ساز رو نصب کنم؟ =
55
+
56
+ * ووکامرس فارسی یک بسته بومی ساز کامله . یک سری ابزارهای کاربردی برای شما در این بسته قرار داده شده که بر اساس نیازهای کاربر ایرانی شخصی سازی شده.
57
+ * برای مثال ، در صفحه تسویه حساب اگر در قسمت کدپستی و شماره موبایل اعداد فارسی وارد بشه (مثلا در حالت زبان فارسی در موبایل های هوشمند) در ووکامرس یک خطا رخ میده که لطفا شماره موبایل و کدپستی صحیح را وارد کنید! چون حروف فارسی رو به عنوان عدد شناسایی نمیکنه و کاربر شما این رو نمیدونه! ووکامرس فارسی یک ابزار ویژه برای تبدیل اعداد فارسی به انگلیسی قرار داده که این مشکل رفع شده!
58
+ * شما میتونید در صفحه تسویه حساب بدون اینکه نیاز باشه ، کاری کنید تا کاربر بجای وارد کردن اسم شهرش ، از لیست موجود شهرش رو انتخاب کنه!
59
+ * ابزار تاریخ شمسی ووکامرس به شما کمک میکنه تا به راحتی تاریخ تخفیف ها و سایر بخش های مربوط به ووکامرس رو به صورت کامل شمسی مشاهده کنید.
60
+ * میتونید به راحتی کمترین قیمت رو به عنوان قیمت اصلی برای نمایش به کاربر ، در محصولات ووکامرس به کاربر نمایش بدید!
61
+ * ترجمه کاملا روان و ساده بسته فارسی ساز ووکامرس باعث میشه کاربر با وب سایت شما ارتباط بگیره. ترجمه موجود در ووکامرس اصلی کاملا به صورت ماشینی ثبت شده و افراد متفاوت با تخصص های معمولا پایین کلمات با معانی و مفاهیم نادرست اقدام به ترجمه کردن.
62
+ * ابزار جایگزین کننده عبارات به شما کمک میکنه هر جای سایتت که کلمات انگلیسی وجود داره ، واژه فارسی شو جایگزین کنی تا به راحتی در سایتت جایگزین بشه
63
+ * حروف عربی رو به راحتی در هنگام جستجوی کاربران به حروف فارسی تبدیل کنید!
64
+ * میخوای فروشت رو به یک استان محدود کنی؟ خب کافیه ابزار ما رو تست کنی! چنین قابلیتی رو برای شما فراهم کردیم
65
+ * نمیخوای برای محصولت قیمت بزاری؟ میخوای در قسمت قیمت نوشته بشه "تماس بگیرید" ؟ کافیه ابزار ما رو امتحان کنی
66
+ * هنوز راضی نشدی؟ کافیه یک بار تستش کنی!...
67
+
68
+ = تاریخ شمسی ووکامرس فارسی به چه صورت عمل میکنه؟ =
69
+
70
+ ووکامرس فارسی طوری شمسی ساز رو طراحی کرده تا در صورتی که افزونه رو غیر فعال کردید ، هیچ اتفاقی برای داده های موجود در دیتابیس رخ نده.
71
+
72
+ = چه درگاه های بانکی در بسته فارسی ساز وجود داره =
73
+
74
+ تا الان یک درگاه بانکی درون بسته وجود داره ، اما به زودی کلی درگاه رایگان دیگه در این بسته اضافه میشه.
75
+
76
+ = پاسخم را نیافتم. از چه طریقی میتوانم اقدام کنم؟ =
77
+
78
+ میتوانید راهنما و مستندات را از طریق سایت [WooSupport.ir](https://www.woosupport.ir) بدست بیاورید
79
 
80
  == Changelog ==
81
+ = 5.8.0 =
82
+ * بروزرسانی درگاه پرداخت پی.آی.آر
83
+ * بهبود ابزار بررسی صحت کدپستی
84
+ * افزودن ابزار تبدیل حروف عربی به فارسی در جستجو
85
+ * بازنویسی سیستم نوتیفیکیشن
86
+ * بهبود ابزار حذف فیلد‌های تسویه حساب برای محصولات دانلودی و مجازی
87
+ * افزودن ابزار مدیریت قیمت محصولات متغیر
88
+ = 5.7.1 =
89
+ * بروزرسانی ترجمه
90
  = 5.2.2 =
91
  * بروزرسانی ترجمه
92
  = 4.0.5 =
233
  * نسخه اولیه
234
 
235
  == Upgrade Notice ==
236
+ = 5.8.0 =
237
+ * Bug Fix in Translate Class
238
  == Traducciones ==
239
  پشتیبانی در سایت [WooSupport.ir](https://www.woosupport.ir) انجام میشود.
woocommerce-persian.php CHANGED
@@ -2,20 +2,18 @@
2
  /*
3
  Plugin Name: ووکامرس فارسی
4
  Plugin URI: https://woosupport.ir
5
- Description: بسته فارسی ساز ووکامرس پارسی به راحتی سیستم فروشگاه ساز ووکامرس را فارسی می کند. با فعال سازی افزونه ، بسیاری از قابلیت های مخصوص ایران به افزونه افزوده می شوند. پشتیبانی در <a href="http://www.woocommerce.ir/" target="_blank">ووکامرس پارسی</a>.
6
- Version: 5.2.2
7
  Author: ووکامرس فارسی
8
  Author URI: https://woosupport.ir
9
- WC requires at least: 3.6.0
10
- WC tested up to: 5.2.2
11
  */
12
 
13
- if ( ! defined( 'ABSPATH' ) ) {
14
- exit;
15
- } // Exit if accessed directly
16
 
17
  if ( ! defined( 'PW_VERSION' ) ) {
18
- define( 'PW_VERSION', '5.2.2' );
19
  }
20
 
21
  if ( ! defined( 'PW_DIR' ) ) {
@@ -37,7 +35,7 @@ function PW() {
37
  return Persian_Woocommerce_Core::instance();
38
  }
39
 
40
- add_action( 'woocommerce_loaded', function() {
41
 
42
  require_once( 'vendor/autoload.php' );
43
  require_once( 'include/class-core.php' );
@@ -46,9 +44,10 @@ add_action( 'woocommerce_loaded', function() {
46
  require_once( 'include/class-tools.php' );
47
  require_once( 'include/class-address.php' );
48
  require_once( 'include/class-currencies.php' );
 
49
 
50
  } );
51
 
52
- register_activation_hook( PW_FILE, function() {
53
  file_put_contents( PW_DIR . '/.activated', '' );
54
  } );
2
  /*
3
  Plugin Name: ووکامرس فارسی
4
  Plugin URI: https://woosupport.ir
5
+ Description: بسته فارسی ساز ووکامرس پارسی به راحتی سیستم فروشگاه ساز ووکامرس را فارسی می کند. با فعال سازی افزونه ، بسیاری از قابلیت های مخصوص ایران به افزونه افزوده می شوند. پشتیبانی در <a href="http://woosupport.ir" target="_blank">ووکامرس پارسی</a>.
6
+ Version: 5.8.0
7
  Author: ووکامرس فارسی
8
  Author URI: https://woosupport.ir
9
+ WC requires at least: 4.0.0
10
+ WC tested up to: 5.9.0
11
  */
12
 
13
+ defined( 'ABSPATH' ) || exit;
 
 
14
 
15
  if ( ! defined( 'PW_VERSION' ) ) {
16
+ define( 'PW_VERSION', '5.8.1' );
17
  }
18
 
19
  if ( ! defined( 'PW_DIR' ) ) {
35
  return Persian_Woocommerce_Core::instance();
36
  }
37
 
38
+ add_action( 'woocommerce_loaded', function () {
39
 
40
  require_once( 'vendor/autoload.php' );
41
  require_once( 'include/class-core.php' );
44
  require_once( 'include/class-tools.php' );
45
  require_once( 'include/class-address.php' );
46
  require_once( 'include/class-currencies.php' );
47
+ require_once( 'include/class-notice.php' );
48
 
49
  } );
50
 
51
+ register_activation_hook( PW_FILE, function () {
52
  file_put_contents( PW_DIR . '/.activated', '' );
53
  } );