Ultimate Tag Cloud Widget - Version 2.2-beta1

Version Description

= 2.2 =

  • New features, see the plugin page at wordpress.org for full details

= 2.1 =

  • New features, see the plugin page at wordpress.org for full details

= 2.0.1 =

  • Small bug fix in the widget options panel

= 2.0 =

  • New plugin architecture and a big rewrite of the plugin foundation. Watch out for breaking changes, please see http://exz.nu/utcwbreaking for more information.
Download this release

Release Info

Developer exz
Plugin Icon wp plugin Ultimate Tag Cloud Widget
Version 2.2-beta1
Comparing to
See all releases

Code changes from version 2.1 to 2.2-beta1

js/utcw.min.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! Ultimate Tag Cloud Widget - v2.1 - 2013-01-27
2
  * https://0x539.se/wordpress/ultimate-tag-cloud-widget/
3
  * Copyright (c) 2013 Rickard Andersson; Licensed GPLv2 */
4
  var Query=function(e){"use strict";var t=function(e){var t=[],n,r,i,s;if(typeof e=="undefined"||e===null||e==="")return t;e.indexOf("?")===0&&(e=e.substring(1)),r=e.toString().split(/[&;]/);for(n=0;n<r.length;n++)i=r[n],s=i.split("="),t.push([s[0],s[1]]);return t},n=t(e),r=function(){var e="",t,r;for(t=0;t<n.length;t++)r=n[t],e.length>0&&(e+="&"),e+=r.join("=");return e.length>0?"?"+e:e},i=function(e){return e=decodeURIComponent(e),e=e.replace("+"," "),e},s=function(e){var t,r;for(r=0;r<n.length;r++){t=n[r];if(i(e)===i(t[0]))return t[1]}},o=function(e){var t=[],r,s;for(r=0;r<n.length;r++)s=n[r],i(e)===i(s[0])&&t.push(s[1]);return t},u=function(e,t){var r=[],s,o,u,a;for(s=0;s<n.length;s++)o=n[s],u=i(o[0])===i(e),a=i(o[1])===i(t),(arguments.length===1&&!u||arguments.length===2&&!u&&!a)&&r.push(o);return n=r,this},a=function(e,t,r){return arguments.length===3&&r!==-1?(r=Math.min(r,n.length),n.splice(r,0,[e,t])):arguments.length>0&&n.push([e,t]),this},f=function(e,t,r){var s=-1,o,f;if(arguments.length===3){for(o=0;o<n.length;o++){f=n[o];if(i(f[0])===i(e)&&decodeURIComponent(f[1])===i(r)){s=o;break}}u(e,r).addParam(e,t,s)}else{for(o=0;o<n.length;o++){f=n[o];if(i(f[0])===i(e)){s=o;break}}u(e),a(e,t,s)}return this};return{getParamValue:s,getParamValues:o,deleteParam:u,addParam:a,replaceParam:f,toString:r}},Uri=function(e){"use strict";var t=!1,n=function(e){var n={strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/},r=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],i={name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},s=n[t?"strict":"loose"].exec(e),o={},u=14;while(u--)o[r[u]]=s[u]||"";return o[i.name]={},o[r[12]].replace(i.parser,function(e,t,n){t&&(o[i.name][t]=n)}),o},r=n(e||""),i=new Query(r.query),s=function(e){return typeof e!="undefined"&&(r.protocol=e),r.protocol},o=null,u=function(e){return typeof e!="undefined"&&(o=e),o===null?r.source.indexOf("//")!==-1:o},a=function(e){return typeof e!="undefined"&&(r.userInfo=e),r.userInfo},f=function(e){return typeof e!="undefined"&&(r.host=e),r.host},l=function(e){return typeof e!="undefined"&&(r.port=e),r.port},c=function(e){return typeof e!="undefined"&&(r.path=e),r.path},h=function(e){return typeof e!="undefined"&&(i=new Query(e)),i},p=function(e){return typeof e!="undefined"&&(r.anchor=e),r.anchor},d=function(e){return s(e),this},v=function(e){return u(e),this},m=function(e){return a(e),this},g=function(e){return f(e),this},y=function(e){return l(e),this},b=function(e){return c(e),this},w=function(e){return h(e),this},E=function(e){return p(e),this},S=function(e){return h().getParamValue(e)},x=function(e){return h().getParamValues(e)},T=function(e,t){return arguments.length===2?h().deleteParam(e,t):h().deleteParam(e),this},N=function(e,t,n){return arguments.length===3?h().addParam(e,t,n):h().addParam(e,t),this},C=function(e,t,n){return arguments.length===3?h().replaceParam(e,t,n):h().replaceParam(e,t),this},k=function(){var e="",t=function(e){return e!==null&&e!==""};return t(s())?(e+=s(),s().indexOf(":")!==s().length-1&&(e+=":"),e+="//"):u()&&t(f())&&(e+="//"),t(a())&&t(f())&&(e+=a(),a().indexOf("@")!==a().length-1&&(e+="@")),t(f())&&(e+=f(),t(l())&&(e+=":"+l())),t(c())?e+=c():t(f())&&(t(h().toString())||t(p()))&&(e+="/"),t(h().toString())&&(h().toString().indexOf("?")!==0&&(e+="?"),e+=h().toString()),t(p())&&(p().indexOf("#")!==0&&(e+="#"),e+=p()),e},L=function(){return new Uri(k())};return{protocol:s,hasAuthorityPrefix:u,userInfo:a,host:f,port:l,path:c,query:h,anchor:p,setProtocol:d,setHasAuthorityPrefix:v,setUserInfo:m,setHost:g,setPort:y,setPath:b,setQuery:w,setAnchor:E,getQueryParamValue:S,getQueryParamValues:x,deleteQueryParam:T,addQueryParam:N,replaceQueryParam:C,toString:k,clone:L}},jsUri=Uri;(function(e){e.fn.wTooltip=function(t,n){function m(n){n&&(t.degrade?e(h).html(t.content.replace(/<\/?[^>]+>/gi,"")):e(h).html(t.content))}function g(n){function i(e){r&&!t.content&&(r="")}function u(){!l&&t.auto&&(clearInterval(o),t.fadeOut?e(h).fadeOut(t.fadeOut,function(){i(n)}):(i(n),h.style.display="none")),typeof t.callAfter=="function"&&t.callAfter(h,n,t),d&&(t=e.listen(t))}t.timeout>0?s=setTimeout(function(){u()},t.timeout):u()}t=e.extend({content:null,ajax:null,follow:!0,auto:!0,fadeIn:0,fadeOut:0,appendTip:document.body,degrade:!1,offsetY:10,offsetX:1,style:{},className:null,id:null,callBefore:function(e,t,n){},callAfter:function(e,t,n){},clickAction:function(t,n){e(t).hide()},delay:0,timeout:0},t||{}),!t.style&&typeof t.style!="object"?(t.style={},t.style.zIndex="1000"):t.style=e.extend({border:"1px solid gray",background:"#edeef0",color:"#000",padding:"10px",zIndex:"1000",textAlign:"left"},t.style||{}),typeof n=="function"&&(t.callAfter=n||t.callAfter),t.style.display="none",t.style.position="absolute";var r,i,s,o,u={},f=!0,l=!1,c=!1,h=document.createElement("div"),p=typeof document.body.style.maxWidth=="undefined"?!0:!1,d=typeof e.talk=="function"&&typeof e.listen=="function"?!0:!1;t.id&&(h.id=t.id),t.className&&(h.className=t.className),t.degrade=t.degrade&&p?!0:!1;for(var v in t.style)h.style[v]=t.style[v];return t.ajax&&e.get(t.ajax,function(e){e&&(t.content=e),m(t.content)}),e(h).hover(function(){l=!0},function(){l=!1,g(u)}),d&&(t.key=h,t.plugin="wTooltip",t.channel="wayfarer",e.talk(t)),m(t.content&&!t.ajax),e(h).appendTo(t.appendTip),this.each(function(){e(this).hover(function(){function o(){typeof t.callBefore=="function"&&t.callBefore(h,n,t),d&&(t=e.listen(t));var i;t.content?t.degrade||(i="block"):r&&!t.degrade?(e(h).html(unescape(r)),i="block",r=""):i="none",t.auto&&(i=="block"&&t.fadeIn?e(h).fadeIn(t.fadeIn):h.style.display=i)}var n=this;clearTimeout(s),(this.title||this.titleMemKeep)&&!t.degrade&&!t.content&&(r=this.title||this.titleMemKeep,this.title&&(this.titleMemKeep=this.title,this.title="")),t.content&&t.degrade&&(this.title=h.innerHTML),t.delay>0?i=setTimeout(function(){o()},t.delay):o()},function(){clearTimeout(i);var n=this;f=!0,!t.follow||c||t.offsetX<0&&0-t.offsetX<e(h).outerWidth()&&t.offsetY>0&&0-t.offsetY<e(h).outerHeight()?setTimeout(function(){o=setInterval(function(){g(n)},1)},1):g(this)}),e(this).mousemove(function(n){u=this;if(t.follow||f){var r=e(window).scrollTop(),i=e(window).scrollLeft(),s=n.clientY+r+t.offsetY,o=n.clientX+i+t.offsetX,l=e(t.appendTip).outerHeight(),p=e(t.appendTip).innerHeight(),d=e(window).width()+i-e(h).outerWidth(),v=e(window).height()+r-e(h).outerHeight();s=l>p?s-(l-p):s,c=s>v||o>d?!0:!1,o-i<=0&&t.offsetX<0?o=i:o>d&&(o=d),s-r<=0&&t.offsetY<0?s=r:s>v&&(s=v),h.style.top=s+"px",h.style.left=o+"px",f=!1}}),typeof t.clickAction=="function"&&e(this).click(function(){t.clickAction(h,this)})})}})(jQuery),function(e){"use strict";var t={border:"solid 1px #6295fb",background:"#fff",color:"#000",padding:"5px",zIndex:1e3},n={activeTab:{},init:function(){e("input[id$=-color_none], input[id$=-color_random], input[id$=-color_set], input[id$=-color_span]").live("click",this.colorClickHandler),e(".utcw-tab-button").live("click",this.tabClickHandler),e(".utcw-input-taxonomy").live("click",this.taxonomyClickHandler),e(".utcw-all-authors").live("click",this.allAuthorsClickHandler),e(".utcw-selected-authors").live("click",this.selectedAuthorsClickHandler),e(".utcw-remove-config").live("click",this.removeConfigClickHandler),e(document).ready(this.initTooltip),e(document).ajaxSuccess(this.ajaxSuccessHandler)},initTooltip:function(){e(".utcw-help").wTooltip({style:t,className:"utcw-tooltip"})},removeConfigClickHandler:function(){var t=e(this),r=n.findWidgetParent(t),i=r.find(".utcw-load-config"),s=i.val(),o=t.data("input-name")+"[]",u=e(document.createElement("input"));u.attr("type","hidden"),u.attr("name",o),u.attr("value",s),t.after(u),i.find(":selected").remove()},allAuthorsClickHandler:function(){var t=e(this),r=n.findWidgetParent(t);r.find(".utcw-authors").addClass("hidden"),r.find(".utcw-author-field").attr("checked",!1)},selectedAuthorsClickHandler:function(){var t=e(this),r=n.findWidgetParent(t);r.find(".utcw-authors").removeClass("hidden")},tabClickHandler:function(){var t=e(this);return t.data("id")==="utcw-__i__"?!1:(t.parent().find(".utcw-tab-button").removeClass("utcw-active"),t.addClass("utcw-active"),t.parent().find("fieldset.utcw").addClass("hidden"),e("#"+t.data("tab")).removeClass("hidden"),n.activeTab[t.data("id")]=t.data("tab"),!1)},colorClickHandler:function(){var t=e('div[id$="set_chooser"]'),n=e('div[id$="span_chooser"]'),r=e(this).val();t.addClass("utcw-hidden"),n.addClass("utcw-hidden"),r==="set"?t.removeClass("utcw-hidden"):r==="span"&&n.removeClass("utcw-hidden")},findWidgetParent:function(e){return e.parents(".widget-content")},taxonomyClickHandler:function(){var t=e(this),r=t.val(),i=t.is(":checked"),s=n.findWidgetParent(t),o=s.find("#"+r+"-terms");i?o.removeClass("hidden"):o.addClass("hidden")},ajaxSuccessHandler:function(e,t,r){n.setCurrentTab.apply(n,[r.data]),n.initTooltip.apply(n)},setCurrentTab:function(t){var n=new Uri,r;n.setQuery(decodeURI(t)),n.getQueryParamValue("action")==="save-widget"&&n.getQueryParamValue("id_base")==="utcw"&&(r=n.getQueryParamValue("widget-id"),this.activeTab[r]&&e('button[data-tab="'+this.activeTab[r]+'"]').trigger("click"))}};n.init()}(jQuery);
1
+ /*! Ultimate Tag Cloud Widget - v2.1 - 2013-02-03
2
  * https://0x539.se/wordpress/ultimate-tag-cloud-widget/
3
  * Copyright (c) 2013 Rickard Andersson; Licensed GPLv2 */
4
  var Query=function(e){"use strict";var t=function(e){var t=[],n,r,i,s;if(typeof e=="undefined"||e===null||e==="")return t;e.indexOf("?")===0&&(e=e.substring(1)),r=e.toString().split(/[&;]/);for(n=0;n<r.length;n++)i=r[n],s=i.split("="),t.push([s[0],s[1]]);return t},n=t(e),r=function(){var e="",t,r;for(t=0;t<n.length;t++)r=n[t],e.length>0&&(e+="&"),e+=r.join("=");return e.length>0?"?"+e:e},i=function(e){return e=decodeURIComponent(e),e=e.replace("+"," "),e},s=function(e){var t,r;for(r=0;r<n.length;r++){t=n[r];if(i(e)===i(t[0]))return t[1]}},o=function(e){var t=[],r,s;for(r=0;r<n.length;r++)s=n[r],i(e)===i(s[0])&&t.push(s[1]);return t},u=function(e,t){var r=[],s,o,u,a;for(s=0;s<n.length;s++)o=n[s],u=i(o[0])===i(e),a=i(o[1])===i(t),(arguments.length===1&&!u||arguments.length===2&&!u&&!a)&&r.push(o);return n=r,this},a=function(e,t,r){return arguments.length===3&&r!==-1?(r=Math.min(r,n.length),n.splice(r,0,[e,t])):arguments.length>0&&n.push([e,t]),this},f=function(e,t,r){var s=-1,o,f;if(arguments.length===3){for(o=0;o<n.length;o++){f=n[o];if(i(f[0])===i(e)&&decodeURIComponent(f[1])===i(r)){s=o;break}}u(e,r).addParam(e,t,s)}else{for(o=0;o<n.length;o++){f=n[o];if(i(f[0])===i(e)){s=o;break}}u(e),a(e,t,s)}return this};return{getParamValue:s,getParamValues:o,deleteParam:u,addParam:a,replaceParam:f,toString:r}},Uri=function(e){"use strict";var t=!1,n=function(e){var n={strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/},r=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],i={name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},s=n[t?"strict":"loose"].exec(e),o={},u=14;while(u--)o[r[u]]=s[u]||"";return o[i.name]={},o[r[12]].replace(i.parser,function(e,t,n){t&&(o[i.name][t]=n)}),o},r=n(e||""),i=new Query(r.query),s=function(e){return typeof e!="undefined"&&(r.protocol=e),r.protocol},o=null,u=function(e){return typeof e!="undefined"&&(o=e),o===null?r.source.indexOf("//")!==-1:o},a=function(e){return typeof e!="undefined"&&(r.userInfo=e),r.userInfo},f=function(e){return typeof e!="undefined"&&(r.host=e),r.host},l=function(e){return typeof e!="undefined"&&(r.port=e),r.port},c=function(e){return typeof e!="undefined"&&(r.path=e),r.path},h=function(e){return typeof e!="undefined"&&(i=new Query(e)),i},p=function(e){return typeof e!="undefined"&&(r.anchor=e),r.anchor},d=function(e){return s(e),this},v=function(e){return u(e),this},m=function(e){return a(e),this},g=function(e){return f(e),this},y=function(e){return l(e),this},b=function(e){return c(e),this},w=function(e){return h(e),this},E=function(e){return p(e),this},S=function(e){return h().getParamValue(e)},x=function(e){return h().getParamValues(e)},T=function(e,t){return arguments.length===2?h().deleteParam(e,t):h().deleteParam(e),this},N=function(e,t,n){return arguments.length===3?h().addParam(e,t,n):h().addParam(e,t),this},C=function(e,t,n){return arguments.length===3?h().replaceParam(e,t,n):h().replaceParam(e,t),this},k=function(){var e="",t=function(e){return e!==null&&e!==""};return t(s())?(e+=s(),s().indexOf(":")!==s().length-1&&(e+=":"),e+="//"):u()&&t(f())&&(e+="//"),t(a())&&t(f())&&(e+=a(),a().indexOf("@")!==a().length-1&&(e+="@")),t(f())&&(e+=f(),t(l())&&(e+=":"+l())),t(c())?e+=c():t(f())&&(t(h().toString())||t(p()))&&(e+="/"),t(h().toString())&&(h().toString().indexOf("?")!==0&&(e+="?"),e+=h().toString()),t(p())&&(p().indexOf("#")!==0&&(e+="#"),e+=p()),e},L=function(){return new Uri(k())};return{protocol:s,hasAuthorityPrefix:u,userInfo:a,host:f,port:l,path:c,query:h,anchor:p,setProtocol:d,setHasAuthorityPrefix:v,setUserInfo:m,setHost:g,setPort:y,setPath:b,setQuery:w,setAnchor:E,getQueryParamValue:S,getQueryParamValues:x,deleteQueryParam:T,addQueryParam:N,replaceQueryParam:C,toString:k,clone:L}},jsUri=Uri;(function(e){e.fn.wTooltip=function(t,n){function m(n){n&&(t.degrade?e(h).html(t.content.replace(/<\/?[^>]+>/gi,"")):e(h).html(t.content))}function g(n){function i(e){r&&!t.content&&(r="")}function u(){!l&&t.auto&&(clearInterval(o),t.fadeOut?e(h).fadeOut(t.fadeOut,function(){i(n)}):(i(n),h.style.display="none")),typeof t.callAfter=="function"&&t.callAfter(h,n,t),d&&(t=e.listen(t))}t.timeout>0?s=setTimeout(function(){u()},t.timeout):u()}t=e.extend({content:null,ajax:null,follow:!0,auto:!0,fadeIn:0,fadeOut:0,appendTip:document.body,degrade:!1,offsetY:10,offsetX:1,style:{},className:null,id:null,callBefore:function(e,t,n){},callAfter:function(e,t,n){},clickAction:function(t,n){e(t).hide()},delay:0,timeout:0},t||{}),!t.style&&typeof t.style!="object"?(t.style={},t.style.zIndex="1000"):t.style=e.extend({border:"1px solid gray",background:"#edeef0",color:"#000",padding:"10px",zIndex:"1000",textAlign:"left"},t.style||{}),typeof n=="function"&&(t.callAfter=n||t.callAfter),t.style.display="none",t.style.position="absolute";var r,i,s,o,u={},f=!0,l=!1,c=!1,h=document.createElement("div"),p=typeof document.body.style.maxWidth=="undefined"?!0:!1,d=typeof e.talk=="function"&&typeof e.listen=="function"?!0:!1;t.id&&(h.id=t.id),t.className&&(h.className=t.className),t.degrade=t.degrade&&p?!0:!1;for(var v in t.style)h.style[v]=t.style[v];return t.ajax&&e.get(t.ajax,function(e){e&&(t.content=e),m(t.content)}),e(h).hover(function(){l=!0},function(){l=!1,g(u)}),d&&(t.key=h,t.plugin="wTooltip",t.channel="wayfarer",e.talk(t)),m(t.content&&!t.ajax),e(h).appendTo(t.appendTip),this.each(function(){e(this).hover(function(){function o(){typeof t.callBefore=="function"&&t.callBefore(h,n,t),d&&(t=e.listen(t));var i;t.content?t.degrade||(i="block"):r&&!t.degrade?(e(h).html(unescape(r)),i="block",r=""):i="none",t.auto&&(i=="block"&&t.fadeIn?e(h).fadeIn(t.fadeIn):h.style.display=i)}var n=this;clearTimeout(s),(this.title||this.titleMemKeep)&&!t.degrade&&!t.content&&(r=this.title||this.titleMemKeep,this.title&&(this.titleMemKeep=this.title,this.title="")),t.content&&t.degrade&&(this.title=h.innerHTML),t.delay>0?i=setTimeout(function(){o()},t.delay):o()},function(){clearTimeout(i);var n=this;f=!0,!t.follow||c||t.offsetX<0&&0-t.offsetX<e(h).outerWidth()&&t.offsetY>0&&0-t.offsetY<e(h).outerHeight()?setTimeout(function(){o=setInterval(function(){g(n)},1)},1):g(this)}),e(this).mousemove(function(n){u=this;if(t.follow||f){var r=e(window).scrollTop(),i=e(window).scrollLeft(),s=n.clientY+r+t.offsetY,o=n.clientX+i+t.offsetX,l=e(t.appendTip).outerHeight(),p=e(t.appendTip).innerHeight(),d=e(window).width()+i-e(h).outerWidth(),v=e(window).height()+r-e(h).outerHeight();s=l>p?s-(l-p):s,c=s>v||o>d?!0:!1,o-i<=0&&t.offsetX<0?o=i:o>d&&(o=d),s-r<=0&&t.offsetY<0?s=r:s>v&&(s=v),h.style.top=s+"px",h.style.left=o+"px",f=!1}}),typeof t.clickAction=="function"&&e(this).click(function(){t.clickAction(h,this)})})}})(jQuery),function(e){"use strict";var t={border:"solid 1px #6295fb",background:"#fff",color:"#000",padding:"5px",zIndex:1e3},n={activeTab:{},init:function(){e("input[id$=-color_none], input[id$=-color_random], input[id$=-color_set], input[id$=-color_span]").live("click",this.colorClickHandler),e(".utcw-tab-button").live("click",this.tabClickHandler),e(".utcw-input-taxonomy").live("click",this.taxonomyClickHandler),e(".utcw-all-authors").live("click",this.allAuthorsClickHandler),e(".utcw-selected-authors").live("click",this.selectedAuthorsClickHandler),e(".utcw-remove-config").live("click",this.removeConfigClickHandler),e(document).ready(this.initTooltip),e(document).ajaxSuccess(this.ajaxSuccessHandler)},initTooltip:function(){e(".utcw-help").wTooltip({style:t,className:"utcw-tooltip"})},removeConfigClickHandler:function(){var t=e(this),r=n.findWidgetParent(t),i=r.find(".utcw-load-config"),s=i.val(),o=t.data("input-name")+"[]",u=e(document.createElement("input"));u.attr("type","hidden"),u.attr("name",o),u.attr("value",s),t.after(u),i.find(":selected").remove()},allAuthorsClickHandler:function(){var t=e(this),r=n.findWidgetParent(t);r.find(".utcw-authors").addClass("hidden"),r.find(".utcw-author-field").attr("checked",!1)},selectedAuthorsClickHandler:function(){var t=e(this),r=n.findWidgetParent(t);r.find(".utcw-authors").removeClass("hidden")},tabClickHandler:function(){var t=e(this);return t.data("id")==="utcw-__i__"?!1:(t.parent().find(".utcw-tab-button").removeClass("utcw-active"),t.addClass("utcw-active"),t.parent().find("fieldset.utcw").addClass("hidden"),e("#"+t.data("tab")).removeClass("hidden"),n.activeTab[t.data("id")]=t.data("tab"),!1)},colorClickHandler:function(){var t=e('div[id$="set_chooser"]'),n=e('div[id$="span_chooser"]'),r=e(this).val();t.addClass("utcw-hidden"),n.addClass("utcw-hidden"),r==="set"?t.removeClass("utcw-hidden"):r==="span"&&n.removeClass("utcw-hidden")},findWidgetParent:function(e){return e.parents(".widget-content")},taxonomyClickHandler:function(){var t=e(this),r=t.val(),i=t.is(":checked"),s=n.findWidgetParent(t),o=s.find("#"+r+"-terms");i?o.removeClass("hidden"):o.addClass("hidden")},ajaxSuccessHandler:function(e,t,r){n.setCurrentTab.apply(n,[r.data]),n.initTooltip.apply(n)},setCurrentTab:function(t){var n=new Uri,r;n.setQuery(decodeURI(t)),n.getQueryParamValue("action")==="save-widget"&&n.getQueryParamValue("id_base")==="utcw"&&(r=n.getQueryParamValue("widget-id"),this.activeTab[r]&&e('button[data-tab="'+this.activeTab[r]+'"]').trigger("click"))}};n.init()}(jQuery);
pages/settings.php CHANGED
@@ -2,18 +2,18 @@
2
  /**
3
  * Ultimate Tag Cloud Widget
4
  * @author Rickard Andersson <rickard@0x539.se>
5
- * @version 2.1
6
  * @license GPLv2
7
  * @package utcw
8
  * @subpackage pages
9
  *
10
- * @var UTCW_Config $config
11
  * @var array $available_taxonomies
12
  * @var array $available_post_types
13
  * @var array $configurations
14
  * @var array $terms
15
  * @var array $users
16
- * @var UTCW $this
17
  */
18
  if ( ! defined( 'ABSPATH' ) ) die();
19
 
@@ -33,6 +33,13 @@ if ( ! defined( 'ABSPATH' ) ) die();
33
 
34
  <fieldset class='utcw' id="<?php echo $this->get_field_id( 'utcw-tab-data' ) ?>">
35
  <legend></legend>
 
 
 
 
 
 
 
36
  <a class="utcw-help"
37
  title="<?php _e( 'Only posts from the selected authors will be used when calculating the tag cloud.', 'utcw' ) ?>">?</a>
38
  <strong><?php _e( 'Authors:', 'utcw' ) ?></strong><br>
@@ -272,7 +279,11 @@ if ( ! defined( 'ABSPATH' ) ) die();
272
  <input type="checkbox" name="<?php echo $this->get_field_name( 'show_title' ) ?>"
273
  id="<?php echo $this->get_field_id( 'show_title' ) ?>" <?php echo $config->show_title === true ? 'checked="checked"' : ''?>>
274
  <label for="<?php echo $this->get_field_id( 'show_title' ) ?>"
275
- title="<?php _e( 'This is a title', 'utcw' ) ?>"><?php _e( 'Show title (hover text)', 'utcw' ) ?></label><br>
 
 
 
 
276
  <br>
277
 
278
  <a class="utcw-help"
2
  /**
3
  * Ultimate Tag Cloud Widget
4
  * @author Rickard Andersson <rickard@0x539.se>
5
+ * @version 2.2
6
  * @license GPLv2
7
  * @package utcw
8
  * @subpackage pages
9
  *
10
+ * @var \Rickard\UTCW\Config $config
11
  * @var array $available_taxonomies
12
  * @var array $available_post_types
13
  * @var array $configurations
14
  * @var array $terms
15
  * @var array $users
16
+ * @var \Rickard\UTCW\Widget $this
17
  */
18
  if ( ! defined( 'ABSPATH' ) ) die();
19
 
33
 
34
  <fieldset class='utcw' id="<?php echo $this->get_field_id( 'utcw-tab-data' ) ?>">
35
  <legend></legend>
36
+
37
+ <a class="utcw-help" title="<?php _e('How the tag cloud should find tags to display. Popularity based selection is the default strategy which shows the most popular tags.', 'utcw') ?>">?</a>
38
+ <strong><?php _e('Selection strategy:', 'utcw') ?></strong><br>
39
+ <label><input type="radio" name="<?php echo $this->get_field_name('strategy') ?>" value="popularity" <?php if ($config->strategy === 'popularity') echo 'checked="checked"' ?>><?php _e('Popularity','utcw') ?></label><br>
40
+ <label><input type="radio" name="<?php echo $this->get_field_name('strategy') ?>" value="random" <?php if ($config->strategy === 'random') echo 'checked="checked"' ?>><?php _e('Random','utcw') ?></label><br>
41
+ <br>
42
+
43
  <a class="utcw-help"
44
  title="<?php _e( 'Only posts from the selected authors will be used when calculating the tag cloud.', 'utcw' ) ?>">?</a>
45
  <strong><?php _e( 'Authors:', 'utcw' ) ?></strong><br>
279
  <input type="checkbox" name="<?php echo $this->get_field_name( 'show_title' ) ?>"
280
  id="<?php echo $this->get_field_id( 'show_title' ) ?>" <?php echo $config->show_title === true ? 'checked="checked"' : ''?>>
281
  <label for="<?php echo $this->get_field_id( 'show_title' ) ?>"
282
+ title="<?php _e( 'This is a title', 'utcw' ) ?>"><?php _e( 'Show title (hover text)', 'utcw' ) ?></label><br> <a class="utcw-help"
283
+ title="<?php _e( 'Uncheck this option if you do not want your tag cloud to contain links to the archive page for each tag.', 'utcw' ) ?>">?</a>
284
+ <input type="checkbox" name="<?php echo $this->get_field_name( 'show_links' ) ?>"
285
+ id="<?php echo $this->get_field_id( 'show_links' ) ?>" <?php echo $config->show_links === true ? 'checked="checked"' : ''?>>
286
+ <label for="<?php echo $this->get_field_id( 'show_links' ) ?>"><?php _e( 'Show links', 'utcw' ) ?></label><br>
287
  <br>
288
 
289
  <a class="utcw-help"
readme.txt CHANGED
@@ -47,6 +47,11 @@ If you have questions, please post them in the forums.
47
 
48
  == Changelog ==
49
 
 
 
 
 
 
50
  = 2.1 =
51
 
52
  * Support for multiple taxonomies per widget
@@ -70,6 +75,10 @@ The upgrade notice history for the 1.x branch is available on [GitHub](https://g
70
 
71
  == Upgrade Notice ==
72
 
 
 
 
 
73
  = 2.1 =
74
 
75
  * New features, see the plugin page at wordpress.org for full details
47
 
48
  == Changelog ==
49
 
50
+ = 2.2 =
51
+
52
+ * Support for disabling links in tag cloud output
53
+ * Support for loading a saved configuration from short code
54
+
55
  = 2.1 =
56
 
57
  * Support for multiple taxonomies per widget
75
 
76
  == Upgrade Notice ==
77
 
78
+ = 2.2 =
79
+
80
+ * New features, see the plugin page at wordpress.org for full details
81
+
82
  = 2.1 =
83
 
84
  * New features, see the plugin page at wordpress.org for full details
src/Config.php ADDED
@@ -0,0 +1,898 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage main
13
+ * @since 2.0
14
+ */
15
+
16
+ /**
17
+ * Configuration class for the widget.
18
+ *
19
+ * @since 2.0
20
+ * @package utcw
21
+ * @subpackage main
22
+ */
23
+ class Config
24
+ {
25
+
26
+ /**
27
+ * Title text of the widget.
28
+ * Default value: Tag cloud
29
+ *
30
+ * @var string
31
+ * @since 2.0
32
+ */
33
+ public $title;
34
+
35
+ /**
36
+ * How the result should be ordered
37
+ * Default value: name
38
+ * Valid values: random, name, slug, id, color, count
39
+ *
40
+ * @var string
41
+ * @since 2.0
42
+ */
43
+ public $order;
44
+
45
+ /**
46
+ * The smallest possible size
47
+ * Default: 10px
48
+ *
49
+ * @var string
50
+ * @since 2.0
51
+ */
52
+ public $size_from;
53
+
54
+ /**
55
+ * The greatest possible size
56
+ * Default: 30px
57
+ *
58
+ * @var string
59
+ * @since 2.0
60
+ */
61
+ public $size_to;
62
+
63
+ /**
64
+ * Maximum number of tags to display
65
+ * Default: 45
66
+ *
67
+ * @var int
68
+ * @since 2.0
69
+ */
70
+ public $max;
71
+
72
+ /**
73
+ * Which taxonomy to show tags from
74
+ * Default: [post_tag]
75
+ *
76
+ * @var array
77
+ * @since 2.0
78
+ */
79
+ public $taxonomy;
80
+
81
+ /**
82
+ * If the order of tags should be shown in reverse order
83
+ * Default: false
84
+ *
85
+ * @var bool
86
+ * @since 2.0
87
+ */
88
+ public $reverse;
89
+
90
+ /**
91
+ * Which coloring strategy to use
92
+ * Default: none
93
+ * Valid values: none, random, set, span
94
+ *
95
+ * @var string
96
+ * @since 2.0
97
+ */
98
+ public $color;
99
+
100
+ /**
101
+ * CSS letter-spacing value (in pixels)
102
+ * Default: normal
103
+ *
104
+ * @var string
105
+ * @since 2.0
106
+ */
107
+ public $letter_spacing;
108
+
109
+ /**
110
+ * CSS word-spacing value (in pixels)
111
+ * Default: normal
112
+ *
113
+ * @var string
114
+ * @since 2.0
115
+ */
116
+ public $word_spacing;
117
+
118
+ /**
119
+ * CSS text-transform value
120
+ * Default: none
121
+ * Valid values: lowercase, uppercase, capitalize
122
+ *
123
+ * @var string
124
+ * @since 2.0
125
+ */
126
+ public $text_transform;
127
+
128
+ /**
129
+ * If sorting should be applied case sensitive
130
+ * Default: false
131
+ *
132
+ * @var bool
133
+ * @since 2.0
134
+ */
135
+ public $case_sensitive;
136
+
137
+ /**
138
+ * How many posts a term needs to have to be shown in the cloud
139
+ * Default: 1
140
+ *
141
+ * @var int
142
+ * @since 2.0
143
+ */
144
+ public $minimum;
145
+
146
+ /**
147
+ * How the $tags_list should be used
148
+ * Default: exclude
149
+ * Valid values: exclude, include
150
+ *
151
+ * @var string
152
+ * @since 2.0
153
+ */
154
+ public $tags_list_type;
155
+
156
+ /**
157
+ * If the title attribute should be added to links in the cloud
158
+ * Default: true
159
+ *
160
+ * @var bool
161
+ * @since 2.0
162
+ */
163
+ public $show_title;
164
+
165
+ /**
166
+ * If the tags should be wrapped in links
167
+ * Default: true
168
+ *
169
+ * @var bool
170
+ * @since 2.2
171
+ */
172
+ public $show_links;
173
+
174
+ /**
175
+ * If links should be styled with underline decoration
176
+ * Default: default
177
+ * Valid values: yes, no, default
178
+ *
179
+ * @var string
180
+ * @since 2.0
181
+ */
182
+ public $link_underline;
183
+
184
+ /**
185
+ * If links should be styled as bold
186
+ * Default: default
187
+ * Valid values: yes, no, default
188
+ *
189
+ * @var string
190
+ * @since 2.0
191
+ */
192
+ public $link_bold;
193
+
194
+ /**
195
+ * If links should be styled as italic
196
+ * Default: default
197
+ * Valid values: yes, no, default
198
+ *
199
+ * @var string
200
+ * @since 2.0
201
+ */
202
+ public $link_italic;
203
+
204
+ /**
205
+ * Background color for links
206
+ * Default: transparent
207
+ * Valid values: A hexadecimal color
208
+ *
209
+ * @var string
210
+ * @since 2.0
211
+ */
212
+ public $link_bg_color;
213
+
214
+ /**
215
+ * Border style for links
216
+ * Default: none
217
+ * Valid values: none, dotted, dashed, solid, double, groove, ridge, inset, outset
218
+ *
219
+ * @var string
220
+ * @since 2.0
221
+ */
222
+ public $link_border_style;
223
+
224
+ /**
225
+ * Border width for links
226
+ * Default: 0
227
+ *
228
+ * @var string
229
+ * @since 2.0
230
+ */
231
+ public $link_border_width;
232
+
233
+ /**
234
+ * Border color for links
235
+ * Default: none
236
+ * Valid values: A hexadecimal color
237
+ *
238
+ * @var string
239
+ * @since 2.0
240
+ */
241
+ public $link_border_color;
242
+
243
+ /**
244
+ * If links should be decorated with underline decoration in their hover state
245
+ * Default: default
246
+ * Valid values: yes, no, default
247
+ *
248
+ * @var string
249
+ * @since 2.0
250
+ */
251
+ public $hover_underline;
252
+
253
+ /**
254
+ * If links should be styled as bold in their hover state
255
+ * Default: default
256
+ * Valid values: yes, no, default
257
+ *
258
+ * @var string
259
+ * @since 2.0
260
+ */
261
+ public $hover_bold;
262
+
263
+ /**
264
+ * If links should be styled as italic in their hover state
265
+ * Default: default
266
+ * Valid values: yes, no, default
267
+ *
268
+ * @var string
269
+ * @since 2.0
270
+ */
271
+ public $hover_italic;
272
+
273
+ /**
274
+ * Background color for links in their hover state
275
+ * Default: transparent
276
+ * Valid values: A hexadecimal color
277
+ *
278
+ * @var string
279
+ * @since 2.0
280
+ */
281
+ public $hover_bg_color;
282
+
283
+ /**
284
+ * Text color for links in their hover state
285
+ * Default: default
286
+ * Valid values: A hexadecimal color
287
+ *
288
+ * @var string
289
+ * @since 2.0
290
+ */
291
+ public $hover_color;
292
+
293
+ /**
294
+ * Border style for links in their hover state
295
+ * Default: none
296
+ * Valid values: none, dotted, dashed, solid, double, groove, ridge, inset, outset
297
+ *
298
+ * @var string
299
+ * @since 2.0
300
+ */
301
+ public $hover_border_style;
302
+
303
+ /**
304
+ * Border width for links in their hover state
305
+ * Default: 0
306
+ *
307
+ * @var string
308
+ * @since 2.0
309
+ */
310
+ public $hover_border_width;
311
+
312
+ /**
313
+ * Border color for links in their hover state
314
+ * Default: none
315
+ * Valid values: A hexadecimal color
316
+ *
317
+ * @var string
318
+ * @since 2.0
319
+ */
320
+ public $hover_border_color;
321
+
322
+ /**
323
+ * CSS margin between tags
324
+ * Default: auto
325
+ *
326
+ * @var string
327
+ * @since 2.0
328
+ */
329
+ public $tag_spacing;
330
+
331
+ /**
332
+ * If debug output should be included
333
+ * Default: false
334
+ *
335
+ * @var bool
336
+ * @since 2.0
337
+ */
338
+ public $debug;
339
+
340
+ /**
341
+ * How many days old a post needs to be to be included in tag size calculation
342
+ * Default: 0
343
+ *
344
+ * @var int
345
+ * @since 2.0
346
+ */
347
+ public $days_old;
348
+
349
+ /**
350
+ * CSS line-height for the tags
351
+ * Default: inherit
352
+ *
353
+ * @var string
354
+ * @since 2.0
355
+ */
356
+ public $line_height;
357
+
358
+ /**
359
+ * Separator between tags
360
+ * Default: (a space character)
361
+ *
362
+ * @var string
363
+ * @since 2.0
364
+ */
365
+ public $separator;
366
+
367
+ /**
368
+ * Prefix before each tag
369
+ * Default: (empty string)
370
+ *
371
+ * @var string
372
+ * @since 2.0
373
+ */
374
+ public $prefix;
375
+
376
+ /**
377
+ * Suffix after each tag
378
+ * Default: (empty string)
379
+ *
380
+ * @var string
381
+ * @since 2.0
382
+ */
383
+ public $suffix;
384
+
385
+ /**
386
+ * If the widget title should be shown
387
+ * Default: true
388
+ *
389
+ * @var bool
390
+ * @since 2.0
391
+ */
392
+ public $show_title_text;
393
+
394
+ /**
395
+ * An array of post type names to to include posts from in tag size calculation
396
+ * Default: [ post ]
397
+ *
398
+ * @var array
399
+ * @since 2.0
400
+ */
401
+ public $post_type;
402
+
403
+ /**
404
+ * A list of term IDs to be included or excluded. Inclusion or exclusion is determined by $tags_list_type
405
+ * Default: [] (an empty array)
406
+ *
407
+ * @var array
408
+ * @since 2.0
409
+ */
410
+ public $tags_list;
411
+
412
+ /**
413
+ * Which color value to start from in color calculation. This is the color that the smallest tag will get.
414
+ * Default: (an empty string)
415
+ *
416
+ * @var string
417
+ * @since 2.0
418
+ */
419
+ public $color_span_to;
420
+
421
+ /**
422
+ * Which color value to end at in color calculation. This is the color that the biggest tag will get.
423
+ * Default: (an empty string)
424
+ *
425
+ * @var string
426
+ * @since 2.0
427
+ */
428
+ public $color_span_from;
429
+
430
+ /**
431
+ * Which authors to include posts from. An empty array will include all authors
432
+ * Default: [] (an empty array)
433
+ *
434
+ * @var array
435
+ * @since 2.0
436
+ */
437
+ public $authors;
438
+
439
+ /**
440
+ * A set of colors to randomly select from when coloring the tags
441
+ * Default: [] (an empty array)
442
+ *
443
+ * @var array
444
+ * @since 2.0
445
+ */
446
+ public $color_set;
447
+
448
+ /**
449
+ * If the current user is authenticated. Will be set internally
450
+ *
451
+ * @internal
452
+ * @var bool
453
+ * @since 2.0
454
+ */
455
+ public $authenticated;
456
+
457
+ /**
458
+ * Text to display before the widget.
459
+ * The default value for this setting will probably be determined by the theme
460
+ * Default: (an empty string)
461
+ *
462
+ * @var string
463
+ * @since 2.0
464
+ */
465
+ public $before_widget;
466
+
467
+ /**
468
+ * Text to display after the widget.
469
+ * The default value for this setting will probably be determined by the theme
470
+ * Default: (an empty string)
471
+ *
472
+ * @var string
473
+ * @since 2.0
474
+ */
475
+ public $after_widget;
476
+
477
+ /**
478
+ * Text to display before the widget title.
479
+ * The default value for this setting will probably be determined by the theme
480
+ * Default: (an empty string)
481
+ *
482
+ * @var string
483
+ * @since 2.0
484
+ */
485
+ public $before_title;
486
+
487
+ /**
488
+ * Text to display after the widget title.
489
+ * The default value for this setting will probably be determined by the theme
490
+ * Default: (an empty string)
491
+ *
492
+ * @var string
493
+ * @since 2.0
494
+ */
495
+ public $after_title;
496
+
497
+ /**
498
+ * Which strategy to use when selecting tags
499
+ * Default: popularity
500
+ *
501
+ * @var string
502
+ * @since 2.2
503
+ */
504
+ public $strategy;
505
+
506
+ /**
507
+ * Config store with default values
508
+ *
509
+ * @static
510
+ * @var array
511
+ * @since 2.0
512
+ */
513
+ static protected $options = array(
514
+ 'title' => 'Tag Cloud',
515
+ 'order' => 'name',
516
+ 'size_from' => '10px',
517
+ 'size_to' => '30px',
518
+ 'max' => 45,
519
+ 'taxonomy' => array('post_tag'),
520
+ 'reverse' => false,
521
+ 'color' => 'none',
522
+ 'letter_spacing' => 'normal',
523
+ 'word_spacing' => 'normal',
524
+ 'text_transform' => 'none',
525
+ 'case_sensitive' => false,
526
+ 'minimum' => 1,
527
+ 'tags_list_type' => 'exclude',
528
+ 'show_title' => true,
529
+ 'show_links' => true,
530
+ 'link_underline' => 'default',
531
+ 'link_bold' => 'default',
532
+ 'link_italic' => 'default',
533
+ 'link_bg_color' => 'transparent',
534
+ 'link_border_style' => 'none',
535
+ 'link_border_width' => '0',
536
+ 'link_border_color' => 'none',
537
+ 'hover_underline' => 'default',
538
+ 'hover_bold' => 'default',
539
+ 'hover_italic' => 'default',
540
+ 'hover_bg_color' => 'transparent',
541
+ 'hover_color' => 'default',
542
+ 'hover_border_style' => 'none',
543
+ 'hover_border_width' => '0',
544
+ 'hover_border_color' => 'none',
545
+ 'tag_spacing' => 'auto',
546
+ 'debug' => false,
547
+ 'days_old' => 0,
548
+ 'line_height' => 'inherit',
549
+ 'separator' => ' ',
550
+ 'prefix' => '',
551
+ 'suffix' => '',
552
+ 'show_title_text' => true,
553
+ 'post_type' => array('post'),
554
+ 'tags_list' => array(),
555
+ 'color_span_to' => '',
556
+ 'color_span_from' => '',
557
+ 'authors' => array(),
558
+ 'color_set' => array(),
559
+ 'before_widget' => '',
560
+ 'after_widget' => '',
561
+ 'before_title' => '',
562
+ 'after_title' => '',
563
+ 'strategy' => 'popularity'
564
+ );
565
+
566
+ /**
567
+ * Which ordering strategies are allowed
568
+ *
569
+ * @var array
570
+ * @since 2.0
571
+ */
572
+ protected $allowed_orders = array('random', 'name', 'slug', 'id', 'color', 'count');
573
+
574
+ /**
575
+ * Which taxonomies are allowed. Will be set dynamically at load
576
+ *
577
+ * @var array
578
+ * @since 2.0
579
+ */
580
+ protected $allowed_taxonomies = array();
581
+
582
+ /**
583
+ * Which post types are allowed. Will be set dynamically at load
584
+ *
585
+ * @var array
586
+ * @since 2.0
587
+ */
588
+ protected $allowed_post_types = array();
589
+
590
+ /**
591
+ * Which coloring strategies are allowed
592
+ *
593
+ * @var array
594
+ * @since 2.0
595
+ */
596
+ protected $allowed_colors = array('none', 'random', 'set', 'span');
597
+
598
+ /**
599
+ * Which CSS text-transform values are allowed
600
+ *
601
+ * @var array
602
+ * @since 2.0
603
+ */
604
+ protected $allowed_text_transforms = array('lowercase', 'uppercase', 'capitalize');
605
+
606
+ /**
607
+ * Which tags_list_type values are allowed
608
+ *
609
+ * @var array
610
+ * @since 2.0
611
+ */
612
+ protected $allowed_tags_list_types = array('exclude', 'include');
613
+
614
+ /**
615
+ * Which values are allowed for optional booleans.
616
+ * These are values which can be true, false or fallback to theme default (where applicable)
617
+ *
618
+ * @var array
619
+ * @since 2.0
620
+ */
621
+ protected $allowed_optional_booleans = array('yes', 'no', 'default');
622
+
623
+ /**
624
+ * Which CSS border-style values are allowed
625
+ *
626
+ * @var array
627
+ * @since 2.0
628
+ */
629
+ protected $allowed_border_styles = array(
630
+ 'none',
631
+ 'dotted',
632
+ 'dashed',
633
+ 'solid',
634
+ 'double',
635
+ 'groove',
636
+ 'ridge',
637
+ 'inset',
638
+ 'outset',
639
+ );
640
+
641
+ /**
642
+ * Which strategies are allowed
643
+ *
644
+ * @var array
645
+ * @since 2.2
646
+ */
647
+ protected $allowed_strategies = array('popularity', 'random');
648
+
649
+ /**
650
+ * Loads a configuration instance array and parses the options
651
+ *
652
+ * @param array $input Array of key => value pairs of settings and values
653
+ * @param Plugin $plugin Reference to the main plugin instance
654
+ *
655
+ * @since 2.0
656
+ */
657
+ public function __construct(array $input, Plugin $plugin)
658
+ {
659
+ $this->allowed_post_types = $plugin->getAllowedPostTypes();
660
+ $this->allowed_taxonomies = $plugin->getAllowedTaxonomies();
661
+ $this->authenticated = $plugin->isAuthenticatedUser();
662
+
663
+ foreach (self::$options as $key => $default) {
664
+ $this->$key = $default;
665
+
666
+ if (isset($input[$key])) {
667
+ $valid = true;
668
+
669
+ switch ($key) {
670
+ case 'strategy':
671
+ $valid = in_array($input[$key], $this->allowed_strategies);
672
+ break;
673
+ case 'order':
674
+ $valid = in_array($input[$key], $this->allowed_orders);
675
+ break;
676
+ case 'text_transform':
677
+ $valid = in_array($input[$key], $this->allowed_text_transforms);
678
+ break;
679
+ case 'tags_list_type':
680
+ $valid = in_array($input[$key], $this->allowed_tags_list_types);
681
+ break;
682
+ // Optional booleans, can be yes, no or default
683
+ case 'link_underline':
684
+ case 'link_bold':
685
+ case 'link_italic':
686
+ case 'hover_underline':
687
+ case 'hover_bold':
688
+ case 'hover_italic':
689
+ $valid = in_array($input[$key], $this->allowed_optional_booleans);
690
+ break;
691
+ case 'link_border_style':
692
+ case 'hover_border_style':
693
+ $valid = in_array($input[$key], $this->allowed_border_styles);
694
+ break;
695
+ case 'color':
696
+ $valid = in_array($input[$key], $this->allowed_colors);
697
+ break;
698
+ // TODO: Allow more flexibility in color setting, like rgb/rgba/hsl/hsla and named colors
699
+ case 'link_bg_color':
700
+ case 'link_border_color':
701
+ case 'hover_bg_color':
702
+ case 'hover_color':
703
+ case 'hover_border_color':
704
+ case 'color_span_to':
705
+ case 'color_span_from':
706
+ $valid = preg_match(UTCW_HEX_COLOR_REGEX, $input[$key]) > 0;
707
+ break;
708
+ case 'color_set':
709
+ if (!is_array($input[$key])) {
710
+ $input[$key] = explode(',', $input[$key]);
711
+ }
712
+
713
+ $valid = $input[$key] && array_filter(
714
+ $input[$key],
715
+ create_function('$item', 'return preg_match( UTCW_HEX_COLOR_REGEX, $item );')
716
+ ) == $input[$key];
717
+ break;
718
+ case 'taxonomy':
719
+ if (!is_array($input[$key])) {
720
+ $input[$key] = explode(',', $input[$key]);
721
+ }
722
+
723
+ // Remove invalid taxonomies
724
+ foreach ($input[$key] as $tax_key => $taxonomy) {
725
+ if (!in_array($taxonomy, $this->allowed_taxonomies)) {
726
+ unset($input[$key][$tax_key]);
727
+ }
728
+ }
729
+
730
+ $valid = !!$input[$key]; // Setting is valid if any of the taxonomies were valid
731
+ break;
732
+ case 'post_type':
733
+ if (!is_array($input[$key])) {
734
+ $input[$key] = explode(',', $input[$key]);
735
+ }
736
+
737
+ $valid = $input[$key] && count(
738
+ array_intersect($this->allowed_post_types, $input[$key])
739
+ ) == count($input[$key]);
740
+ break;
741
+ case 'authors':
742
+ case 'tags_list':
743
+ if (!is_array($input[$key])) {
744
+ $input[$key] = explode(',', $input[$key]);
745
+ }
746
+
747
+ $valid = $this->isArrayNumeric($input[$key]);
748
+ $input[$key] = array_map('intval', $input[$key]);
749
+ break;
750
+ case 'size_from':
751
+ $input['size_from'] = $this->parseMeasurement($input['size_from']);
752
+
753
+ $size_to = isset($input['size_to']) ? $input['size_to'] : self::$options['size_to'];
754
+ $valid = $input['size_from'] !== false && $this->equalUnits(
755
+ $input['size_from'],
756
+ $size_to
757
+ ) && floatval($input['size_from']) <= floatval($size_to);
758
+ break;
759
+ case 'size_to':
760
+ $input['size_to'] = $this->parseMeasurement($input['size_to']);
761
+
762
+ $size_from = isset($input['size_from']) ? $input['size_from'] : self::$options['size_from'];
763
+ $valid = $input['size_to'] !== false && $this->equalUnits(
764
+ $size_from,
765
+ $input['size_to']
766
+ ) && floatval($input['size_to']) >= floatval($size_from);
767
+ break;
768
+ case 'letter_spacing':
769
+ case 'word_spacing':
770
+ case 'tag_spacing':
771
+ case 'line_height':
772
+ case 'link_border_width':
773
+ case 'hover_border_width':
774
+ $input[$key] = $this->parseMeasurement($input[$key]);
775
+ $valid = $input[$key] !== false;
776
+ break;
777
+ }
778
+
779
+ if (!$valid) {
780
+ continue;
781
+ }
782
+
783
+ // Special handling of the color_set config attribute which needs to be expanded to full 6 digit values
784
+ if ($key == 'color_set') {
785
+ foreach ($input[$key] as $cs_key => $color) {
786
+ if (strlen($color) == 4) {
787
+ $red = substr($color, 1, 1);
788
+ $green = substr($color, 2, 1);
789
+ $blue = substr($color, 3, 1);
790
+ $input[$key][$cs_key] = sprintf('#%s%s%s%s%s%s', $red, $red, $green, $green, $blue, $blue);
791
+ }
792
+ }
793
+ $this->$key = $input[$key];
794
+ } elseif ($key == 'minimum') {
795
+ $this->$key = intval($input[$key]);
796
+ } elseif (is_string(self::$options[$key]) && is_string($input[$key]) && strlen($input[$key]) > 0) {
797
+ $this->$key = $input[$key];
798
+ } elseif (is_integer(self::$options[$key]) && $input[$key] > 0) {
799
+ $this->$key = intval($input[$key]);
800
+ } elseif (is_bool(self::$options[$key])) {
801
+ $this->$key = !!$input[$key];
802
+ } elseif (is_array(self::$options[$key])) {
803
+ $this->$key = is_array($input[$key]) ? $input[$key] : explode(
804
+ ',',
805
+ $input[$key]
806
+ );
807
+ }
808
+ }
809
+ }
810
+ }
811
+
812
+ /**
813
+ * Checks if every item in the array is numeric
814
+ *
815
+ * @param array $array
816
+ *
817
+ * @return bool
818
+ * @since 2.0
819
+ */
820
+ private function isArrayNumeric(array $array)
821
+ {
822
+ foreach ($array as $item) {
823
+ if (!is_numeric($item)) {
824
+ return false;
825
+ }
826
+ }
827
+
828
+ return true;
829
+ }
830
+
831
+ /**
832
+ * Parses the input value as measurement
833
+ *
834
+ * @param mixed $input
835
+ *
836
+ * @return bool|string False on failure
837
+ * @since 2.1
838
+ */
839
+ private function parseMeasurement($input)
840
+ {
841
+ if (!preg_match('/^' . UTCW_DECIMAL_REGEX . '(em|px|%)?$/i', $input)) {
842
+ return false;
843
+ }
844
+
845
+ // Convert integer values to pixel values
846
+ if (preg_match('/^' . UTCW_DECIMAL_REGEX . '$/', $input)) {
847
+ return $input . 'px';
848
+ }
849
+
850
+ return $input;
851
+ }
852
+
853
+ /**
854
+ * Checks if the two measurements have the same unit
855
+ *
856
+ * @param string $measurement1
857
+ * @param string $measurement2
858
+ *
859
+ * @return bool
860
+ * @since 2.1
861
+ */
862
+ private function equalUnits($measurement1, $measurement2)
863
+ {
864
+ $unit1 = preg_replace('/' . UTCW_DECIMAL_REGEX . '/', '', $measurement1);
865
+ $unit2 = preg_replace('/' . UTCW_DECIMAL_REGEX . '/', '', $measurement2);
866
+
867
+ return $unit1 === $unit2 || ($unit1 === 'px' && $unit2 === '') || ($unit1 === '' && $unit2 === 'px');
868
+ }
869
+
870
+ /**
871
+ * Returns an array of current configuration
872
+ *
873
+ * @return array
874
+ * @since 2.0
875
+ */
876
+ public function getInstance()
877
+ {
878
+ $instance = array();
879
+
880
+ foreach (array_keys(self::$options) as $key) {
881
+ $instance[$key] = $this->$key;
882
+ }
883
+
884
+ return $instance;
885
+ }
886
+
887
+ /**
888
+ * Returns the default values for all the configuration options
889
+ *
890
+ * @static
891
+ * @return array
892
+ * @since 2.0
893
+ */
894
+ public static function getDefaults()
895
+ {
896
+ return self::$options;
897
+ }
898
+ }
src/Data.php ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage main
13
+ * @since 2.0
14
+ */
15
+
16
+ use Rickard\UTCW\Selection\PopularityStrategy;
17
+ use Rickard\UTCW\Selection\RandomStrategy;
18
+ use Rickard\UTCW\Selection\SelectionStrategy;
19
+ use wpdb;
20
+ use stdClass;
21
+
22
+ /**
23
+ * Class for loading data for the cloud
24
+ *
25
+ * @since 2.0
26
+ * @package utcw
27
+ * @subpackage main
28
+ */
29
+ class Data
30
+ {
31
+
32
+ /**
33
+ * Reference to the current configuration
34
+ *
35
+ * @var Config
36
+ * @since 2.0
37
+ */
38
+ protected $config;
39
+
40
+ /**
41
+ * Reference to WPDB object
42
+ *
43
+ * @var wpdb
44
+ * @since 2.0
45
+ */
46
+ protected $db;
47
+
48
+ /**
49
+ * Reference to main plugin instance
50
+ *
51
+ * @var Plugin
52
+ * @since 2.0
53
+ */
54
+ protected $plugin;
55
+
56
+ /**
57
+ * Reference to the selection strategy used
58
+ *
59
+ * @var SelectionStrategy
60
+ * @since 2.2
61
+ */
62
+ protected $strategy;
63
+
64
+ /**
65
+ * Creates a new instance
66
+ *
67
+ * @param Config $config Current configuration
68
+ * @param Plugin $plugin Main plugin instance
69
+ * @param wpdb $db WordPress DB instance
70
+ *
71
+ * @since 2.0
72
+ */
73
+ public function __construct(Config $config, Plugin $plugin, wpdb $db)
74
+ {
75
+ $this->config = $config;
76
+ $this->db = $db;
77
+ $this->plugin = $plugin;
78
+
79
+ switch ($this->config->strategy) {
80
+ case 'popularity':
81
+ $this->strategy = new PopularityStrategy($this->config, $this->plugin, $this->db);
82
+ break;
83
+ case 'random':
84
+ $this->strategy = new RandomStrategy($this->config, $this->plugin, $this->db);
85
+ break;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Loads terms based on current configuration
91
+ *
92
+ * @return Term[]
93
+ * @since 2.0
94
+ */
95
+ public function getTerms()
96
+ {
97
+ $terms = array();
98
+ $result = $this->strategy->getData();
99
+
100
+ // Calculate sizes
101
+ $min_count = PHP_INT_MAX;
102
+ $max_count = 0;
103
+
104
+ // Get translation handler if a translation plugin is active
105
+ $translationHandler = $this->plugin->getTranslationHandler();
106
+
107
+ foreach ($result as $item) {
108
+ if ($item->count < $min_count) {
109
+ $min_count = $item->count;
110
+ }
111
+
112
+ if ($item->count > $max_count) {
113
+ $max_count = $item->count;
114
+ }
115
+
116
+ if ($translationHandler) {
117
+
118
+ // Let the translation handler determine if the term should be included or not
119
+ $term = $translationHandler->createTerm($item, $this->plugin);
120
+
121
+ if ($term) {
122
+ $terms[] = $term;
123
+ }
124
+ } else {
125
+ $terms[] = new Term($item, $this->plugin);
126
+ }
127
+ }
128
+
129
+ $size_from = floatval($this->config->size_from);
130
+ $size_to = floatval($this->config->size_to);
131
+ $unit = preg_replace('/' . UTCW_DECIMAL_REGEX . '/', '', $this->config->size_from);
132
+
133
+ $font_step = $this->calcStep($min_count, $max_count, $size_from, $size_to);
134
+
135
+ foreach ($terms as $term) {
136
+ $term->size = $this->calcSize($size_from, $term->count, $min_count, $font_step) . $unit;
137
+ }
138
+
139
+ // Set colors
140
+ switch ($this->config->color) {
141
+ case 'random':
142
+ foreach ($terms as $term) {
143
+ $term->color = sprintf(UTCW_HEX_COLOR_FORMAT, rand() % 255, rand() % 255, rand() % 255);
144
+ }
145
+ break;
146
+ case 'set':
147
+ if ($this->config->color_set) {
148
+ foreach ($terms as $term) {
149
+ $term->color = $this->config->color_set[array_rand($this->config->color_set)];
150
+ }
151
+ }
152
+ break;
153
+ case 'span':
154
+ if ($this->config->color_span_from && $this->config->color_span_to) {
155
+ preg_match_all('/[0-9a-f]{2}/i', $this->config->color_span_from, $cf_rgb_matches);
156
+ list($red_from, $green_from, $blue_from) = array_map('hexdec', $cf_rgb_matches[0]);
157
+
158
+ preg_match_all('/[0-9a-f]{2}/i', $this->config->color_span_to, $ct_rgb_matches);
159
+ list($red_to, $green_to, $blue_to) = array_map('hexdec', $ct_rgb_matches[0]);
160
+
161
+ $colors = new stdClass;
162
+ $colors->red_from = $red_from;
163
+ $colors->red_to = $red_to;
164
+ $colors->green_from = $green_from;
165
+ $colors->green_to = $green_to;
166
+ $colors->blue_from = $blue_from;
167
+ $colors->blue_to = $blue_to;
168
+
169
+ foreach ($terms as $term) {
170
+ $term->color = $this->calcColor($min_count, $max_count, $colors, $term->count);
171
+ }
172
+ }
173
+ }
174
+
175
+ // Last order by color if selected, this is the only order which can't be done in the DB
176
+ if ($this->config->order == 'color') {
177
+ // Change the argument order to change the sort order
178
+ $sort_fn_arguments = $this->config->reverse ? '$b,$a' : '$a,$b';
179
+
180
+ // There's no difference in sortin case sensitive or case in-sensitive since
181
+ // the colors are always lower case and internally generated
182
+
183
+ $sort_fn = create_function($sort_fn_arguments, 'return strcmp( $a->color, $b->color );');
184
+
185
+ usort($terms, $sort_fn);
186
+ }
187
+
188
+ return $terms;
189
+ }
190
+
191
+ /**
192
+ * Calculate term color
193
+ *
194
+ * @param int $min_count Min count of all the terms
195
+ * @param int $max_count Max count of all the terms
196
+ * @param stdClass $colors Object with red/green/blue_from/to properties
197
+ * @param int $count Count of current term
198
+ *
199
+ * @return string
200
+ * @since 2.0
201
+ */
202
+ private function calcColor($min_count, $max_count, stdClass $colors, $count)
203
+ {
204
+ $red_step = $this->calcStep($min_count, $max_count, $colors->red_from, $colors->red_to);
205
+ $green_step = $this->calcStep($min_count, $max_count, $colors->green_from, $colors->green_to);
206
+ $blue_step = $this->calcStep($min_count, $max_count, $colors->blue_from, $colors->blue_to);
207
+
208
+ $red = $this->calcSize($colors->red_from, $count, $min_count, $red_step);
209
+ $green = $this->calcSize($colors->green_from, $count, $min_count, $green_step);
210
+ $blue = $this->calcSize($colors->blue_from, $count, $min_count, $blue_step);
211
+
212
+ $color = sprintf(UTCW_HEX_COLOR_FORMAT, $red, $green, $blue);
213
+
214
+ return $color;
215
+ }
216
+
217
+ /**
218
+ * Calculate term size
219
+ *
220
+ * @param int $size_from Configured min size
221
+ * @param int $count Current count
222
+ * @param int $min_count Configured max count
223
+ * @param int $font_step Calculated step
224
+ *
225
+ * @return int
226
+ * @since 2.0
227
+ */
228
+ private function calcSize($size_from, $count, $min_count, $font_step)
229
+ {
230
+ return $size_from + (($count - $min_count) * $font_step);
231
+ }
232
+
233
+ /**
234
+ * Calculate step size
235
+ *
236
+ * @param int $min Minimum count
237
+ * @param int $max Maximum count
238
+ * @param int $from Minimum size
239
+ * @param int $to Maximum size
240
+ *
241
+ * @return int
242
+ * @since 2.0
243
+ */
244
+ private function calcStep($min, $max, $from, $to)
245
+ {
246
+ if ($min === $max) {
247
+ return 0;
248
+ }
249
+
250
+ $spread = $max - $min;
251
+ $font_spread = $to - $from;
252
+ $step = $font_spread / $spread;
253
+
254
+ return $step;
255
+ }
256
+
257
+ /**
258
+ * Cleans up sensitive data before being used in debug output
259
+ */
260
+ public function cleanupForDebug()
261
+ {
262
+ unset($this->db);
263
+ $this->strategy->cleanupForDebug();
264
+ }
265
+ }
src/Database/QueryBuilder.php ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW\Database;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage language
13
+ * @since 2.2
14
+ */
15
+
16
+ use Rickard\UTCW\Plugin;
17
+ use wpdb;
18
+
19
+ /**
20
+ * Class to handle QTranslate multi language support
21
+ *
22
+ * @since 2.2
23
+ * @package utcw
24
+ * @subpackage database
25
+ */
26
+ class QueryBuilder
27
+ {
28
+
29
+ /**
30
+ * Database reference
31
+ *
32
+ * @var wpdb
33
+ * @since 2.2
34
+ */
35
+ protected $db;
36
+
37
+ /**
38
+ * Creates a new instance of the QueryBuilder
39
+ *
40
+ * @param Plugin $plugin
41
+ * @param wpdb $db
42
+ *
43
+ * @since 2.2
44
+ */
45
+ public function __construct(Plugin $plugin, wpdb $db)
46
+ {
47
+ $this->db = $db;
48
+ $this->plugin = $plugin;
49
+ $this->query = $this->getBaseQuery();
50
+ $this->parameters = array();
51
+ }
52
+
53
+ /**
54
+ * Returns the resulting query
55
+ *
56
+ * @return string
57
+ * @since 2.2
58
+ */
59
+ public function getQuery()
60
+ {
61
+ return join(' ', $this->query);
62
+ }
63
+
64
+ /**
65
+ * Returns the parameters for the resulting query
66
+ *
67
+ * @return array
68
+ * @since 2.2
69
+ */
70
+ public function getParameters()
71
+ {
72
+ return $this->parameters;
73
+ }
74
+
75
+ /**
76
+ * Add a statement to the query
77
+ *
78
+ * @param string $statement
79
+ *
80
+ * @since 2.2
81
+ */
82
+ public function addStatement($statement)
83
+ {
84
+ $this->query[] = $statement;
85
+ }
86
+
87
+ /**
88
+ * Returns the base query with joins
89
+ *
90
+ * @return array
91
+ * @since 2.2
92
+ */
93
+ public function getBaseQuery()
94
+ {
95
+ $query = array();
96
+
97
+ $query[] = 'SELECT t.term_id, t.name, t.slug, COUNT(p.ID) AS `count`, tt.taxonomy';
98
+ $query[] = 'FROM `' . $this->db->terms . '` AS t';
99
+ $query[] = 'JOIN `' . $this->db->term_taxonomy . '` AS tt ON t.term_id = tt.term_id';
100
+ $query[] = 'LEFT JOIN `' . $this->db->term_relationships . '` AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id';
101
+ $query[] = 'LEFT JOIN `' . $this->db->posts . '` AS p ON tr.object_id = p.ID';
102
+
103
+ return $query;
104
+ }
105
+
106
+ /**
107
+ * Add author constraint
108
+ *
109
+ * @param array $authors
110
+ *
111
+ * @since 2.2
112
+ */
113
+ public function addAuthorConstraint(array $authors)
114
+ {
115
+ if ($authors) {
116
+ $author_parameters = array();
117
+
118
+ foreach ($authors as $author) {
119
+ $author_parameters[] = '%d';
120
+ $this->parameters[] = $author;
121
+ }
122
+
123
+ $this->query[] = 'AND p.post_author IN (' . join(',', $author_parameters) . ')';
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Add post type constraint
129
+ *
130
+ * @param array $post_types
131
+ *
132
+ * @since 2.2
133
+ */
134
+ public function addPostTypeConstraint(array $post_types)
135
+ {
136
+ $post_type_parameters = array();
137
+
138
+ foreach ($post_types as $post_type) {
139
+ $post_type_parameters[] = '%s';
140
+ $this->parameters[] = $post_type;
141
+ }
142
+
143
+ $this->query[] = 'AND p.post_type IN (' . join(',', $post_type_parameters) . ')';
144
+ }
145
+
146
+ /**
147
+ * Add post status constraint
148
+ *
149
+ * @param bool $authenticated
150
+ *
151
+ * @since 2.2
152
+ */
153
+ public function addPostStatusConstraint($authenticated)
154
+ {
155
+ // Authenticated users are allowed to view tags for private posts
156
+ if ($authenticated) {
157
+ $this->query[] = "AND p.post_status IN ('publish','private')";
158
+ } else {
159
+ $this->query[] = "AND p.post_status = 'publish'";
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Add days old constraint
165
+ *
166
+ * @param int $days_old
167
+ *
168
+ * @since 2.2
169
+ */
170
+ public function addDaysOldConstraint($days_old)
171
+ {
172
+ if ($days_old) {
173
+ $this->query[] = 'AND p.post_date > %s';
174
+ $this->parameters[] = date('Y-m-d', strtotime('-' . $days_old . ' days'));
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Add taxonomies constraint
180
+ *
181
+ * @param array $taxonomies
182
+ *
183
+ * @since 2.2
184
+ */
185
+ public function addTaxonomyConstraint(array $taxonomies)
186
+ {
187
+ $taxonomy_parameters = array();
188
+
189
+ foreach ($taxonomies as $taxonomy) {
190
+ $taxonomy_parameters[] = '%s';
191
+ $this->parameters[] = $taxonomy;
192
+ }
193
+
194
+ $this->query[] = 'WHERE tt.taxonomy IN (' . join(',', $taxonomy_parameters) . ')';
195
+ }
196
+
197
+ /**
198
+ * Add include or exclude constraint
199
+ *
200
+ * @param string $type
201
+ * @param array $list
202
+ * @param array $taxonomy
203
+ *
204
+ * @since 2.2
205
+ */
206
+ public function addTagsListConstraint($type, array $list, array $taxonomy)
207
+ {
208
+ if ($list) {
209
+ $tags_list_parameters = array();
210
+
211
+ foreach ($list as $tag_id) {
212
+ if ($this->plugin->checkTermTaxonomy($tag_id, $taxonomy)) {
213
+ $tags_list_parameters[] = '%d';
214
+ $this->parameters[] = $tag_id;
215
+ }
216
+ }
217
+
218
+ if ($tags_list_parameters) {
219
+ $tags_list_operator = $type == 'include' ? 'IN' : 'NOT IN';
220
+ $this->query[] = 'AND t.term_id ' . $tags_list_operator . ' (' . join(
221
+ ',',
222
+ $tags_list_parameters
223
+ ) . ')';
224
+ }
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Add grouping statement
230
+ *
231
+ * @since 2.2
232
+ */
233
+ public function addGrouping()
234
+ {
235
+ $this->query[] = 'GROUP BY tr.term_taxonomy_id';
236
+ }
237
+
238
+ /**
239
+ * Add minimum constraint
240
+ *
241
+ * @param int $minimum
242
+ *
243
+ * @since 2.2
244
+ */
245
+ public function addMinimum($minimum)
246
+ {
247
+ if ($minimum) {
248
+ $this->query[] = 'HAVING count >= %d';
249
+ $this->parameters[] = $minimum;
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Add max constraint
255
+ *
256
+ * @param int $max
257
+ *
258
+ * @since 2.2
259
+ */
260
+ public function addMaxConstraint($max)
261
+ {
262
+ $this->query[] = 'LIMIT %d';
263
+ $this->parameters[] = $max;
264
+ }
265
+
266
+ /**
267
+ * Add sorting the result
268
+ *
269
+ * @param string $order
270
+ * @param bool $reverse
271
+ * @param bool $case_sensitive
272
+ *
273
+ * @since 2.2
274
+ */
275
+ public function addSort($order, $reverse, $case_sensitive)
276
+ {
277
+ // If the result should be ordered in another way, try to create a sub-query to sort the result
278
+ // directly in the database query
279
+ $subquery_required = true;
280
+
281
+ // No subquery is needed if the order should be by count desc (it's already sorted that way)
282
+ if ($reverse && $order == 'count') {
283
+ $subquery_required = false;
284
+ }
285
+
286
+ // No subquery is needed if the order should be by color since the sorting is done in PHP afterwards
287
+ if ($order == 'color') {
288
+ $subquery_required = false;
289
+ }
290
+
291
+ if ($subquery_required) {
292
+ array_unshift($this->query, 'SELECT * FROM (');
293
+ $this->query[] = ') AS subQuery';
294
+
295
+ $way = $reverse ? 'DESC' : 'ASC';
296
+ $binary = $case_sensitive ? 'BINARY ' : '';
297
+
298
+ switch ($order) {
299
+ case 'random':
300
+ $this->query[] = 'ORDER BY RAND() ' . $way;
301
+ break;
302
+ case 'name':
303
+ $this->query[] = 'ORDER BY ' . $binary . 'name ' . $way;
304
+ break;
305
+ case 'slug':
306
+ $this->query[] = 'ORDER BY ' . $binary . 'slug ' . $way;
307
+ break;
308
+ case 'id':
309
+ $this->query[] = 'ORDER BY term_id ' . $way;
310
+ break;
311
+ case 'count':
312
+ $this->query[] = 'ORDER BY count ' . $way;
313
+ break;
314
+ }
315
+ }
316
+ }
317
+ }
src/Language/QTranslateHandler.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW\Language;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage language
13
+ * @since 2.2
14
+ */
15
+
16
+ use Rickard\UTCW\Plugin;
17
+ use Rickard\UTCW\Term;
18
+ use stdClass;
19
+
20
+ /**
21
+ * Class to handle QTranslate multi language support
22
+ *
23
+ * @since 2.2
24
+ * @package utcw
25
+ * @subpackage language
26
+ */
27
+ class QTranslateHandler extends TranslationHandler
28
+ {
29
+ /**
30
+ * An array of term names mapped to translated names
31
+ *
32
+ * @var array
33
+ * @since 2.2
34
+ */
35
+ protected $nameMap;
36
+
37
+ /**
38
+ * @param array $nameMap An array of term names mapped to translated names
39
+ *
40
+ * @since 2.2
41
+ */
42
+ public function __construct(array $nameMap)
43
+ {
44
+ $this->nameMap = $nameMap;
45
+ }
46
+
47
+ /**
48
+ * Returns true if QTranslate is installed and active
49
+ *
50
+ * @return bool
51
+ * @since 2.2
52
+ */
53
+ public function isEnabled()
54
+ {
55
+ return defined('QT_SUPPORTED_WP_VERSION');
56
+ }
57
+
58
+ /**
59
+ * Returns the current QTranslate language
60
+ *
61
+ * @return string|bool
62
+ * @since 2.2
63
+ */
64
+ public function getLanguage()
65
+ {
66
+ return function_exists('qtrans_getLanguage') ? qtrans_getLanguage() : false;
67
+ }
68
+
69
+ /**
70
+ * {@inheritdoc}
71
+ *
72
+ * @param stdClass $input
73
+ * @param Plugin $plugin
74
+ *
75
+ * @return null|Term
76
+ * @since 2.2
77
+ */
78
+ public function createTerm(stdClass $input, Plugin $plugin)
79
+ {
80
+ $input->name = $this->getTermName($input->name);
81
+
82
+ return new Term($input, $plugin);
83
+ }
84
+
85
+ /**
86
+ * Returns the QTranslate translated name for the given term name.
87
+ *
88
+ * @param string $term
89
+ *
90
+ * @return string
91
+ * @since 2.2
92
+ */
93
+ public function getTermName($term)
94
+ {
95
+ $language = $this->getLanguage();
96
+
97
+ if (!$language) {
98
+ return $term;
99
+ }
100
+
101
+ $language = strtolower($language);
102
+
103
+ if (!isset($this->nameMap[$term][$language])) {
104
+ return $term;
105
+ }
106
+
107
+ return $this->nameMap[$term][$language];
108
+ }
109
+ }
src/Language/TranslationHandler.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW\Language;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage language
13
+ * @since 2.2
14
+ */
15
+
16
+ use Rickard\UTCW\Plugin;
17
+ use Rickard\UTCW\Term;
18
+ use stdClass;
19
+
20
+ /**
21
+ * Abstract class to handle multi language support
22
+ *
23
+ * @since 2.2
24
+ * @package utcw
25
+ * @subpackage language
26
+ */
27
+ abstract class TranslationHandler
28
+ {
29
+ /**
30
+ * Returns true if this multi-language plugin is enabled
31
+ *
32
+ * @return bool
33
+ * @since 2.2
34
+ */
35
+ abstract public function isEnabled();
36
+
37
+ /**
38
+ * Returns a new Term or null depending on if the term should be included with the current language settings.
39
+ * The returned Term will have its name translated into the current language
40
+ *
41
+ * @param stdClass $input
42
+ * @param Plugin $plugin
43
+ *
44
+ * @return null|Term
45
+ * @since 2.2
46
+ */
47
+ abstract public function createTerm(stdClass $input, Plugin $plugin);
48
+ }
src/Language/WPMLHandler.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW\Language;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage language
13
+ * @since 2.2
14
+ */
15
+
16
+ use Rickard\UTCW\Plugin;
17
+ use Rickard\UTCW\Term;
18
+ use stdClass;
19
+
20
+ /**
21
+ * Class to handle WPML multi-language support
22
+ *
23
+ * @since 2.2
24
+ * @package utcw
25
+ * @subpackage language
26
+ */
27
+ class WPMLHandler extends TranslationHandler
28
+ {
29
+ /**
30
+ * Returns true if WPML is installed and active
31
+ *
32
+ * @return bool
33
+ * @since 2.2
34
+ */
35
+ public function isEnabled()
36
+ {
37
+ return defined('ICL_LANGUAGE_CODE');
38
+ }
39
+
40
+ /**
41
+ * Returns the current WPML language
42
+ *
43
+ * @return bool|string
44
+ * @since 2.2
45
+ */
46
+ public function getLanguage()
47
+ {
48
+ return defined('ICL_LANGUAGE_CODE') ? constant('ICL_LANGUAGE_CODE') : false;
49
+ }
50
+
51
+ /**
52
+ * Returns the default language for WPML
53
+ *
54
+ * @return string
55
+ * @since 2.2
56
+ */
57
+ public function getDefaultLanguage()
58
+ {
59
+ /** @var SitePress */
60
+ global $sitepress;
61
+ return $sitepress->get_default_language();
62
+ }
63
+
64
+ /**
65
+ * Returns the WPML translated name for the given term name
66
+ *
67
+ * @param string $term
68
+ *
69
+ * @return string
70
+ * @since 2.2
71
+ */
72
+ public function getTermName($term)
73
+ {
74
+ /** @var SitePress */
75
+ global $sitepress;
76
+
77
+ $translated = $sitepress->the_category_name_filter($term);
78
+
79
+ if (!$translated) {
80
+ return $term;
81
+ }
82
+
83
+ return $translated;
84
+ }
85
+
86
+ /**
87
+ * Returns true if the given term input is determined to be in the current language
88
+ *
89
+ * @param stdClass $input
90
+ *
91
+ * @return bool
92
+ * @since 2.2
93
+ */
94
+ public function isInCurrentLanguage(stdClass $input)
95
+ {
96
+ $language = $this->getLanguage();
97
+ $defaultLanguage = $this->getDefaultLanguage();
98
+
99
+ if ($language === $defaultLanguage) {
100
+ return strpos($input->name, '@') === false; // Terms in the default language doesn't have a @-notation
101
+ }
102
+
103
+ // Translated terms will have @{lang} at the end
104
+ return strpos($input->name, '@' . $language) !== false;
105
+ }
106
+
107
+ /**
108
+ * {@inheritdoc}
109
+ *
110
+ * @param stdClass $input
111
+ * @param Plugin $plugin
112
+ *
113
+ * @return null|Term
114
+ * @since 2.2
115
+ */
116
+ public function createTerm(stdClass $input, Plugin $plugin)
117
+ {
118
+ if ($this->isInCurrentLanguage($input)) {
119
+
120
+ $input->name = $this->getTermName($input->name);
121
+
122
+ return new Term($input, $plugin);
123
+ }
124
+
125
+ return null;
126
+ }
127
+ }
src/Plugin.php ADDED
@@ -0,0 +1,398 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW;
4
+
5
+ /**
6
+ * Class for general plugin integration with WordPress
7
+ *
8
+ * @since 2.0
9
+ * @package utcw
10
+ * @subpackage main
11
+ */
12
+ use Rickard\UTCW\Language\QTranslateHandler;
13
+ use Rickard\UTCW\Language\TranslationHandler;
14
+ use Rickard\UTCW\Language\WPMLHandler;
15
+
16
+ /**
17
+ * Ultimate Tag Cloud Widget
18
+ *
19
+ * @author Rickard Andersson <rickard@0x539.se>
20
+ * @version 2.2
21
+ * @license GPLv2
22
+ * @package utcw
23
+ * @subpackage main
24
+ * @since 2.0
25
+ */
26
+ class Plugin
27
+ {
28
+
29
+ /**
30
+ * An array of which taxonomies are available
31
+ *
32
+ * @var array
33
+ * @since 2.0
34
+ */
35
+ protected $allowed_taxonomies = array();
36
+
37
+ /**
38
+ * An array of which post types are available
39
+ *
40
+ * @var array
41
+ * @since 2.0
42
+ */
43
+ protected $allowed_post_types = array();
44
+
45
+ /**
46
+ * Singleton instance
47
+ *
48
+ * @var Plugin
49
+ * @since 2.0
50
+ */
51
+ private static $instance;
52
+
53
+ /**
54
+ * Initializes the WordPress hooks needed
55
+ *
56
+ * @todo Add tests that these hooks are set
57
+ * @since 2.0
58
+ */
59
+ private function __construct()
60
+ {
61
+ add_action('admin_head-widgets.php', array($this, 'initAdminAssets'));
62
+ add_action('wpLoaded', array($this, 'wpLoaded'));
63
+ add_action('widgets_init', create_function('', 'return register_widget("Rickard\UTCW\Widget");'));
64
+ add_shortcode('utcw', array($this, 'shortcode'));
65
+ }
66
+
67
+ /**
68
+ * Returns an instance of the plugin
69
+ *
70
+ * @static
71
+ * @return Plugin
72
+ * @since 2.0
73
+ */
74
+ public static function getInstance()
75
+ {
76
+ if (!self::$instance) {
77
+ self::$instance = new self;
78
+ }
79
+
80
+ return self::$instance;
81
+ }
82
+
83
+ /**
84
+ * Action handler for 'wpLoaded' hook
85
+ * Loads taxonomies and post types
86
+ *
87
+ * @since 2.0
88
+ */
89
+ public function wpLoaded()
90
+ {
91
+ $this->allowed_taxonomies = get_taxonomies();
92
+ $this->allowed_post_types = get_post_types(array('public' => true));
93
+ }
94
+
95
+ /**
96
+ * Shortcode handler for 'utcw' hook
97
+ *
98
+ * @param array $args
99
+ *
100
+ * @return string
101
+ * @since 2.0
102
+ */
103
+ public function shortcode(array $args)
104
+ {
105
+ global $wpdb;
106
+
107
+ if (isset($args['load_config'])) {
108
+ $loaded = $this->loadConfiguration($args['load_config']);
109
+
110
+ if (is_array($loaded)) {
111
+ $args = $loaded;
112
+ }
113
+ }
114
+
115
+ $config = new Config($args, $this);
116
+ $data = new Data($config, $this, $wpdb);
117
+ $render = new Render($config, $data, $this);
118
+
119
+ return $render->getCloud();
120
+ }
121
+
122
+ /**
123
+ * Action handler for 'admin_head-widgets.php' hook
124
+ * Loads assets needed by the administration interface
125
+ *
126
+ * @since 2.0
127
+ */
128
+ public function initAdminAssets()
129
+ {
130
+ wp_enqueue_style('utcw-admin', plugins_url('ultimate-tag-cloud-widget/css/style.css'), array(), UTCW_VERSION);
131
+
132
+ // In development mode, add the libraries and main file individually
133
+ if (UTCW_DEV) {
134
+ wp_enqueue_script(
135
+ 'utcw-lib-jsuri',
136
+ plugins_url('ultimate-tag-cloud-widget/js/lib/jsuri-1.1.1.min.js'),
137
+ array(),
138
+ UTCW_VERSION,
139
+ true
140
+ );
141
+ wp_enqueue_script(
142
+ 'utcw-lib-tooltip',
143
+ plugins_url('ultimate-tag-cloud-widget/js/lib/tooltip.min.js'),
144
+ array('jquery'),
145
+ UTCW_VERSION,
146
+ true
147
+ );
148
+ wp_enqueue_script(
149
+ 'utcw',
150
+ plugins_url('ultimate-tag-cloud-widget/js/utcw.js'),
151
+ array('utcw-lib-jsuri', 'utcw-lib-tooltip', 'jquery'),
152
+ UTCW_VERSION,
153
+ true
154
+ );
155
+ } else {
156
+ wp_enqueue_script(
157
+ 'utcw',
158
+ plugins_url('ultimate-tag-cloud-widget/js/utcw.min.js'),
159
+ array('jquery'),
160
+ UTCW_VERSION,
161
+ true
162
+ );
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Returns an array with the names of allowed taxonomies
168
+ *
169
+ * @return array
170
+ * @since 2.0
171
+ */
172
+ public function getAllowedTaxonomies()
173
+ {
174
+ return $this->allowed_taxonomies;
175
+ }
176
+
177
+ /**
178
+ * Returns allowed taxonomies as objects
179
+ *
180
+ * @return array
181
+ * @since 2.0
182
+ */
183
+ public function getAllowedTaxonomiesObjects()
184
+ {
185
+ return get_taxonomies(array(), 'objects');
186
+ }
187
+
188
+ /**
189
+ * Returns an array with taxonomy as key and an array of term objects for each taxonomy. Like:
190
+ *
191
+ * @return array
192
+ * @since 2.0
193
+ */
194
+ public function getTerms()
195
+ {
196
+ $terms = array();
197
+
198
+ foreach ($this->getAllowedTaxonomies() as $taxonomy) {
199
+ $terms[$taxonomy] = get_terms($taxonomy);
200
+ }
201
+
202
+ return $terms;
203
+ }
204
+
205
+ /**
206
+ * Returns an array with the names of allowed post types
207
+ *
208
+ * @return array
209
+ * @since 2.0
210
+ */
211
+ public function getAllowedPostTypes()
212
+ {
213
+ return $this->allowed_post_types;
214
+ }
215
+
216
+ /**
217
+ * Returns the users on this blog
218
+ *
219
+ * @return array
220
+ * @since 2.0
221
+ */
222
+ public function getUsers()
223
+ {
224
+ global $wp_version;
225
+
226
+ if ((float)$wp_version < 3.1) {
227
+ return get_users_of_blog();
228
+ } else {
229
+ return get_users();
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Removes a previously saved configuration
235
+ *
236
+ * @param string $name
237
+ *
238
+ * @return bool
239
+ * @since 2.1
240
+ */
241
+ public function removeConfiguration($name)
242
+ {
243
+ $configs = $this->getConfigurations();
244
+
245
+ if (isset($configs[$name])) {
246
+ unset($configs[$name]);
247
+ return $this->setConfigurations($configs);
248
+ }
249
+
250
+ return false;
251
+ }
252
+
253
+ /**
254
+ * Saves the configuration
255
+ *
256
+ * @param string $name Name of configuration
257
+ * @param array $config Exported configuration from Config
258
+ *
259
+ * @return bool
260
+ * @since 2.0
261
+ */
262
+ public function saveConfiguration($name, array $config)
263
+ {
264
+ $configs = $this->getConfigurations();
265
+ $configs[$name] = $config;
266
+
267
+ return $this->setConfigurations($configs);
268
+ }
269
+
270
+ /**
271
+ * Loads saved configuration
272
+ *
273
+ * @param string $name Name of configuration
274
+ *
275
+ * @return array|bool Returns an instance array on success and boolean false on failure
276
+ * @since 2.0
277
+ */
278
+ public function loadConfiguration($name)
279
+ {
280
+ $configs = $this->getConfigurations();
281
+
282
+ if (isset($configs[$name])) {
283
+ return $configs[$name];
284
+ }
285
+
286
+ return false;
287
+ }
288
+
289
+ /**
290
+ * Get saved configurations
291
+ *
292
+ * @return array
293
+ * @since 2.0
294
+ */
295
+ public function getConfigurations()
296
+ {
297
+ return get_option('utcw_saved_configs', array());
298
+ }
299
+
300
+ /**
301
+ * Set saved configurations
302
+ *
303
+ * @param array $configs
304
+ *
305
+ * @return bool
306
+ * @since 2.1
307
+ */
308
+ protected function setConfigurations($configs)
309
+ {
310
+ return update_option('utcw_saved_configs', $configs);
311
+ }
312
+
313
+ /**
314
+ * Returns boolean true if the current page request is for an authenticated user
315
+ *
316
+ * @return bool
317
+ * @since 2.0
318
+ */
319
+ public function isAuthenticatedUser()
320
+ {
321
+ return is_user_logged_in();
322
+ }
323
+
324
+ /**
325
+ * Returns an absolute URI to the archive page for the term
326
+ *
327
+ * @param int $term_id Term ID
328
+ * @param string $taxonomy Taxonomy name
329
+ *
330
+ * @return string Returns URI on success and empty string on failure
331
+ * @since 2.0
332
+ */
333
+ public function getTermLink($term_id, $taxonomy)
334
+ {
335
+ $link = get_term_link($term_id, $taxonomy);
336
+
337
+ return !is_wp_error($link) ? $link : '';
338
+ }
339
+
340
+ /**
341
+ * Check if the term exist for any of the taxonomies
342
+ *
343
+ * @param int $term_id Term ID
344
+ * @param array $taxonomy Array of taxonomy names
345
+ *
346
+ * @return bool
347
+ * @since 2.0
348
+ */
349
+ public function checkTermTaxonomy($term_id, array $taxonomy)
350
+ {
351
+
352
+ foreach ($taxonomy as $tax) {
353
+ if (get_term($term_id, $tax)) {
354
+ return true;
355
+ }
356
+ }
357
+
358
+ return false;
359
+ }
360
+
361
+ /**
362
+ * Apply filters
363
+ *
364
+ * @param string $tag
365
+ * @param mixed $value
366
+ *
367
+ * @return mixed|void
368
+ * @since 2.0
369
+ */
370
+ public function applyFilters($tag, $value)
371
+ {
372
+ return apply_filters($tag, $value);
373
+ }
374
+
375
+ /**
376
+ * Returns a new instance of the QTranslate Handler class
377
+ *
378
+ * @return null|TranslationHandler
379
+ */
380
+ public function getTranslationHandler()
381
+ {
382
+ $names = get_option('qtranslate_term_name');
383
+ $names = $names ? $names : array();
384
+ $qTranslate = new QTranslateHandler($names);
385
+
386
+ if ($qTranslate->isEnabled()) {
387
+ return $qTranslate;
388
+ }
389
+
390
+ $WPML = new WPMLHandler();
391
+
392
+ if ($WPML->isEnabled()) {
393
+ return $WPML;
394
+ }
395
+
396
+ return null;
397
+ }
398
+ }
src/Render.php ADDED
@@ -0,0 +1,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage main
13
+ * @since 2.0
14
+ */
15
+
16
+ /**
17
+ * Class for rendering the cloud
18
+ *
19
+ * @since 2.0
20
+ * @package utcw
21
+ * @subpackage main
22
+ */
23
+ class Render
24
+ {
25
+
26
+ /**
27
+ * Reference to the Data class which contains the data to be rendered
28
+ *
29
+ * @var Data
30
+ * @since 2.0
31
+ */
32
+ private $data;
33
+
34
+ /**
35
+ * Reference to the current configuration
36
+ *
37
+ * @var Config
38
+ * @since 2.0
39
+ */
40
+ private $config;
41
+
42
+ /**
43
+ * Reference to the main plugin instance
44
+ *
45
+ * @var Plugin
46
+ * @since 2.0
47
+ */
48
+ private $plugin;
49
+
50
+ /**
51
+ * Unique ID for this widget configuration
52
+ *
53
+ * @var int
54
+ * @since 2.0
55
+ */
56
+ private $id;
57
+
58
+ /**
59
+ * CSS styles for this widget instance
60
+ *
61
+ * @var string
62
+ * @since 2.0
63
+ */
64
+ private $css = '';
65
+
66
+ /**
67
+ * Creates a new instance of the renderer
68
+ *
69
+ * @param Config $config Configuration
70
+ * @param Data $data Term data
71
+ * @param Plugin $plugin Main plugin instance
72
+ *
73
+ * @since 2.0
74
+ */
75
+ public function __construct(Config $config, Data $data, Plugin $plugin)
76
+ {
77
+ $this->data = $data;
78
+ $this->config = $config;
79
+ $this->plugin = $plugin;
80
+ $this->id = base_convert(crc32(serialize($config)), 10, 27);
81
+
82
+ $this->buildCSS();
83
+ }
84
+
85
+ /**
86
+ * Renders the cloud as output
87
+ *
88
+ * @since 2.0
89
+ */
90
+ public function render()
91
+ {
92
+ echo $this->getCloud();
93
+ }
94
+
95
+ /**
96
+ * Returns the cloud as a string
97
+ *
98
+ * @return string
99
+ * @since 2.0
100
+ */
101
+ public function getCloud()
102
+ {
103
+ $markup = array();
104
+
105
+ if ($this->css) {
106
+ $markup[] = $this->css;
107
+ }
108
+
109
+ if ($this->config->before_widget) {
110
+ $markup[] = $this->config->before_widget;
111
+ }
112
+
113
+ if ($this->config->show_title_text) {
114
+ if ($this->config->before_title) {
115
+ $markup[] = $this->config->before_title;
116
+ }
117
+
118
+ $markup[] = $this->plugin->applyFilters('widget_title', $this->config->title);
119
+
120
+ if ($this->config->after_title) {
121
+ $markup[] = $this->config->after_title;
122
+ }
123
+ }
124
+
125
+ $markup[] = '<div class="widget_tag_cloud utcw-' . $this->id . '">';
126
+
127
+ $terms = array();
128
+
129
+ foreach ($this->data->getTerms() as $term) {
130
+ $color = $term->color ? ';color:' . $term->color : '';
131
+ $title = $this->config->show_title ? sprintf(
132
+ ' title="' . _n('%s topic', '%s topics', $term->count) . '"',
133
+ $term->count
134
+ ) : '';
135
+ $tag = $this->config->show_links ? 'a' : 'span';
136
+
137
+ $terms[] = sprintf(
138
+ '%s<%s class="tag-link-%s" href="%s" style="font-size:%s%s"%s>%s</%s>%s',
139
+ $this->config->prefix,
140
+ $tag,
141
+ $term->term_id,
142
+ $term->link,
143
+ $term->size,
144
+ $color,
145
+ $title,
146
+ $term->name,
147
+ $tag,
148
+ $this->config->suffix
149
+ );
150
+ }
151
+
152
+ $markup[] = join($this->config->separator, $terms);
153
+
154
+ $markup[] = '</div>';
155
+
156
+ if ($this->config->debug) {
157
+ $debug_object = clone $this->data;
158
+ $debug_object->cleanupForDebug();
159
+ $markup[] = sprintf("<!-- Ultimate Tag Cloud Debug information:\n%s -->", print_r($debug_object, true));
160
+ }
161
+
162
+ if ($this->config->after_widget) {
163
+ $markup[] = $this->config->after_widget;
164
+ }
165
+
166
+ return join('', $markup);
167
+ }
168
+
169
+ /**
170
+ * Builds the CSS needed to properly style the cloud
171
+ *
172
+ * @since 2.0
173
+ */
174
+ private function buildCSS()
175
+ {
176
+ $main_styles = array('word-wrap:break-word');
177
+
178
+ if (!$this->hasDefaultValue('text_transform')) {
179
+ $main_styles[] = sprintf('text-transform:%s', $this->config->text_transform);
180
+ }
181
+
182
+ if (!$this->hasDefaultValue('letter_spacing')) {
183
+ $main_styles[] = sprintf('letter-spacing:%s', $this->config->letter_spacing);
184
+ }
185
+
186
+ if (!$this->hasDefaultValue('word_spacing')) {
187
+ $main_styles[] = sprintf('word-spacing:%s', $this->config->word_spacing);
188
+ }
189
+
190
+ $link_styles = array();
191
+
192
+ if (!$this->hasDefaultValue('link_underline')) {
193
+ $link_styles[] = sprintf(
194
+ 'text-decoration:%s',
195
+ $this->config->link_underline === 'yes' ? 'underline' : 'none'
196
+ );
197
+ }
198
+
199
+ if (!$this->hasDefaultValue('link_bold')) {
200
+ $link_styles[] = sprintf('font-weight:%s', $this->config->link_bold === 'yes' ? 'bold' : 'normal');
201
+ }
202
+
203
+ if (!$this->hasDefaultValue('link_italic')) {
204
+ $link_styles[] = sprintf('font-style:%s', $this->config->link_italic === 'yes' ? 'italic' : 'normal');
205
+ }
206
+
207
+ if (!$this->hasDefaultValue('link_bg_color')) {
208
+ $link_styles[] = sprintf('background-color:%s', $this->config->link_bg_color);
209
+ }
210
+
211
+ if (!$this->hasDefaultValue('link_border_style') && !$this->hasDefaultValue(
212
+ 'link_border_color'
213
+ ) && !$this->hasDefaultValue('link_border_width')
214
+ ) {
215
+ $link_styles[] = sprintf(
216
+ 'border:%s %s %s',
217
+ $this->config->link_border_style,
218
+ $this->config->link_border_width,
219
+ $this->config->link_border_color
220
+ );
221
+ } else {
222
+ if (!$this->hasDefaultValue('link_border_style')) {
223
+ $link_styles[] = sprintf('border-style:%s', $this->config->link_border_style);
224
+ }
225
+
226
+ if (!$this->hasDefaultValue('link_border_color')) {
227
+ $link_styles[] = sprintf('border-color:%s', $this->config->link_border_color);
228
+ }
229
+
230
+ if (!$this->hasDefaultValue('link_border_width')) {
231
+ $link_styles[] = sprintf('border-width:%s', $this->config->link_border_width);
232
+ }
233
+ }
234
+
235
+ if (!$this->hasDefaultValue('tag_spacing')) {
236
+ $link_styles[] = sprintf('margin-right:%s', $this->config->tag_spacing);
237
+ }
238
+
239
+ if (!$this->hasDefaultValue('line_height')) {
240
+ $link_styles[] = sprintf('line-height:%s', $this->config->line_height);
241
+ }
242
+
243
+ $hover_styles = array();
244
+
245
+ if (!$this->hasDefaultValue('hover_underline')) {
246
+ $hover_styles[] = sprintf(
247
+ 'text-decoration:%s',
248
+ $this->config->hover_underline === 'yes' ? 'underline' : 'none'
249
+ );
250
+ }
251
+
252
+ if (!$this->hasDefaultValue('hover_bold')) {
253
+ $hover_styles[] = sprintf('font-weight:%s', $this->config->hover_bold === 'yes' ? 'bold' : 'normal');
254
+ }
255
+
256
+ if (!$this->hasDefaultValue('hover_italic')) {
257
+ $hover_styles[] = sprintf('font-style:%s', $this->config->hover_italic === 'yes' ? 'italic' : 'normal');
258
+ }
259
+
260
+ if (!$this->hasDefaultValue('hover_bg_color')) {
261
+ $hover_styles[] = sprintf('background-color:%s', $this->config->hover_bg_color);
262
+ }
263
+
264
+
265
+ if (!$this->hasDefaultValue('hover_border_style') && !$this->hasDefaultValue(
266
+ 'hover_border_color'
267
+ ) && !$this->hasDefaultValue('hover_border_width')
268
+ ) {
269
+ $hover_styles[] = sprintf(
270
+ 'border:%s %s %s',
271
+ $this->config->hover_border_style,
272
+ $this->config->hover_border_width,
273
+ $this->config->hover_border_color
274
+ );
275
+ } else {
276
+ if (!$this->hasDefaultValue('hover_border_style')) {
277
+ $hover_styles[] = sprintf('border-style:%s', $this->config->hover_border_style);
278
+ }
279
+
280
+ if (!$this->hasDefaultValue('hover_border_color')) {
281
+ $hover_styles[] = sprintf('border-color:%s', $this->config->hover_border_color);
282
+ }
283
+
284
+ if (!$this->hasDefaultValue('hover_border_width')) {
285
+ $hover_styles[] = sprintf('border-width:%s', $this->config->hover_border_width);
286
+ }
287
+ }
288
+
289
+ if (!$this->hasDefaultValue('hover_color')) {
290
+ $hover_styles[] = sprintf('color:%s', $this->config->hover_color);
291
+ }
292
+
293
+ $styles = array();
294
+
295
+ if ($main_styles) {
296
+ $styles[] = sprintf('.utcw-%s{%s}', $this->id, join(';', $main_styles));
297
+ }
298
+
299
+ if ($link_styles) {
300
+ $styles[] = sprintf('.utcw-%s span,.utcw-%s a{%s}', $this->id, $this->id, join(';', $link_styles));
301
+ }
302
+
303
+ if ($hover_styles) {
304
+ $styles[] = sprintf('.utcw-%s span:hover,.utcw-%s a:hover{%s}', $this->id, $this->id, join(';', $hover_styles));
305
+ }
306
+
307
+ if ($styles) {
308
+ $this->css = sprintf('<style type="text/css">%s</style>', join('', $styles));
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Checks if option still has the default value
314
+ *
315
+ * @param string $option
316
+ *
317
+ * @return bool
318
+ * @since 2.0
319
+ */
320
+ private function hasDefaultValue($option)
321
+ {
322
+ $defaults = $this->config->getDefaults();
323
+ return $this->config->$option === $defaults[$option];
324
+ }
325
+ }
src/Selection/PopularityStrategy.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW\Selection;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage language
13
+ * @since 2.2
14
+ */
15
+
16
+ use Rickard\UTCW\Config;
17
+ use Rickard\UTCW\Database\QueryBuilder;
18
+ use Rickard\UTCW\Plugin;
19
+ use \stdClass;
20
+ use wpdb;
21
+
22
+ /**
23
+ * Class to select the most popular terms from the DB
24
+ *
25
+ * @since 2.2
26
+ * @package utcw
27
+ * @subpackage selection
28
+ */
29
+ class PopularityStrategy extends SelectionStrategy
30
+ {
31
+ /**
32
+ * @var Config
33
+ * @since 2.2
34
+ */
35
+ protected $config;
36
+
37
+ /**
38
+ * @var Plugin
39
+ * @since 2.2
40
+ */
41
+ protected $plugin;
42
+
43
+ /**
44
+ * @var wpdb
45
+ * @since 2.2
46
+ */
47
+ protected $db;
48
+
49
+ /**
50
+ * A copy of the SQL query for debugging purposes
51
+ *
52
+ * @var string
53
+ * @since 2.2
54
+ */
55
+ protected $query;
56
+
57
+ /**
58
+ * Creates a new instance
59
+ *
60
+ * @param Config $config Current configuration
61
+ * @param Plugin $plugin Main plugin instance
62
+ * @param wpdb $db WordPress DB instance
63
+ *
64
+ * @since 2.2
65
+ */
66
+ public function __construct(Config $config, Plugin $plugin, wpdb $db)
67
+ {
68
+ $this->config = $config;
69
+ $this->plugin = $plugin;
70
+ $this->db = $db;
71
+ }
72
+
73
+ /**
74
+ * Returns term data based on current configuration
75
+ *
76
+ * @return stdClass[]
77
+ * @since 2.2
78
+ */
79
+ public function getData()
80
+ {
81
+ $builder = new QueryBuilder($this->plugin, $this->db);
82
+
83
+ $builder->addAuthorConstraint($this->config->authors);
84
+ $builder->addPostTypeConstraint($this->config->post_type);
85
+ $builder->addPostStatusConstraint($this->plugin->isAuthenticatedUser());
86
+ $builder->addDaysOldConstraint($this->config->days_old);
87
+ $builder->addTaxonomyConstraint($this->config->taxonomy);
88
+ $builder->addTagsListConstraint(
89
+ $this->config->tags_list_type,
90
+ $this->config->tags_list,
91
+ $this->config->taxonomy
92
+ );
93
+ $builder->addGrouping();
94
+ $builder->addMinimum($this->config->minimum);
95
+ $builder->addStatement('ORDER BY count DESC');
96
+ $builder->addMaxConstraint($this->config->max);
97
+ $builder->addSort($this->config->order, $this->config->reverse, $this->config->case_sensitive);
98
+
99
+ $query = $builder->getQuery();
100
+ $parameters = $builder->getParameters();
101
+ $query = $this->db->prepare($query, $parameters);
102
+
103
+ $result = $this->db->get_results($query);
104
+ $this->query = $this->db->last_query;
105
+
106
+ return $result;
107
+ }
108
+
109
+ /**
110
+ * @return void
111
+ * @since 2.2
112
+ */
113
+ public function cleanupForDebug()
114
+ {
115
+ unset($this->db);
116
+ }
117
+ }
src/Selection/RandomStrategy.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW\Selection;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage language
13
+ * @since 2.2
14
+ */
15
+
16
+ use Rickard\UTCW\Config;
17
+ use Rickard\UTCW\Database\QueryBuilder;
18
+ use Rickard\UTCW\Plugin;
19
+ use stdClass;
20
+ use wpdb;
21
+
22
+ /**
23
+ * Class to select a random set of terms from the DB
24
+ *
25
+ * @since 2.2
26
+ * @package utcw
27
+ * @subpackage selection
28
+ */
29
+ class RandomStrategy extends SelectionStrategy
30
+ {
31
+ /**
32
+ * @var Config
33
+ * @since 2.2
34
+ */
35
+ protected $config;
36
+
37
+ /**
38
+ * @var Plugin
39
+ * @since 2.2
40
+ */
41
+ protected $plugin;
42
+
43
+ /**
44
+ * @var wpdb
45
+ * @since 2.2
46
+ */
47
+ protected $db;
48
+
49
+ /**
50
+ * A copy of the SQL query for debugging purposes
51
+ *
52
+ * @var string
53
+ * @since 2.2
54
+ */
55
+ protected $query;
56
+
57
+ /**
58
+ * Creates a new instance
59
+ *
60
+ * @param Config $config Current configuration
61
+ * @param Plugin $plugin Main plugin instance
62
+ * @param wpdb $db WordPress DB instance
63
+ *
64
+ * @since 2.2
65
+ */
66
+ public function __construct(Config $config, Plugin $plugin, wpdb $db)
67
+ {
68
+ $this->config = $config;
69
+ $this->plugin = $plugin;
70
+ $this->db = $db;
71
+ }
72
+
73
+ /**
74
+ * Returns term data based on current configuration
75
+ *
76
+ * @return stdClass[]
77
+ * @since 2.2
78
+ */
79
+ public function getData()
80
+ {
81
+ $builder = new QueryBuilder($this->plugin, $this->db);
82
+
83
+ $builder->addAuthorConstraint($this->config->authors);
84
+ $builder->addPostTypeConstraint($this->config->post_type);
85
+ $builder->addPostStatusConstraint($this->plugin->isAuthenticatedUser());
86
+ $builder->addDaysOldConstraint($this->config->days_old);
87
+ $builder->addTaxonomyConstraint($this->config->taxonomy);
88
+ $builder->addTagsListConstraint(
89
+ $this->config->tags_list_type,
90
+ $this->config->tags_list,
91
+ $this->config->taxonomy
92
+ );
93
+ $builder->addGrouping();
94
+ $builder->addMinimum($this->config->minimum);
95
+ $builder->addStatement('ORDER BY RAND()');
96
+ $builder->addMaxConstraint($this->config->max);
97
+ $builder->addSort($this->config->order, $this->config->reverse, $this->config->case_sensitive);
98
+
99
+ $query = $builder->getQuery();
100
+ $parameters = $builder->getParameters();
101
+
102
+ // Build query
103
+ $query = join("\n", $query);
104
+ $query = $this->db->prepare($query, $parameters);
105
+
106
+ // Fetch terms from DB
107
+ $result = $this->db->get_results($query);
108
+ $this->query = $this->db->last_query;
109
+
110
+ return $result;
111
+ }
112
+
113
+ /**
114
+ * @return void
115
+ * @since 2.2
116
+ */
117
+ public function cleanupForDebug()
118
+ {
119
+ unset($this->db);
120
+ }
121
+ }
src/Selection/SelectionStrategy.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW\Selection;
4
+
5
+ /**
6
+ * Ultimate Tag Cloud Widget
7
+ *
8
+ * @author Rickard Andersson <rickard@0x539.se>
9
+ * @version 2.2
10
+ * @license GPLv2
11
+ * @package utcw
12
+ * @subpackage selection
13
+ * @since 2.2
14
+ */
15
+
16
+ use Rickard\UTCW\Config;
17
+ use Rickard\UTCW\Plugin;
18
+ use \stdClass;
19
+ use wpdb;
20
+
21
+ /**
22
+ * Abstract class to define selection strategy for finding terms
23
+ *
24
+ * @since 2.2
25
+ * @package utcw
26
+ * @subpackage language
27
+ */
28
+ abstract class SelectionStrategy
29
+ {
30
+ /**
31
+ * Creates a new instance
32
+ *
33
+ * @param Config $config Current configuration
34
+ * @param Plugin $plugin Main plugin instance
35
+ * @param wpdb $db WordPress DB instance
36
+ *
37
+ * @since 2.0
38
+ */
39
+ abstract public function __construct(Config $config, Plugin $plugin, wpdb $db);
40
+
41
+ /**
42
+ * Loads terms based on current configuration
43
+ *
44
+ * @return stdClass[]
45
+ * @since 2.0
46
+ */
47
+ abstract public function getData();
48
+
49
+ /**
50
+ * @return void
51
+ */
52
+ abstract public function cleanupForDebug();
53
+ }
src/Term.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW;
4
+
5
+ use stdClass;
6
+
7
+ /**
8
+ * Ultimate Tag Cloud Widget
9
+ *
10
+ * @author Rickard Andersson <rickard@0x539.se>
11
+ * @version 2.2
12
+ * @license GPLv2
13
+ * @package utcw
14
+ * @subpackage main
15
+ * @since 2.0
16
+ */
17
+
18
+ /**
19
+ * Class to represent a term
20
+ *
21
+ * @since 2.0
22
+ * @package utcw
23
+ * @subpackage main
24
+ */
25
+ class Term
26
+ {
27
+
28
+ /**
29
+ * Term ID
30
+ *
31
+ * @var int
32
+ * @since 2.0
33
+ */
34
+ public $term_id;
35
+
36
+ /**
37
+ * Number of posts
38
+ *
39
+ * @var int
40
+ * @since 2.0
41
+ */
42
+ public $count;
43
+
44
+ /**
45
+ * Term slug
46
+ *
47
+ * @var string
48
+ * @since 2.0
49
+ */
50
+ public $slug;
51
+
52
+ /**
53
+ * Term name
54
+ *
55
+ * @var string
56
+ * @since 2.0
57
+ */
58
+ public $name;
59
+
60
+ /**
61
+ * Term link
62
+ *
63
+ * @var string
64
+ * @since 2.0
65
+ */
66
+ public $link;
67
+
68
+ /**
69
+ * Term color
70
+ *
71
+ * @var string
72
+ * @since 2.0
73
+ */
74
+ public $color;
75
+
76
+ /**
77
+ * Term taxonomy
78
+ *
79
+ * @var string
80
+ * @since 2.0
81
+ */
82
+ public $taxonomy;
83
+
84
+ /**
85
+ * Term size
86
+ *
87
+ * @var float
88
+ * @since 2.0
89
+ */
90
+ public $size;
91
+
92
+ /**
93
+ * Creates a new term
94
+ *
95
+ * @param stdClass $input Object with properties term_id, count, slug, name, color and taxonomy
96
+ * @param Plugin $plugin Reference to the plugin instance
97
+ *
98
+ * @since 2.0
99
+ */
100
+ public function __construct(stdClass $input, Plugin $plugin)
101
+ {
102
+
103
+ if (isset($input->term_id) && filter_var($input->term_id, FILTER_VALIDATE_INT)) {
104
+ $this->term_id = intval($input->term_id);
105
+ }
106
+
107
+ if (isset($input->count) && filter_var($input->count, FILTER_VALIDATE_INT)) {
108
+ $this->count = intval($input->count);
109
+ }
110
+
111
+ if (isset($input->slug) && strlen($input->slug) > 0 && preg_match('/^[0-9a-z\-]+/i', $input->slug)) {
112
+ $this->slug = $input->slug;
113
+ }
114
+
115
+ if (isset($input->name) && strlen($input->name) > 0) {
116
+ $this->name = $input->name;
117
+ }
118
+
119
+ if (isset($input->color) && strlen($input->color) > 0 && preg_match(UTCW_HEX_COLOR_REGEX, $input->color)) {
120
+ $this->color = $input->color;
121
+ }
122
+
123
+ if (isset($input->taxonomy) && strlen($input->taxonomy) > 0) {
124
+ $this->taxonomy = $input->taxonomy;
125
+ }
126
+
127
+ if ($this->term_id && $this->taxonomy) {
128
+ $this->link = $plugin->getTermLink($this->term_id, $this->taxonomy);
129
+ }
130
+ }
131
+ }
src/Widget.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Rickard\UTCW;
4
+
5
+ use WP_Widget;
6
+
7
+ /**
8
+ * Ultimate Tag Cloud Widget
9
+ *
10
+ * @author Rickard Andersson <rickard@0x539.se>
11
+ * @version 2.2
12
+ * @license GPLv2
13
+ * @package utcw
14
+ * @subpackage main
15
+ * @since 2.0
16
+ */
17
+
18
+ /**
19
+ * Widget class for WordPress integration
20
+ *
21
+ * @since 1.0
22
+ * @package utcw
23
+ * @subpackage main
24
+ */
25
+ class Widget extends WP_Widget
26
+ {
27
+
28
+ /**
29
+ * Reference to the main plugin instance
30
+ *
31
+ * @var Plugin
32
+ * @since 2.0
33
+ */
34
+ private $plugin;
35
+
36
+ /**
37
+ * Constructor
38
+ *
39
+ * @param Plugin $plugin Optional. Plugin instance for dependency injection
40
+ *
41
+ * @return Widget
42
+ * @since 1.0
43
+ */
44
+ public function __construct(Plugin $plugin = null)
45
+ {
46
+ $options = array('description' => __('Highly configurable tag cloud', 'utcw'));
47
+ parent::__construct('utcw', __('Ultimate Tag Cloud', 'utcw'), $options);
48
+
49
+ $this->plugin = $plugin ? $plugin : Plugin::getInstance();
50
+ }
51
+
52
+ /**
53
+ * Action handler for the form in the admin panel
54
+ *
55
+ * @param array $new_instance
56
+ * @param array $old_instance
57
+ *
58
+ * @return array
59
+ * @since 1.0
60
+ */
61
+ public function update(array $new_instance, array $old_instance)
62
+ {
63
+ $load_config = isset($new_instance['load_config']) &&
64
+ isset($new_instance['load_config_name']) &&
65
+ $new_instance['load_config_name'];
66
+
67
+ $save_config = isset($new_instance['save_config']) &&
68
+ isset($new_instance['save_config_name']) &&
69
+ $new_instance['save_config_name'];
70
+
71
+ // Overwrite the form values with the saved configuration
72
+ if ($load_config) {
73
+ $loaded_configuration = $this->plugin->loadConfiguration($new_instance['load_config_name']);
74
+
75
+ if ($loaded_configuration) {
76
+ $new_instance = $loaded_configuration;
77
+ }
78
+ }
79
+
80
+ // Checkbox inputs which are unchecked, will not be set in $new_instance. Set them manually to false
81
+ $checkbox_settings = array('show_title_text', 'show_links', 'show_title', 'debug', 'reverse', 'case_sensitive');
82
+
83
+ foreach ($checkbox_settings as $checkbox_setting) {
84
+ if (!isset($new_instance[$checkbox_setting])) {
85
+ $new_instance[$checkbox_setting] = false;
86
+ }
87
+ }
88
+
89
+ $config = new Config($new_instance, $this->plugin);
90
+
91
+ if ($save_config) {
92
+ $this->plugin->saveConfiguration($new_instance['save_config_name'], $config->getInstance());
93
+ }
94
+
95
+ if (isset($new_instance['remove_config']) && is_array($new_instance['remove_config'])) {
96
+ foreach ($new_instance['remove_config'] as $configuration) {
97
+ $this->plugin->removeConfiguration($configuration);
98
+ }
99
+ }
100
+
101
+ return $config->getInstance();
102
+ }
103
+
104
+ /**
105
+ * Function for handling the widget control in admin panel
106
+ *
107
+ * @param array $instance
108
+ *
109
+ * @return void|string
110
+ * @since 1.0
111
+ */
112
+ public function form(array $instance)
113
+ {
114
+ /** @noinspection PhpUnusedLocalVariableInspection */
115
+ $config = new Config($instance, $this->plugin);
116
+ /** @noinspection PhpUnusedLocalVariableInspection */
117
+ $configurations = $this->plugin->getConfigurations();
118
+ /** @noinspection PhpUnusedLocalVariableInspection */
119
+ $available_post_types = $this->plugin->getAllowedPostTypes();
120
+ /** @noinspection PhpUnusedLocalVariableInspection */
121
+ $available_taxonomies = $this->plugin->getAllowedTaxonomiesObjects();
122
+ /** @noinspection PhpUnusedLocalVariableInspection */
123
+ $users = $this->plugin->getUsers();
124
+ /** @noinspection PhpUnusedLocalVariableInspection */
125
+ $terms = $this->plugin->getTerms();
126
+
127
+ // Content of the widget settings form
128
+ require dirname(__FILE__) . '/../pages/settings.php';
129
+ }
130
+
131
+ /**
132
+ * Function for rendering the widget
133
+ *
134
+ * @param array $args
135
+ *
136
+ * @param array $instance
137
+ */
138
+ public function widget(array $args, array $instance)
139
+ {
140
+ global $wpdb;
141
+
142
+ $input = array_merge($instance, $args);
143
+
144
+ $config = new Config($input, $this->plugin);
145
+ $data = new Data($config, $this->plugin, $wpdb);
146
+ $render = new Render($config, $data, $this->plugin);
147
+
148
+ $render->render();
149
+ }
150
+ }
ultimate-tag-cloud-widget.php CHANGED
@@ -1,14 +1,98 @@
1
  <?php
 
 
2
  /*
3
  Plugin Name: Ultimate tag cloud widget
4
  Plugin URI: https://www.0x539.se/wordpress/ultimate-tag-cloud-widget/
5
- Description: This plugin aims to be the most configurable tag cloud widget out there, able to suit all your weird tag cloud needs.
6
- Version: 2.1
7
  Author: Rickard Andersson
8
  Author URI: https://www.0x539.se
9
  License: GPLv2
10
  */
11
 
12
- // Legacy file for compatibility with version 1.x
13
- /** @noinspection PhpIncludeInspection */
14
- require_once 'utcw.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+ use Rickard\UTCW\Plugin;
3
+
4
  /*
5
  Plugin Name: Ultimate tag cloud widget
6
  Plugin URI: https://www.0x539.se/wordpress/ultimate-tag-cloud-widget/
7
+ Description: This plugin aims to be the most configurable tag cloud widget out there.
8
+ Version: 2.2-beta1
9
  Author: Rickard Andersson
10
  Author URI: https://www.0x539.se
11
  License: GPLv2
12
  */
13
 
14
+ /**
15
+ * Current version number
16
+ *
17
+ * @var string
18
+ * @since 2.0
19
+ */
20
+ define('UTCW_VERSION', '2.2-beta1');
21
+
22
+ /**
23
+ * If development mode is currently enabled
24
+ *
25
+ * @var bool
26
+ * @since 2.0
27
+ */
28
+ define('UTCW_DEV', false);
29
+
30
+ /**
31
+ * Regular expression for matching hexadecimal colors
32
+ *
33
+ * @var string
34
+ * @since 2.0
35
+ */
36
+ define('UTCW_HEX_COLOR_REGEX', '/#([a-f0-9]{6}|[a-f0-9]{3})/i');
37
+
38
+ /**
39
+ * Regular expression for matching decimal numbers
40
+ *
41
+ * @var string
42
+ * @since 2.1
43
+ */
44
+ define('UTCW_DECIMAL_REGEX', '\d+(\.\d+)?');
45
+
46
+ /**
47
+ * printf format for rendering hexadecimal colors
48
+ *
49
+ * @var string
50
+ * @since 2.0
51
+ */
52
+ define('UTCW_HEX_COLOR_FORMAT', '#%02x%02x%02x');
53
+
54
+ if (UTCW_DEV) {
55
+ require_once '/www/utcw2/src/Plugin.php';
56
+ require_once '/www/utcw2/src/Config.php';
57
+ require_once '/www/utcw2/src/Widget.php';
58
+ require_once '/www/utcw2/src/Data.php';
59
+ require_once '/www/utcw2/src/Render.php';
60
+ require_once '/www/utcw2/src/Term.php';
61
+ require_once '/www/utcw2/src/Language/TranslationHandler.php';
62
+ require_once '/www/utcw2/src/Language/QTranslateHandler.php';
63
+ require_once '/www/utcw2/src/Language/WPMLHandler.php';
64
+ require_once '/www/utcw2/src/Selection/SelectionStrategy.php';
65
+ require_once '/www/utcw2/src/Selection/PopularityStrategy.php';
66
+ require_once '/www/utcw2/src/Selection/RandomStrategy.php';
67
+ require_once '/www/utcw2/src/Database/QueryBuilder.php';
68
+ } else {
69
+ require_once 'src/Plugin.php';
70
+ require_once 'src/Config.php';
71
+ require_once 'src/Widget.php';
72
+ require_once 'src/Data.php';
73
+ require_once 'src/Render.php';
74
+ require_once 'src/Term.php';
75
+ require_once 'src/Language/TranslationHandler.php';
76
+ require_once 'src/Language/QTranslateHandler.php';
77
+ require_once 'src/Language/WPMLHandler.php';
78
+ require_once 'src/Selection/SelectionStrategy.php';
79
+ require_once 'src/Selection/PopularityStrategy.php';
80
+ require_once 'src/Selection/RandomStrategy.php';
81
+ require_once 'src/Database/QueryBuilder.php';
82
+ }
83
+
84
+ // Instantiates the plugin
85
+ Plugin::getInstance();
86
+
87
+ /**
88
+ * Function for theme integration
89
+ *
90
+ * @param array $args
91
+ *
92
+ * @since 1.3
93
+ */
94
+ function do_utcw(array $args)
95
+ {
96
+ $plugin = Plugin::getInstance();
97
+ echo $plugin->shortcode($args);
98
+ }
utcw-config.php DELETED
@@ -1,841 +0,0 @@
1
- <?php
2
- /**
3
- * Ultimate Tag Cloud Widget
4
- * @author Rickard Andersson <rickard@0x539.se>
5
- * @version 2.1
6
- * @license GPLv2
7
- * @package utcw
8
- * @subpackage main
9
- * @since 2.0
10
- */
11
- if ( ! defined( 'ABSPATH' ) ) die();
12
-
13
- /**
14
- * Configuration class for the widget.
15
- *
16
- * @since 2.0
17
- * @package utcw
18
- * @subpackage main
19
- */
20
- class UTCW_Config {
21
-
22
- /**
23
- * Title text of the widget.
24
- * Default value: Tag cloud
25
- *
26
- * @var string
27
- * @since 2.0
28
- */
29
- public $title;
30
-
31
- /**
32
- * How the result should be ordered
33
- * Default value: name
34
- * Valid values: random, name, slug, id, color, count
35
- *
36
- * @var string
37
- * @since 2.0
38
- */
39
- public $order;
40
-
41
- /**
42
- * The smallest possible size
43
- * Default: 10px
44
- *
45
- * @var string
46
- * @since 2.0
47
- */
48
- public $size_from;
49
-
50
- /**
51
- * The greatest possible size
52
- * Default: 30px
53
- *
54
- * @var string
55
- * @since 2.0
56
- */
57
- public $size_to;
58
-
59
- /**
60
- * Maximum number of tags to display
61
- * Default: 45
62
- *
63
- * @var int
64
- * @since 2.0
65
- */
66
- public $max;
67
-
68
- /**
69
- * Which taxonomy to show tags from
70
- * Default: [post_tag]
71
- *
72
- * @var array
73
- * @since 2.0
74
- */
75
- public $taxonomy;
76
-
77
- /**
78
- * If the order of tags should be shown in reverse order
79
- * Default: false
80
- *
81
- * @var bool
82
- * @since 2.0
83
- */
84
- public $reverse;
85
-
86
- /**
87
- * Which coloring strategy to use
88
- * Default: none
89
- * Valid values: none, random, set, span
90
- *
91
- * @var string
92
- * @since 2.0
93
- */
94
- public $color;
95
-
96
- /**
97
- * CSS letter-spacing value (in pixels)
98
- * Default: normal
99
- *
100
- * @var string
101
- * @since 2.0
102
- */
103
- public $letter_spacing;
104
-
105
- /**
106
- * CSS word-spacing value (in pixels)
107
- * Default: normal
108
- *
109
- * @var string
110
- * @since 2.0
111
- */
112
- public $word_spacing;
113
-
114
- /**
115
- * CSS text-transform value
116
- * Default: none
117
- * Valid values: lowercase, uppercase, capitalize
118
- *
119
- * @var string
120
- * @since 2.0
121
- */
122
- public $text_transform;
123
-
124
- /**
125
- * If sorting should be applied case sensitive
126
- * Default: false
127
- *
128
- * @var bool
129
- * @since 2.0
130
- */
131
- public $case_sensitive;
132
-
133
- /**
134
- * How many posts a term needs to have to be shown in the cloud
135
- * Default: 1
136
- *
137
- * @var int
138
- * @since 2.0
139
- */
140
- public $minimum;
141
-
142
- /**
143
- * How the $tags_list should be used
144
- * Default: exclude
145
- * Valid values: exclude, include
146
- *
147
- * @var string
148
- * @since 2.0
149
- */
150
- public $tags_list_type;
151
-
152
- /**
153
- * If the title attribute should be added to links in the cloud
154
- * Default: true
155
- *
156
- * @var bool
157
- * @since 2.0
158
- */
159
- public $show_title;
160
-
161
- /**
162
- * If links should be styled with underline decoration
163
- * Default: default
164
- * Valid values: yes, no, default
165
- *
166
- * @var string
167
- * @since 2.0
168
- */
169
- public $link_underline;
170
-
171
- /**
172
- * If links should be styled as bold
173
- * Default: default
174
- * Valid values: yes, no, default
175
- *
176
- * @var string
177
- * @since 2.0
178
- */
179
- public $link_bold;
180
-
181
- /**
182
- * If links should be styled as italic
183
- * Default: default
184
- * Valid values: yes, no, default
185
- *
186
- * @var string
187
- * @since 2.0
188
- */
189
- public $link_italic;
190
-
191
- /**
192
- * Background color for links
193
- * Default: transparent
194
- * Valid values: A hexadecimal color
195
- *
196
- * @var string
197
- * @since 2.0
198
- */
199
- public $link_bg_color;
200
-
201
- /**
202
- * Border style for links
203
- * Default: none
204
- * Valid values: none, dotted, dashed, solid, double, groove, ridge, inset, outset
205
- *
206
- * @var string
207
- * @since 2.0
208
- */
209
- public $link_border_style;
210
-
211
- /**
212
- * Border width for links
213
- * Default: 0
214
- *
215
- * @var string
216
- * @since 2.0
217
- */
218
- public $link_border_width;
219
-
220
- /**
221
- * Border color for links
222
- * Default: none
223
- * Valid values: A hexadecimal color
224
- *
225
- * @var string
226
- * @since 2.0
227
- */
228
- public $link_border_color;
229
-
230
- /**
231
- * If links should be decorated with underline decoration in their hover state
232
- * Default: default
233
- * Valid values: yes, no, default
234
- *
235
- * @var string
236
- * @since 2.0
237
- */
238
- public $hover_underline;
239
-
240
- /**
241
- * If links should be styled as bold in their hover state
242
- * Default: default
243
- * Valid values: yes, no, default
244
- *
245
- * @var string
246
- * @since 2.0
247
- */
248
- public $hover_bold;
249
-
250
- /**
251
- * If links should be styled as italic in their hover state
252
- * Default: default
253
- * Valid values: yes, no, default
254
- *
255
- * @var string
256
- * @since 2.0
257
- */
258
- public $hover_italic;
259
-
260
- /**
261
- * Background color for links in their hover state
262
- * Default: transparent
263
- * Valid values: A hexadecimal color
264
- *
265
- * @var string
266
- * @since 2.0
267
- */
268
- public $hover_bg_color;
269
-
270
- /**
271
- * Text color for links in their hover state
272
- * Default: default
273
- * Valid values: A hexadecimal color
274
- *
275
- * @var string
276
- * @since 2.0
277
- */
278
- public $hover_color;
279
-
280
- /**
281
- * Border style for links in their hover state
282
- * Default: none
283
- * Valid values: none, dotted, dashed, solid, double, groove, ridge, inset, outset
284
- *
285
- * @var string
286
- * @since 2.0
287
- */
288
- public $hover_border_style;
289
-
290
- /**
291
- * Border width for links in their hover state
292
- * Default: 0
293
- *
294
- * @var string
295
- * @since 2.0
296
- */
297
- public $hover_border_width;
298
-
299
- /**
300
- * Border color for links in their hover state
301
- * Default: none
302
- * Valid values: A hexadecimal color
303
- *
304
- * @var string
305
- * @since 2.0
306
- */
307
- public $hover_border_color;
308
-
309
- /**
310
- * CSS margin between tags
311
- * Default: auto
312
- *
313
- * @var string
314
- * @since 2.0
315
- */
316
- public $tag_spacing;
317
-
318
- /**
319
- * If debug output should be included
320
- * Default: false
321
- *
322
- * @var bool
323
- * @since 2.0
324
- */
325
- public $debug;
326
-
327
- /**
328
- * How many days old a post needs to be to be included in tag size calculation
329
- * Default: 0
330
- *
331
- * @var int
332
- * @since 2.0
333
- */
334
- public $days_old;
335
-
336
- /**
337
- * CSS line-height for the tags
338
- * Default: inherit
339
- *
340
- * @var string
341
- * @since 2.0
342
- */
343
- public $line_height;
344
-
345
- /**
346
- * Separator between tags
347
- * Default: (a space character)
348
- *
349
- * @var string
350
- * @since 2.0
351
- */
352
- public $separator;
353
-
354
- /**
355
- * Prefix before each tag
356
- * Default: (empty string)
357
- *
358
- * @var string
359
- * @since 2.0
360
- */
361
- public $prefix;
362
-
363
- /**
364
- * Suffix after each tag
365
- * Default: (empty string)
366
- *
367
- * @var string
368
- * @since 2.0
369
- */
370
- public $suffix;
371
-
372
- /**
373
- * If the widget title should be shown
374
- * Default: true
375
- *
376
- * @var bool
377
- * @since 2.0
378
- */
379
- public $show_title_text;
380
-
381
- /**
382
- * An array of post type names to to include posts from in tag size calculation
383
- * Default: [ post ]
384
- *
385
- * @var array
386
- * @since 2.0
387
- */
388
- public $post_type;
389
-
390
- /**
391
- * A list of term IDs to be included or excluded. Inclusion or exclusion is determined by $tags_list_type
392
- * Default: [] (an empty array)
393
- *
394
- * @var array
395
- * @since 2.0
396
- */
397
- public $tags_list;
398
-
399
- /**
400
- * Which color value to start from in color calculation. This is the color that the smallest tag will get.
401
- * Default: (an empty string)
402
- *
403
- * @var string
404
- * @since 2.0
405
- */
406
- public $color_span_to;
407
-
408
- /**
409
- * Which color value to end at in color calculation. This is the color that the biggest tag will get.
410
- * Default: (an empty string)
411
- *
412
- * @var string
413
- * @since 2.0
414
- */
415
- public $color_span_from;
416
-
417
- /**
418
- * Which authors to include posts from. An empty array will include all authors
419
- * Default: [] (an empty array)
420
- *
421
- * @var array
422
- * @since 2.0
423
- */
424
- public $authors;
425
-
426
- /**
427
- * A set of colors to randomly select from when coloring the tags
428
- * Default: [] (an empty array)
429
- *
430
- * @var array
431
- * @since 2.0
432
- */
433
- public $color_set;
434
-
435
- /**
436
- * If the current user is authenticated. Will be set internally
437
- *
438
- * @internal
439
- * @var bool
440
- * @since 2.0
441
- */
442
- public $authenticated;
443
-
444
- /**
445
- * Text to display before the widget. The default value for this setting will probably be determined by the theme
446
- * Default: (an empty string)
447
- *
448
- * @var string
449
- * @since 2.0
450
- */
451
- public $before_widget;
452
-
453
- /**
454
- * Text to display after the widget. The default value for this setting will probably be determined by the theme
455
- * Default: (an empty string)
456
- *
457
- * @var string
458
- * @since 2.0
459
- */
460
- public $after_widget;
461
-
462
- /**
463
- * Text to display before the widget title. The default value for this setting will probably be determined by the theme
464
- * Default: (an empty string)
465
- *
466
- * @var string
467
- * @since 2.0
468
- */
469
- public $before_title;
470
-
471
- /**
472
- * Text to display after the widget title. The default value for this setting will probably be determined by the theme
473
- * Default: (an empty string)
474
- *
475
- * @var string
476
- * @since 2.0
477
- */
478
- public $after_title;
479
-
480
- /**
481
- * Config store with default values
482
- *
483
- * @static
484
- * @var array
485
- * @since 2.0
486
- */
487
- static protected $options = array(
488
- 'title' => 'Tag Cloud',
489
- 'order' => 'name',
490
- 'size_from' => '10px',
491
- 'size_to' => '30px',
492
- 'max' => 45,
493
- 'taxonomy' => array( 'post_tag' ),
494
- 'reverse' => false,
495
- 'color' => 'none',
496
- 'letter_spacing' => 'normal',
497
- 'word_spacing' => 'normal',
498
- 'text_transform' => 'none',
499
- 'case_sensitive' => false,
500
- 'minimum' => 1,
501
- 'tags_list_type' => 'exclude',
502
- 'show_title' => true,
503
- 'link_underline' => 'default',
504
- 'link_bold' => 'default',
505
- 'link_italic' => 'default',
506
- 'link_bg_color' => 'transparent',
507
- 'link_border_style' => 'none',
508
- 'link_border_width' => '0',
509
- 'link_border_color' => 'none',
510
- 'hover_underline' => 'default',
511
- 'hover_bold' => 'default',
512
- 'hover_italic' => 'default',
513
- 'hover_bg_color' => 'transparent',
514
- 'hover_color' => 'default',
515
- 'hover_border_style' => 'none',
516
- 'hover_border_width' => '0',
517
- 'hover_border_color' => 'none',
518
- 'tag_spacing' => 'auto',
519
- 'debug' => false,
520
- 'days_old' => 0,
521
- 'line_height' => 'inherit',
522
- 'separator' => ' ',
523
- 'prefix' => '',
524
- 'suffix' => '',
525
- 'show_title_text' => true,
526
- 'post_type' => array( 'post' ),
527
- 'tags_list' => array(),
528
- 'color_span_to' => '',
529
- 'color_span_from' => '',
530
- 'authors' => array(),
531
- 'color_set' => array(),
532
- 'before_widget' => '',
533
- 'after_widget' => '',
534
- 'before_title' => '',
535
- 'after_title' => '',
536
- );
537
-
538
- /**
539
- * Which ordering strategies are allowed
540
- *
541
- * @var array
542
- * @since 2.0
543
- */
544
- protected $allowed_orders = array( 'random', 'name', 'slug', 'id', 'color', 'count' );
545
-
546
- /**
547
- * Which taxonomies are allowed. Will be set dynamically at load
548
- *
549
- * @var array
550
- * @since 2.0
551
- */
552
- protected $allowed_taxonomies = array();
553
-
554
- /**
555
- * Which post types are allowed. Will be set dynamically at load
556
- *
557
- * @var array
558
- * @since 2.0
559
- */
560
- protected $allowed_post_types = array();
561
-
562
- /**
563
- * Which coloring strategies are allowed
564
- *
565
- * @var array
566
- * @since 2.0
567
- */
568
- protected $allowed_colors = array( 'none', 'random', 'set', 'span' );
569
-
570
- /**
571
- * Which CSS text-transform values are allowed
572
- *
573
- * @var array
574
- * @since 2.0
575
- */
576
- protected $allowed_text_transforms = array( 'lowercase', 'uppercase', 'capitalize' );
577
-
578
- /**
579
- * Which tags_list_type values are allowed
580
- *
581
- * @var array
582
- * @since 2.0
583
- */
584
- protected $allowed_tags_list_types = array( 'exclude', 'include' );
585
-
586
- /**
587
- * Which values are allowed for optional booleans. These are values which can be true, false or fallback to theme default (where applicable)
588
- *
589
- * @var array
590
- * @since 2.0
591
- */
592
- protected $allowed_optional_booleans = array( 'yes', 'no', 'default' );
593
-
594
- /**
595
- * Which CSS border-style valeus are allowed
596
- *
597
- * @var array
598
- * @since 2.0
599
- */
600
- protected $allowed_border_styles = array(
601
- 'none', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset',
602
- );
603
-
604
- /**
605
- * Loads a configuration instance array and parses the options
606
- *
607
- * @param array $input Array of key => value pairs of settings and values
608
- * @param UTCW_Plugin $plugin Reference to the main plugin instance
609
- *
610
- * @since 2.0
611
- */
612
- public function __construct( array $input, UTCW_Plugin $plugin ) {
613
- $this->allowed_post_types = $plugin->get_allowed_post_types();
614
- $this->allowed_taxonomies = $plugin->get_allowed_taxonomies();
615
- $this->authenticated = $plugin->is_authenticated_user();
616
-
617
- foreach ( self::$options as $key => $default ) {
618
- $this->$key = $default;
619
-
620
- if ( isset( $input[ $key ] ) ) {
621
- $valid = true;
622
-
623
- switch ( $key ) {
624
- case 'order':
625
- $valid = in_array( $input[ $key ], $this->allowed_orders );
626
- break;
627
-
628
- case 'text_transform':
629
- $valid = in_array( $input[ $key ], $this->allowed_text_transforms );
630
- break;
631
-
632
- case 'tags_list_type':
633
- $valid = in_array( $input[ $key ], $this->allowed_tags_list_types );
634
- break;
635
-
636
- // Optional booleans, can be yes, no or default
637
- case 'link_underline':
638
- case 'link_bold':
639
- case 'link_italic':
640
- case 'hover_underline':
641
- case 'hover_bold':
642
- case 'hover_italic':
643
- $valid = in_array( $input[ $key ], $this->allowed_optional_booleans );
644
- break;
645
-
646
- case 'link_border_style':
647
- case 'hover_border_style':
648
- $valid = in_array( $input[ $key ], $this->allowed_border_styles );
649
- break;
650
-
651
- case 'color':
652
- $valid = in_array( $input[ $key ], $this->allowed_colors );
653
- break;
654
-
655
- // TODO: Allow more flexibility in color setting, like rgb/rgba/hsl/hsla and named colors
656
- case 'link_bg_color':
657
- case 'link_border_color':
658
- case 'hover_bg_color':
659
- case 'hover_color':
660
- case 'hover_border_color':
661
- case 'color_span_to':
662
- case 'color_span_from':
663
- $valid = preg_match( UTCW_HEX_COLOR_REGEX, $input[ $key ] ) > 0;
664
- break;
665
-
666
- case 'color_set':
667
- if ( ! is_array( $input[ $key ] ) ) {
668
- $input[ $key ] = explode( ',', $input[ $key ] );
669
- }
670
-
671
- $valid = $input[ $key ] && array_filter( $input[ $key ], create_function( '$item', 'return preg_match( UTCW_HEX_COLOR_REGEX, $item );' ) ) == $input[ $key ];
672
- break;
673
-
674
- case 'taxonomy':
675
- if ( ! is_array( $input[ $key ] ) ) {
676
- $input[ $key ] = explode( ',', $input[ $key ] );
677
- }
678
-
679
- // Remove invalid taxonomies
680
- foreach ( $input[ $key ] as $tax_key => $taxonomy ) {
681
- if ( ! in_array( $taxonomy, $this->allowed_taxonomies ) ) {
682
- unset( $input[ $key ][ $tax_key ] );
683
- }
684
- }
685
-
686
- $valid = ! ! $input[ $key ]; // Setting is valid if any of the taxonomies were valid
687
- break;
688
-
689
- case 'post_type':
690
- if ( ! is_array( $input[ $key ] ) ) {
691
- $input[ $key ] = explode( ',', $input[ $key ] );
692
- }
693
-
694
- $valid = $input[ $key ] && count( array_intersect( $this->allowed_post_types, $input[ $key ] ) ) == count( $input[ $key ] );
695
- break;
696
-
697
- case 'authors':
698
- case 'tags_list':
699
- if ( ! is_array( $input[ $key ] ) ) {
700
- $input[ $key ] = explode( ',', $input[ $key ] );
701
- }
702
-
703
- $valid = $this->is_array_numeric( $input[ $key ] );
704
- $input[ $key ] = array_map( 'intval', $input[ $key ] );
705
- break;
706
-
707
- case 'size_from':
708
- $input[ 'size_from' ] = $this->parse_measurement( $input[ 'size_from' ] );
709
- $size_to = isset( $input[ 'size_to' ] ) ? $input[ 'size_to' ] : self::$options[ 'size_to' ];
710
- $valid = $input[ 'size_from' ] !== false && $this->equal_units( $input[ 'size_from' ], $size_to ) && floatval( $input[ 'size_from' ] ) <= floatval( $size_to );
711
- break;
712
-
713
- case 'size_to':
714
- $input[ 'size_to' ] = $this->parse_measurement( $input[ 'size_to' ] );
715
- $size_from = isset( $input[ 'size_from' ] ) ? $input[ 'size_from' ] : self::$options[ 'size_from' ];
716
- $valid = $input[ 'size_to' ] !== false && $this->equal_units( $size_from, $input[ 'size_to' ] ) && floatval( $input[ 'size_to' ] ) >= floatval( $size_from );
717
- break;
718
-
719
- case 'letter_spacing':
720
- case 'word_spacing':
721
- case 'tag_spacing':
722
- case 'line_height':
723
- case 'link_border_width':
724
- case 'hover_border_width':
725
- $input[ $key ] = $this->parse_measurement( $input[ $key ] );
726
- $valid = $input[ $key ] !== false;
727
- break;
728
- }
729
-
730
- if ( ! $valid ) {
731
- continue;
732
- }
733
-
734
- // Special handling of the color_set config attribute which needs to be expanded to full 6 digit hexadecimal values
735
- if ( $key == 'color_set' ) {
736
- foreach ( $input[ $key ] as $cs_key => $color ) {
737
- if ( strlen( $color ) == 4 ) {
738
- $red = substr( $color, 1, 1 );
739
- $green = substr( $color, 2, 1 );
740
- $blue = substr( $color, 3, 1 );
741
- $input[ $key ][ $cs_key ] = sprintf( '#%s%s%s%s%s%s', $red, $red, $green, $green, $blue, $blue );
742
- }
743
- }
744
- $this->$key = $input[ $key ];
745
- } else if ( $key == 'minimum' ) {
746
- $this->$key = intval( $input[ $key ] );
747
- } else if ( is_string( self::$options[ $key ] ) && is_string( $input[ $key ] ) && strlen( $input[ $key ] ) > 0 ) {
748
- $this->$key = $input[ $key ];
749
- } else if ( is_integer( self::$options[ $key ] ) && $input[ $key ] > 0 ) {
750
- $this->$key = intval( $input[ $key ] );
751
- } else if ( is_bool( self::$options[ $key ] ) ) {
752
- $this->$key = ! ! $input[ $key ];
753
- } else if ( is_array( self::$options[ $key ] ) ) {
754
- $this->$key = is_array( $input[ $key ] ) ? $input[ $key ] : explode( ',', $input[ $key ] );
755
- }
756
- }
757
- }
758
- }
759
-
760
- /**
761
- * Checks if every item in the array is numeric
762
- *
763
- * @param array $array
764
- *
765
- * @return bool
766
- * @since 2.0
767
- */
768
- private function is_array_numeric( array $array ) {
769
- foreach ( $array as $item ) {
770
- if ( ! is_numeric( $item ) ) {
771
- return false;
772
- }
773
- }
774
-
775
- return true;
776
- }
777
-
778
- /**
779
- * Parses the input value as measurement
780
- *
781
- * @param mixed $input
782
- *
783
- * @return bool|string False on failure
784
- * @since 2.1
785
- */
786
- private function parse_measurement( $input ) {
787
- if ( ! preg_match( '/^' . UTCW_DECIMAL_REGEX . '(em|px|%)?$/i', $input ) ) {
788
- return false;
789
- }
790
-
791
- // Convert integer values to pixel values
792
- if ( preg_match( '/^' . UTCW_DECIMAL_REGEX . '$/', $input ) ) {
793
- return $input . 'px';
794
- }
795
-
796
- return $input;
797
- }
798
-
799
- /**
800
- * Checks if the two measurements have the same unit
801
- *
802
- * @param string $measurement1
803
- * @param string $measurement2
804
- *
805
- * @return bool
806
- * @since 2.1
807
- */
808
- private function equal_units( $measurement1, $measurement2 ) {
809
- $unit1 = preg_replace( '/' . UTCW_DECIMAL_REGEX . '/', '', $measurement1 );
810
- $unit2 = preg_replace( '/' . UTCW_DECIMAL_REGEX . '/', '', $measurement2 );
811
-
812
- return $unit1 === $unit2 || ( $unit1 === 'px' && $unit2 === '' ) || ( $unit1 === '' && $unit2 === 'px' );
813
- }
814
-
815
- /**
816
- * Returns an array of current configuration
817
- *
818
- * @return array
819
- * @since 2.0
820
- */
821
- public function get_instance() {
822
- $instance = array();
823
-
824
- foreach ( array_keys( self::$options ) as $key ) {
825
- $instance[ $key ] = $this->$key;
826
- }
827
-
828
- return $instance;
829
- }
830
-
831
- /**
832
- * Returns the default values for all the configuration options
833
- *
834
- * @static
835
- * @return array
836
- * @since 2.0
837
- */
838
- public static function get_defaults() {
839
- return self::$options;
840
- }
841
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
utcw-data.php DELETED
@@ -1,364 +0,0 @@
1
- <?php
2
- /**
3
- * Ultimate Tag Cloud Widget
4
- * @author Rickard Andersson <rickard@0x539.se>
5
- * @version 2.1
6
- * @license GPLv2
7
- * @package utcw
8
- * @subpackage main
9
- * @since 2.0
10
- */
11
- if ( ! defined( 'ABSPATH' ) ) die();
12
-
13
- /**
14
- * Class for loading data for the cloud
15
- *
16
- * @since 2.0
17
- * @package utcw
18
- * @subpackage main
19
- */
20
- class UTCW_Data {
21
-
22
- /**
23
- * Reference to the current configuration
24
- *
25
- * @var UTCW_Config
26
- * @since 2.0
27
- */
28
- protected $config;
29
-
30
- /**
31
- * Reference to WPDB object
32
- *
33
- * @var wpdb
34
- * @since 2.0
35
- */
36
- protected $db;
37
-
38
- /**
39
- * Reference to main plugin instance
40
- *
41
- * @var UTCW_Plugin
42
- * @since 2.0
43
- */
44
- protected $plugin;
45
-
46
- /**
47
- * A copy of the SQL query for debugging purposes
48
- *
49
- * @var string
50
- * @since 2.1
51
- */
52
- protected $query;
53
-
54
- /**
55
- * Creates a new instance
56
- *
57
- * @param UTCW_Config $config Current configuration
58
- * @param UTCW_Plugin $plugin Main plugin instance
59
- * @param wpdb $db WordPress DB instance
60
- *
61
- * @since 2.0
62
- */
63
- function __construct( UTCW_Config $config, UTCW_Plugin $plugin, wpdb $db ) {
64
- $this->config = $config;
65
- $this->db = $db;
66
- $this->plugin = $plugin;
67
- }
68
-
69
- /**
70
- * Loads terms based on current configuration
71
- *
72
- * @return UTCW_Term[]
73
- * @since 2.0
74
- */
75
- function get_terms() {
76
- $query = array();
77
-
78
- // Base query with joins
79
- $query[ ] = 'SELECT t.term_id, t.name, t.slug, COUNT(p.ID) AS `count`, tt.taxonomy';
80
- $query[ ] = 'FROM `' . $this->db->terms . '` AS t';
81
- $query[ ] = 'JOIN `' . $this->db->term_taxonomy . '` AS tt ON t.term_id = tt.term_id';
82
- $query[ ] = 'LEFT JOIN `' . $this->db->term_relationships . '` AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id';
83
- $query[ ] = 'LEFT JOIN `' . $this->db->posts . '` AS p ON tr.object_id = p.ID';
84
-
85
- // Add authors constraint if configured
86
- if ( $this->config->authors ) {
87
- $author_parameters = array();
88
-
89
- foreach ( $this->config->authors as $author ) {
90
- $author_parameters[ ] = '%d';
91
- $parameters[ ] = $author;
92
- }
93
-
94
- $query[ ] = 'AND p.post_author IN (' . join( ',', $author_parameters ) . ')';
95
- }
96
-
97
- // Add post types constraint
98
- $post_type_parameters = array();
99
-
100
- foreach ( $this->config->post_type as $post_type ) {
101
- $post_type_parameters[ ] = '%s';
102
- $parameters[ ] = $post_type;
103
- }
104
-
105
- $query[ ] = 'AND p.post_type IN (' . join( ',', $post_type_parameters ) . ')';
106
-
107
- // Add post status statement, authenticated users are allowed to view tags for private posts
108
- if ( $this->config->authenticated ) {
109
- $query[ ] = "AND p.post_status IN ('publish','private')";
110
- } else {
111
- $query[ ] = "AND p.post_status = 'publish'";
112
- }
113
-
114
- // Add days old constraint
115
- if ( $this->config->days_old ) {
116
- $query[ ] = 'AND p.post_date > %s';
117
- $parameters[ ] = date( 'Y-m-d', strtotime( '-' . $this->config->days_old . ' days' ) );
118
- }
119
-
120
- // Add taxonomy statement
121
- $taxonomy_parameters = array();
122
-
123
- foreach ( $this->config->taxonomy as $taxonomy ) {
124
- $taxonomy_parameters[ ] = '%s';
125
- $parameters[ ] = $taxonomy;
126
- }
127
-
128
- $query[ ] = 'WHERE tt.taxonomy IN (' . join( ',', $taxonomy_parameters ) . ')';
129
-
130
- // Add include or exclude statement
131
- if ( $this->config->tags_list ) {
132
- $tags_list_parameters = array();
133
-
134
- foreach ( $this->config->tags_list as $tag_id ) {
135
- if ( $this->plugin->check_term_taxonomy( $tag_id, $this->config->taxonomy ) ) {
136
- $tags_list_parameters[ ] = '%d';
137
- $parameters[ ] = $tag_id;
138
- }
139
- }
140
-
141
- if ( $tags_list_parameters ) {
142
- $tags_list_operator = $this->config->tags_list_type == 'include' ? 'IN' : 'NOT IN';
143
- $query[ ] = 'AND t.term_id ' . $tags_list_operator . ' (' . join( ',', $tags_list_parameters ) . ')';
144
- }
145
- }
146
-
147
- $query[ ] = 'GROUP BY tr.term_taxonomy_id';
148
-
149
- // Add minimum constraint
150
- if ( $this->config->minimum ) {
151
- $query[ ] = 'HAVING count >= %d';
152
- $parameters[ ] = $this->config->minimum;
153
- }
154
-
155
- // Always sort the result by count DESC to always work with the top result
156
- $query[ ] = 'ORDER BY count DESC';
157
-
158
- // Add limit constraint
159
- $query[ ] = 'LIMIT %d';
160
- $parameters[ ] = $this->config->max;
161
-
162
- // If the result should be ordered in another way, try to create a sub-query to sort the result
163
- // directly in the database query
164
- $subquery_required = true;
165
-
166
- // No subquery is needed if the order should be by count desc (it's already sorted that way)
167
- if ( $this->config->reverse && $this->config->order == 'count' ) {
168
- $subquery_required = false;
169
- }
170
-
171
- // No subquery is needed if the order should be by color since the sorting is done in PHP afterwards
172
- if ( $this->config->order == 'color' ) {
173
- $subquery_required = false;
174
- }
175
-
176
- if ( $subquery_required ) {
177
- array_unshift( $query, 'SELECT * FROM (' );
178
- $query[ ] = ') AS subQuery';
179
-
180
- $order = $this->config->reverse ? 'DESC' : 'ASC';
181
- $binary = $this->config->case_sensitive ? 'BINARY ' : '';
182
-
183
- switch ( $this->config->order ) {
184
- case 'random':
185
- $query[ ] = 'ORDER BY RAND() ' . $order;
186
- break;
187
-
188
- case 'name':
189
- $query[ ] = 'ORDER BY ' . $binary . 'name ' . $order;
190
- break;
191
-
192
- case 'slug':
193
- $query[ ] = 'ORDER BY ' . $binary . 'slug ' . $order;
194
- break;
195
-
196
- case 'id':
197
- $query[ ] = 'ORDER BY term_id ' . $order;
198
- break;
199
-
200
- case 'count':
201
- $query[ ] = 'ORDER BY count ' . $order;
202
- break;
203
- }
204
- }
205
-
206
- // Build query
207
- $query = join( "\n", $query );
208
- $query = $this->db->prepare( $query, $parameters );
209
-
210
- // Fetch terms from DB
211
- $result = $this->db->get_results( $query );
212
- $this->query = $this->db->last_query;
213
- $terms = array();
214
-
215
- // Calculate sizes
216
- $min_count = PHP_INT_MAX;
217
- $max_count = 0;
218
-
219
- foreach ( $result as $item ) {
220
- if ( $item->count < $min_count ) {
221
- $min_count = $item->count;
222
- }
223
-
224
- if ( $item->count > $max_count ) {
225
- $max_count = $item->count;
226
- }
227
-
228
- $terms[ ] = new UTCW_Term( $item, $this->plugin );
229
- }
230
-
231
- $size_from = floatval( $this->config->size_from );
232
- $size_to = floatval( $this->config->size_to );
233
- $unit = preg_replace( '/' . UTCW_DECIMAL_REGEX . '/', '', $this->config->size_from );
234
-
235
- $font_step = $this->calc_step( $min_count, $max_count, $size_from, $size_to );
236
-
237
- foreach ( $terms as $term ) {
238
- $term->size = $this->calc_size( $size_from, $term->count, $min_count, $font_step ) . $unit;
239
- }
240
-
241
- // Set colors
242
- switch ( $this->config->color ) {
243
- case 'random':
244
- foreach ( $terms as $term ) {
245
- $term->color = sprintf( UTCW_HEX_COLOR_FORMAT, rand() % 255, rand() % 255, rand() % 255 );
246
- }
247
- break;
248
-
249
- case 'set':
250
- if ( $this->config->color_set ) {
251
- foreach ( $terms as $term ) {
252
- $term->color = $this->config->color_set[ array_rand( $this->config->color_set ) ];
253
- }
254
- }
255
- break;
256
-
257
- case 'span':
258
- if ( $this->config->color_span_from && $this->config->color_span_to ) {
259
- preg_match_all( '/[0-9a-f]{2}/i', $this->config->color_span_from, $cf_rgb_matches );
260
- list( $red_from, $green_from, $blue_from ) = array_map( 'hexdec', $cf_rgb_matches[ 0 ] );
261
-
262
- preg_match_all( '/[0-9a-f]{2}/i', $this->config->color_span_to, $ct_rgb_matches );
263
- list( $red_to, $green_to, $blue_to ) = array_map( 'hexdec', $ct_rgb_matches[ 0 ] );
264
-
265
- $colors = new stdClass;
266
- $colors->red_from = $red_from;
267
- $colors->red_to = $red_to;
268
- $colors->green_from = $green_from;
269
- $colors->green_to = $green_to;
270
- $colors->blue_from = $blue_from;
271
- $colors->blue_to = $blue_to;
272
-
273
- foreach ( $terms as $term ) {
274
- $term->color = $this->calc_color( $min_count, $max_count, $colors, $term->count );
275
- }
276
- }
277
- }
278
-
279
- // Last order by color if selected, this is the only order which can't be done in the DB
280
- if ( $this->config->order == 'color' ) {
281
- // Change the argument order to change the sort order
282
- $sort_fn_arguments = $this->config->reverse ? '$b,$a' : '$a,$b';
283
-
284
- // There's no difference in sortin case sensitive or case in-sensitive since
285
- // the colors are always lower case and internally generated
286
-
287
- $sort_fn = create_function( $sort_fn_arguments, 'return strcmp( $a->color, $b->color );' );
288
-
289
- usort( $terms, $sort_fn );
290
- }
291
-
292
- return $terms;
293
- }
294
-
295
- /**
296
- * Calculate term color
297
- *
298
- * @param int $min_count Min count of all the terms
299
- * @param int $max_count Max count of all the terms
300
- * @param stdClass $colors Object with red/green/blue_from/to properties
301
- * @param int $count Count of current term
302
- *
303
- * @return string
304
- * @since 2.0
305
- */
306
- private function calc_color( $min_count, $max_count, stdClass $colors, $count ) {
307
- $red_step = $this->calc_step( $min_count, $max_count, $colors->red_from, $colors->red_to );
308
- $green_step = $this->calc_step( $min_count, $max_count, $colors->green_from, $colors->green_to );
309
- $blue_step = $this->calc_step( $min_count, $max_count, $colors->blue_from, $colors->blue_to );
310
-
311
- $red = $this->calc_size( $colors->red_from, $count, $min_count, $red_step );
312
- $green = $this->calc_size( $colors->green_from, $count, $min_count, $green_step );
313
- $blue = $this->calc_size( $colors->blue_from, $count, $min_count, $blue_step );
314
-
315
- $color = sprintf( UTCW_HEX_COLOR_FORMAT, $red, $green, $blue );
316
-
317
- return $color;
318
- }
319
-
320
- /**
321
- * Calculate term size
322
- *
323
- * @param int $size_from Configured min size
324
- * @param int $count Current count
325
- * @param int $min_count Configured max count
326
- * @param int $font_step Calculated step
327
- *
328
- * @return int
329
- * @since 2.0
330
- */
331
- private function calc_size( $size_from, $count, $min_count, $font_step ) {
332
- return $size_from + ( ( $count - $min_count ) * $font_step );
333
- }
334
-
335
- /**
336
- * Calculate step size
337
- *
338
- * @param int $min Minimum count
339
- * @param int $max Maximum count
340
- * @param int $from Minimum size
341
- * @param int $to Maximum size
342
- *
343
- * @return int
344
- * @since 2.0
345
- */
346
- private function calc_step( $min, $max, $from, $to ) {
347
- if ( $min === $max ) {
348
- return 0;
349
- }
350
-
351
- $spread = $max - $min;
352
- $font_spread = $to - $from;
353
- $step = $font_spread / $spread;
354
-
355
- return $step;
356
- }
357
-
358
- /**
359
- * Cleans up sensitive data before being used in debug output
360
- */
361
- public function cleanup_for_debug() {
362
- unset( $this->db );
363
- }
364
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
utcw-render.php DELETED
@@ -1,288 +0,0 @@
1
- <?php
2
- /**
3
- * Ultimate Tag Cloud Widget
4
- * @author Rickard Andersson <rickard@0x539.se>
5
- * @version 2.1
6
- * @license GPLv2
7
- * @package utcw
8
- * @subpackage main
9
- * @since 2.0
10
- */
11
- if ( ! defined( 'ABSPATH' ) ) die();
12
-
13
- /**
14
- * Class for rendering the cloud
15
- *
16
- * @since 2.0
17
- * @package utcw
18
- * @subpackage main
19
- */
20
- class UTCW_Render {
21
-
22
- /**
23
- * Reference to the Data class which contains the data to be rendered
24
- *
25
- * @var UTCW_Data
26
- * @since 2.0
27
- */
28
- private $data;
29
-
30
- /**
31
- * Reference to the current configuration
32
- *
33
- * @var UTCW_Config
34
- * @since 2.0
35
- */
36
- private $config;
37
-
38
- /**
39
- * Reference to the main plugin instance
40
- *
41
- * @var UTCW_Plugin
42
- * @since 2.0
43
- */
44
- private $plugin;
45
-
46
- /**
47
- * Unique ID for this widget configuration
48
- *
49
- * @var int
50
- * @since 2.0
51
- */
52
- private $id;
53
-
54
- /**
55
- * CSS styles for this widget instance
56
- *
57
- * @var string
58
- * @since 2.0
59
- */
60
- private $css = '';
61
-
62
- /**
63
- * Creates a new instance of the renderer
64
- *
65
- * @param UTCW_Config $config Configuration
66
- * @param UTCW_Data $data Term data
67
- * @param UTCW_Plugin $plugin Main plugin instance
68
- *
69
- * @since 2.0
70
- */
71
- public function __construct( UTCW_Config $config, UTCW_Data $data, UTCW_Plugin $plugin ) {
72
- $this->data = $data;
73
- $this->config = $config;
74
- $this->plugin = $plugin;
75
- $this->id = base_convert( crc32( serialize( $config ) ), 10, 27 );
76
-
77
- $this->build_css();
78
- }
79
-
80
- /**
81
- * Renders the cloud as output
82
- *
83
- * @since 2.0
84
- */
85
- public function render() {
86
- echo $this->get_cloud();
87
- }
88
-
89
- /**
90
- * Returns the cloud as a string
91
- *
92
- * @return string
93
- * @since 2.0
94
- */
95
- public function get_cloud() {
96
- $markup = array();
97
-
98
- if ( $this->css ) {
99
- $markup[ ] = $this->css;
100
- }
101
-
102
- if ( $this->config->before_widget ) {
103
- $markup[ ] = $this->config->before_widget;
104
- }
105
-
106
- if ( $this->config->show_title_text ) {
107
- if ( $this->config->before_title ) {
108
- $markup[ ] = $this->config->before_title;
109
- }
110
-
111
- $markup[ ] = $this->plugin->apply_filters( 'widget_title', $this->config->title );
112
-
113
- if ( $this->config->after_title ) {
114
- $markup[ ] = $this->config->after_title;
115
- }
116
- }
117
-
118
- $markup[ ] = '<div class="widget_tag_cloud utcw-' . $this->id . '">';
119
-
120
- $terms = array();
121
-
122
- foreach ( $this->data->get_terms() as $term ) {
123
- $color = $term->color ? ';color:' . $term->color : '';
124
- $title = $this->config->show_title ? sprintf( ' title="' . _n( '%s topic', '%s topics', $term->count ) . '"', $term->count ) : '';
125
-
126
- $terms[ ] = sprintf(
127
- '%s<a class="tag-link-%s" href="%s" style="font-size:%s%s"%s>%s</a>%s',
128
- $this->config->prefix,
129
- $term->term_id,
130
- $term->link,
131
- $term->size,
132
- $color,
133
- $title,
134
- $term->name,
135
- $this->config->suffix
136
- );
137
- }
138
-
139
- $markup[ ] = join( $this->config->separator, $terms );
140
-
141
- $markup[ ] = '</div>';
142
-
143
- if ( $this->config->debug ) {
144
- $debug_object = clone $this->data;
145
- $debug_object->cleanup_for_debug();
146
- $markup[ ] = sprintf( "<!-- Ultimate Tag Cloud Debug information:\n%s -->", print_r( $debug_object, true ) );
147
- }
148
-
149
- if ( $this->config->after_widget ) {
150
- $markup[ ] = $this->config->after_widget;
151
- }
152
-
153
- return join( '', $markup );
154
- }
155
-
156
- /**
157
- * Builds the CSS needed to properly style the cloud
158
- *
159
- * @since 2.0
160
- */
161
- private function build_css() {
162
- $main_styles = array( 'word-wrap:break-word' );
163
-
164
- if ( ! $this->has_default_value( 'text_transform' ) ) {
165
- $main_styles[ ] = sprintf( 'text-transform:%s', $this->config->text_transform );
166
- }
167
-
168
- if ( ! $this->has_default_value( 'letter_spacing' ) ) {
169
- $main_styles[ ] = sprintf( 'letter-spacing:%s', $this->config->letter_spacing );
170
- }
171
-
172
- if ( ! $this->has_default_value( 'word_spacing' ) ) {
173
- $main_styles[ ] = sprintf( 'word-spacing:%s', $this->config->word_spacing );
174
- }
175
-
176
- $link_styles = array();
177
-
178
- if ( ! $this->has_default_value( 'link_underline' ) ) {
179
- $link_styles[ ] = sprintf( 'text-decoration:%s', $this->config->link_underline === 'yes' ? 'underline' : 'none' );
180
- }
181
-
182
- if ( ! $this->has_default_value( 'link_bold' ) ) {
183
- $link_styles[ ] = sprintf( 'font-weight:%s', $this->config->link_bold === 'yes' ? 'bold' : 'normal' );
184
- }
185
-
186
- if ( ! $this->has_default_value( 'link_italic' ) ) {
187
- $link_styles[ ] = sprintf( 'font-style:%s', $this->config->link_italic === 'yes' ? 'italic' : 'normal' );
188
- }
189
-
190
- if ( ! $this->has_default_value( 'link_bg_color' ) ) {
191
- $link_styles[ ] = sprintf( 'background-color:%s', $this->config->link_bg_color );
192
- }
193
-
194
- if ( ! $this->has_default_value( 'link_border_style' ) && ! $this->has_default_value( 'link_border_color' ) && ! $this->has_default_value( 'link_border_width' ) ) {
195
- $link_styles[ ] = sprintf( 'border:%s %s %s', $this->config->link_border_style, $this->config->link_border_width, $this->config->link_border_color );
196
- } else {
197
- if ( ! $this->has_default_value( 'link_border_style' ) ) {
198
- $link_styles[ ] = sprintf( 'border-style:%s', $this->config->link_border_style );
199
- }
200
-
201
- if ( ! $this->has_default_value( 'link_border_color' ) ) {
202
- $link_styles[ ] = sprintf( 'border-color:%s', $this->config->link_border_color );
203
- }
204
-
205
- if ( ! $this->has_default_value( 'link_border_width' ) ) {
206
- $link_styles[ ] = sprintf( 'border-width:%s', $this->config->link_border_width );
207
- }
208
- }
209
-
210
- if ( ! $this->has_default_value( 'tag_spacing' ) ) {
211
- $link_styles[ ] = sprintf( 'margin-right:%s', $this->config->tag_spacing );
212
- }
213
-
214
- if ( ! $this->has_default_value( 'line_height' ) ) {
215
- $link_styles[ ] = sprintf( 'line-height:%s', $this->config->line_height );
216
- }
217
-
218
- $hover_styles = array();
219
-
220
- if ( ! $this->has_default_value( 'hover_underline' ) ) {
221
- $hover_styles[ ] = sprintf( 'text-decoration:%s', $this->config->hover_underline === 'yes' ? 'underline' : 'none' );
222
- }
223
-
224
- if ( ! $this->has_default_value( 'hover_bold' ) ) {
225
- $hover_styles[ ] = sprintf( 'font-weight:%s', $this->config->hover_bold === 'yes' ? 'bold' : 'normal' );
226
- }
227
-
228
- if ( ! $this->has_default_value( 'hover_italic' ) ) {
229
- $hover_styles[ ] = sprintf( 'font-style:%s', $this->config->hover_italic === 'yes' ? 'italic' : 'normal' );
230
- }
231
-
232
- if ( ! $this->has_default_value( 'hover_bg_color' ) ) {
233
- $hover_styles[ ] = sprintf( 'background-color:%s', $this->config->hover_bg_color );
234
- }
235
-
236
-
237
- if ( ! $this->has_default_value( 'hover_border_style' ) && ! $this->has_default_value( 'hover_border_color' ) && ! $this->has_default_value( 'hover_border_width' ) ) {
238
- $hover_styles[ ] = sprintf( 'border:%s %s %s', $this->config->hover_border_style, $this->config->hover_border_width, $this->config->hover_border_color );
239
- } else {
240
- if ( ! $this->has_default_value( 'hover_border_style' ) ) {
241
- $hover_styles[ ] = sprintf( 'border-style:%s', $this->config->hover_border_style );
242
- }
243
-
244
- if ( ! $this->has_default_value( 'hover_border_color' ) ) {
245
- $hover_styles[ ] = sprintf( 'border-color:%s', $this->config->hover_border_color );
246
- }
247
-
248
- if ( ! $this->has_default_value( 'hover_border_width' ) ) {
249
- $hover_styles[ ] = sprintf( 'border-width:%s', $this->config->hover_border_width );
250
- }
251
- }
252
-
253
- if ( ! $this->has_default_value( 'hover_color' ) ) {
254
- $hover_styles[ ] = sprintf( 'color:%s', $this->config->hover_color );
255
- }
256
-
257
- $styles = array();
258
-
259
- if ( $main_styles ) {
260
- $styles[ ] = sprintf( '.utcw-%s{%s}', $this->id, join( ';', $main_styles ) );
261
- }
262
-
263
- if ( $link_styles ) {
264
- $styles[ ] = sprintf( '.utcw-%s a{%s}', $this->id, join( ';', $link_styles ) );
265
- }
266
-
267
- if ( $hover_styles ) {
268
- $styles[ ] = sprintf( '.utcw-%s a:hover{%s}', $this->id, join( ';', $hover_styles ) );
269
- }
270
-
271
- if ( $styles ) {
272
- $this->css = sprintf( '<style type="text/css">%s</style>', join( '', $styles ) );
273
- }
274
- }
275
-
276
- /**
277
- * Checks if option still has the default value
278
- *
279
- * @param string $option
280
- *
281
- * @return bool
282
- * @since 2.0
283
- */
284
- private function has_default_value( $option ) {
285
- $defaults = $this->config->get_defaults();
286
- return $this->config->$option === $defaults[ $option ];
287
- }
288
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
utcw-term.php DELETED
@@ -1,124 +0,0 @@
1
- <?php
2
- /**
3
- * Ultimate Tag Cloud Widget
4
- * @author Rickard Andersson <rickard@0x539.se>
5
- * @version 2.1
6
- * @license GPLv2
7
- * @package utcw
8
- * @subpackage main
9
- * @since 2.0
10
- */
11
- if ( ! defined( 'ABSPATH' ) ) die();
12
-
13
- /**
14
- * Class to represent a term
15
- *
16
- * @since 2.0
17
- * @package utcw
18
- * @subpackage main
19
- */
20
- class UTCW_Term {
21
-
22
- /**
23
- * Term ID
24
- *
25
- * @var int
26
- * @since 2.0
27
- */
28
- public $term_id;
29
-
30
- /**
31
- * Number of posts
32
- *
33
- * @var int
34
- * @since 2.0
35
- */
36
- public $count;
37
-
38
- /**
39
- * Term slug
40
- *
41
- * @var string
42
- * @since 2.0
43
- */
44
- public $slug;
45
-
46
- /**
47
- * Term name
48
- *
49
- * @var string
50
- * @since 2.0
51
- */
52
- public $name;
53
-
54
- /**
55
- * Term link
56
- *
57
- * @var string
58
- * @since 2.0
59
- */
60
- public $link;
61
-
62
- /**
63
- * Term color
64
- *
65
- * @var string
66
- * @since 2.0
67
- */
68
- public $color;
69
-
70
- /**
71
- * Term taxonomy
72
- *
73
- * @var string
74
- * @since 2.0
75
- */
76
- public $taxonomy;
77
-
78
- /**
79
- * Term size
80
- *
81
- * @var float
82
- * @since 2.0
83
- */
84
- public $size;
85
-
86
- /**
87
- * Creates a new term
88
- *
89
- * @param stdClass $input Object with properties term_id, count, slug, name, color and taxonomy
90
- * @param UTCW_Plugin $plugin Reference to the plugin instance
91
- *
92
- * @since 2.0
93
- */
94
- function __construct( stdClass $input, UTCW_Plugin $plugin ) {
95
-
96
- if ( isset( $input->term_id ) && filter_var( $input->term_id, FILTER_VALIDATE_INT ) ) {
97
- $this->term_id = intval( $input->term_id );
98
- }
99
-
100
- if ( isset( $input->count ) && filter_var( $input->count, FILTER_VALIDATE_INT ) ) {
101
- $this->count = intval( $input->count );
102
- }
103
-
104
- if ( isset( $input->slug ) && strlen( $input->slug ) > 0 && preg_match( '/^[0-9a-z\-]+/i', $input->slug ) ) {
105
- $this->slug = $input->slug;
106
- }
107
-
108
- if ( isset( $input->name ) && strlen( $input->name ) > 0 ) {
109
- $this->name = $input->name;
110
- }
111
-
112
- if ( isset( $input->color ) && strlen( $input->color ) > 0 && preg_match( UTCW_HEX_COLOR_REGEX, $input->color ) ) {
113
- $this->color = $input->color;
114
- }
115
-
116
- if ( isset( $input->taxonomy ) && strlen( $input->taxonomy ) > 0 ) {
117
- $this->taxonomy = $input->taxonomy;
118
- }
119
-
120
- if ( $this->term_id && $this->taxonomy ) {
121
- $this->link = $plugin->get_term_link( $this->term_id, $this->taxonomy );
122
- }
123
- }
124
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
utcw-widget.php DELETED
@@ -1,133 +0,0 @@
1
- <?php
2
- /**
3
- * Ultimate Tag Cloud Widget
4
- * @author Rickard Andersson <rickard@0x539.se>
5
- * @version 2.1
6
- * @license GPLv2
7
- * @package utcw
8
- * @subpackage main
9
- * @since 2.0
10
- */
11
- if ( ! defined( 'ABSPATH' ) ) die();
12
-
13
- /**
14
- * Widget class for WordPress integration
15
- *
16
- * @since 1.0
17
- * @package utcw
18
- * @subpackage main
19
- */
20
- class UTCW extends WP_Widget {
21
-
22
- /**
23
- * Reference to the main plugin instance
24
- *
25
- * @var UTCW_Plugin
26
- * @since 2.0
27
- */
28
- private $plugin;
29
-
30
- /**
31
- * Constructor
32
- *
33
- * @param UTCW_Plugin $plugin Optional. Plugin instance for dependency injection
34
- *
35
- * @return UTCW
36
- * @since 1.0
37
- */
38
- function __construct( UTCW_Plugin $plugin = null ) {
39
- $options = array( 'description' => __( 'Highly configurable tag cloud', 'utcw' ) );
40
- parent::__construct( false, __( 'Ultimate Tag Cloud', 'utcw' ), $options );
41
-
42
- $this->plugin = $plugin ? $plugin : UTCW_Plugin::get_instance();
43
- }
44
-
45
- /**
46
- * Action handler for the form in the admin panel
47
- *
48
- * @param array $new_instance
49
- * @param array $old_instance
50
- *
51
- * @return array
52
- * @since 1.0
53
- */
54
- function update( array $new_instance, array $old_instance ) {
55
-
56
- // Overwrite the form values with the saved configuration
57
- if ( isset( $new_instance[ 'load_config' ] ) && isset( $new_instance[ 'load_config_name' ] ) && $new_instance[ 'load_config_name' ] ) {
58
- $loaded_configuration = $this->plugin->load_configuration( $new_instance[ 'load_config_name' ] );
59
-
60
- if ( $loaded_configuration ) {
61
- $new_instance = $loaded_configuration;
62
- }
63
- }
64
-
65
- // Checkbox inputs which are unchecked, will not be set in $new_instance. Set them manually to false
66
- $checkbox_settings = array( 'show_title_text', 'show_title', 'debug', 'reverse', 'case_sensitive' );
67
-
68
- foreach ( $checkbox_settings as $checkbox_setting ) {
69
- if ( ! isset( $new_instance[ $checkbox_setting ] ) ) {
70
- $new_instance[ $checkbox_setting ] = false;
71
- }
72
- }
73
-
74
- $config = new UTCW_Config( $new_instance, $this->plugin );
75
-
76
- if ( isset( $new_instance[ 'save_config' ] ) && isset( $new_instance[ 'save_config_name' ] ) && $new_instance[ 'save_config_name' ] ) {
77
- $this->plugin->save_configuration( $new_instance[ 'save_config_name' ], $config->get_instance() );
78
- }
79
-
80
- if ( isset( $new_instance[ 'remove_config' ] ) && is_array( $new_instance[ 'remove_config' ] ) ) {
81
- foreach ( $new_instance[ 'remove_config' ] as $configuration ) {
82
- $this->plugin->remove_configuration( $configuration );
83
- }
84
- }
85
-
86
- return $config->get_instance();
87
- }
88
-
89
- /**
90
- * Function for handling the widget control in admin panel
91
- *
92
- * @param array $instance
93
- *
94
- * @return void|string
95
- * @since 1.0
96
- */
97
- function form( array $instance ) {
98
- /** @noinspection PhpUnusedLocalVariableInspection */
99
- $config = new UTCW_Config( $instance, $this->plugin );
100
- /** @noinspection PhpUnusedLocalVariableInspection */
101
- $configurations = $this->plugin->get_configurations();
102
- /** @noinspection PhpUnusedLocalVariableInspection */
103
- $available_post_types = $this->plugin->get_allowed_post_types();
104
- /** @noinspection PhpUnusedLocalVariableInspection */
105
- $available_taxonomies = $this->plugin->get_allowed_taxonomies_objects();
106
- /** @noinspection PhpUnusedLocalVariableInspection */
107
- $users = $this->plugin->get_users();
108
- /** @noinspection PhpUnusedLocalVariableInspection */
109
- $terms = $this->plugin->get_terms();
110
-
111
- // Content of the widget settings form
112
- require 'pages/settings.php';
113
- }
114
-
115
- /**
116
- * Function for rendering the widget
117
- *
118
- * @param array $args
119
- *
120
- * @param array $instance
121
- */
122
- function widget( array $args, array $instance ) {
123
- global $wpdb;
124
-
125
- $input = array_merge( $instance, $args );
126
-
127
- $config = new UTCW_Config( $input, $this->plugin );
128
- $data = new UTCW_Data( $config, $this->plugin, $wpdb );
129
- $render = new UTCW_Render( $config, $data, $this->plugin );
130
-
131
- $render->render();
132
- }
133
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
utcw.php DELETED
@@ -1,377 +0,0 @@
1
- <?php
2
- /**
3
- * Ultimate Tag Cloud Widget
4
- * @author Rickard Andersson <rickard@0x539.se>
5
- * @version 2.1
6
- * @license GPLv2
7
- * @package utcw
8
- * @subpackage main
9
- * @since 2.0
10
- */
11
- if ( ! defined( 'ABSPATH' ) ) die();
12
-
13
- /**
14
- * Current version number
15
- *
16
- * @var string
17
- * @since 2.0
18
- */
19
- define( 'UTCW_VERSION', '2.1' );
20
-
21
- /**
22
- * If development mode is currently enabled
23
- *
24
- * @var bool
25
- * @since 2.0
26
- */
27
- define( 'UTCW_DEV', false );
28
-
29
- /**
30
- * Regular expression for matching hexadecimal colors
31
- *
32
- * @var string
33
- * @since 2.0
34
- */
35
- define( 'UTCW_HEX_COLOR_REGEX', '/#([a-f0-9]{6}|[a-f0-9]{3})/i' );
36
-
37
- /**
38
- * Regular expression for matching decimal numbers
39
- *
40
- * @var string
41
- * @since 2.1
42
- */
43
- define( 'UTCW_DECIMAL_REGEX', '\d+(\.\d+)?' );
44
-
45
- /**
46
- * printf format for rendering hexadecimal colors
47
- *
48
- * @var string
49
- * @since 2.0
50
- */
51
- define( 'UTCW_HEX_COLOR_FORMAT', '#%02x%02x%02x' );
52
-
53
- require_once 'utcw-config.php';
54
- require_once 'utcw-widget.php';
55
- require_once 'utcw-data.php';
56
- require_once 'utcw-render.php';
57
- require_once 'utcw-term.php';
58
-
59
- /**
60
- * Class for general plugin integration with WordPress
61
- *
62
- * @since 2.0
63
- * @package utcw
64
- * @subpackage main
65
- */
66
- class UTCW_Plugin {
67
-
68
- /**
69
- * An array of which taxonomies are available
70
- *
71
- * @var array
72
- * @since 2.0
73
- */
74
- protected $allowed_taxonomies = array();
75
-
76
- /**
77
- * An array of which post types are available
78
- *
79
- * @var array
80
- * @since 2.0
81
- */
82
- protected $allowed_post_types = array();
83
-
84
- /**
85
- * Singleton instance
86
- *
87
- * @var UTCW_Plugin
88
- * @since 2.0
89
- */
90
- private static $instance;
91
-
92
- /**
93
- * Initializes the WordPress hooks needed
94
- *
95
- * @todo Add tests that these hooks are set
96
- * @since 2.0
97
- */
98
- private function __construct() {
99
- add_action( 'admin_head-widgets.php', array( $this, 'init_admin_assets' ) );
100
- add_action( 'wp_loaded', array( $this, 'wp_loaded' ) );
101
- add_action( 'widgets_init', create_function( '', 'return register_widget("UTCW");' ) );
102
- add_shortcode( 'utcw', array( $this, 'utcw_shortcode' ) );
103
- }
104
-
105
- /**
106
- * Returns an instance of the plugin
107
- *
108
- * @static
109
- * @return UTCW_Plugin
110
- * @since 2.0
111
- */
112
- public static function get_instance() {
113
- if ( ! self::$instance ) {
114
- self::$instance = new self;
115
- }
116
-
117
- return self::$instance;
118
- }
119
-
120
- /**
121
- * Action handler for 'wp_loaded' hook
122
- * Loads taxonomies and post types
123
- *
124
- * @since 2.0
125
- */
126
- function wp_loaded() {
127
- $this->allowed_taxonomies = get_taxonomies();
128
- $this->allowed_post_types = get_post_types( array( 'public' => true ) );
129
- }
130
-
131
- /**
132
- * Shortcode handler for 'utcw' hook
133
- *
134
- * @param array $args
135
- *
136
- * @return string
137
- * @since 2.0
138
- */
139
- function utcw_shortcode( array $args ) {
140
- global $wpdb;
141
-
142
- $config = new UTCW_Config( $args, $this );
143
- $data = new UTCW_Data( $config, $this, $wpdb );
144
- $render = new UTCW_Render( $config, $data, $this );
145
-
146
- return $render->get_cloud();
147
- }
148
-
149
- /**
150
- * Action handler for 'admin_head-widgets.php' hook
151
- * Loads assets needed by the administration interface
152
- *
153
- * @since 2.0
154
- */
155
- public function init_admin_assets() {
156
- wp_enqueue_style( 'utcw-admin', plugins_url( 'ultimate-tag-cloud-widget/css/style.css' ), array(), UTCW_VERSION );
157
-
158
- // In development mode, add the libraries and main file individually
159
- if ( UTCW_DEV ) {
160
- wp_enqueue_script( 'utcw-lib-jsuri', plugins_url( 'ultimate-tag-cloud-widget/js/lib/jsuri-1.1.1.min.js' ), array(), UTCW_VERSION, true );
161
- wp_enqueue_script( 'utcw-lib-tooltip', plugins_url( 'ultimate-tag-cloud-widget/js/lib/tooltip.min.js' ), array( 'jquery' ), UTCW_VERSION, true );
162
- wp_enqueue_script( 'utcw', plugins_url( 'ultimate-tag-cloud-widget/js/utcw.js' ), array( 'utcw-lib-jsuri', 'utcw-lib-tooltip', 'jquery' ), UTCW_VERSION, true );
163
- } else {
164
- wp_enqueue_script( 'utcw', plugins_url( 'ultimate-tag-cloud-widget/js/utcw.min.js' ), array( 'jquery' ), UTCW_VERSION, true );
165
- }
166
- }
167
-
168
- /**
169
- * Returns an array with the names of allowed taxonomies
170
- *
171
- * @return array
172
- * @since 2.0
173
- */
174
- public function get_allowed_taxonomies() {
175
- return $this->allowed_taxonomies;
176
- }
177
-
178
- /**
179
- * Returns allowed taxonomies as objects
180
- *
181
- * @return array
182
- * @since 2.0
183
- */
184
- public function get_allowed_taxonomies_objects() {
185
- return get_taxonomies( array(), 'objects' );
186
- }
187
-
188
- /**
189
- * Returns an array with taxonomy as key and an array of term objects for each taxonomy. Like:
190
- *
191
- * @return array
192
- * @since 2.0
193
- */
194
- public function get_terms() {
195
- $terms = array();
196
-
197
- foreach ( $this->get_allowed_taxonomies() as $taxonomy ) {
198
- $terms[ $taxonomy ] = get_terms( $taxonomy );
199
- }
200
-
201
- return $terms;
202
- }
203
-
204
- /**
205
- * Returns an array with the names of allowed post types
206
- *
207
- * @return array
208
- * @since 2.0
209
- */
210
- public function get_allowed_post_types() {
211
- return $this->allowed_post_types;
212
- }
213
-
214
- /**
215
- * Returns the users on this blog
216
- *
217
- * @return array
218
- * @since 2.0
219
- */
220
- function get_users() {
221
- global $wp_version;
222
-
223
- if ( (float)$wp_version < 3.1 ) {
224
- return get_users_of_blog();
225
- } else {
226
- return get_users();
227
- }
228
- }
229
-
230
- /**
231
- * Removes a previously saved configuration
232
- *
233
- * @param string $name
234
- *
235
- * @return bool
236
- * @since 2.1
237
- */
238
- function remove_configuration( $name ) {
239
- $configs = $this->get_configurations();
240
-
241
- if ( isset( $configs[ $name ] ) ) {
242
- unset( $configs[ $name ] );
243
- return $this->set_configurations( $configs );
244
- }
245
-
246
- return false;
247
- }
248
-
249
- /**
250
- * Saves the configuration
251
- *
252
- * @param string $name Name of configuration
253
- * @param array $config Exported configuration from UTCW_Config
254
- *
255
- * @return bool
256
- * @since 2.0
257
- */
258
- function save_configuration( $name, array $config ) {
259
- $configs = $this->get_configurations();
260
- $configs[ $name ] = $config;
261
-
262
- return $this->set_configurations( $configs );
263
- }
264
-
265
- /**
266
- * Loads saved configuration
267
- *
268
- * @param string $name Name of configuration
269
- *
270
- * @return array|bool Returns an instance array on success and boolean false on failure
271
- * @since 2.0
272
- */
273
- function load_configuration( $name ) {
274
- $configs = $this->get_configurations();
275
-
276
- if ( isset( $configs[ $name ] ) ) {
277
- return $configs[ $name ];
278
- }
279
-
280
- return false;
281
- }
282
-
283
- /**
284
- * Get saved configurations
285
- *
286
- * @return array
287
- * @since 2.0
288
- */
289
- function get_configurations() {
290
- return get_option( 'utcw_saved_configs', array() );
291
- }
292
-
293
- /**
294
- * Set saved configurations
295
- *
296
- * @param array $configs
297
- *
298
- * @return bool
299
- * @since 2.1
300
- */
301
- protected function set_configurations( $configs ) {
302
- return update_option( 'utcw_saved_configs', $configs );
303
- }
304
-
305
- /**
306
- * Returns boolean true if the current page request is for an authenticated user
307
- *
308
- * @return bool
309
- * @since 2.0
310
- */
311
- public function is_authenticated_user() {
312
- return is_user_logged_in();
313
- }
314
-
315
- /**
316
- * Returns an absolute URI to the archive page for the term
317
- *
318
- * @param int $term_id Term ID
319
- * @param string $taxonomy Taxonomy name
320
- *
321
- * @return string Returns URI on success and empty string on failure
322
- * @since 2.0
323
- */
324
- public function get_term_link( $term_id, $taxonomy ) {
325
- $link = get_term_link( $term_id, $taxonomy );
326
-
327
- return ! is_wp_error( $link ) ? $link : '';
328
- }
329
-
330
- /**
331
- * Check if the term exist for any of the taxonomies
332
- *
333
- * @param int $term_id Term ID
334
- * @param array $taxonomy Array of taxonomy names
335
- *
336
- * @return bool
337
- * @since 2.0
338
- */
339
- public function check_term_taxonomy( $term_id, array $taxonomy ) {
340
-
341
- foreach ( $taxonomy as $tax ) {
342
- if ( get_term( $term_id, $tax ) ) {
343
- return true;
344
- }
345
- }
346
-
347
- return false;
348
- }
349
-
350
- /**
351
- * Apply filters
352
- *
353
- * @param string $tag
354
- * @param mixed $value
355
- *
356
- * @return mixed|void
357
- * @since 2.0
358
- */
359
- public function apply_filters( $tag, $value ) {
360
- return apply_filters( $tag, $value );
361
- }
362
- }
363
-
364
- // Instantiates the plugin
365
- UTCW_Plugin::get_instance();
366
-
367
- /**
368
- * Function for theme integration
369
- *
370
- * @param array $args
371
- *
372
- * @since 1.3
373
- */
374
- function do_utcw( array $args ) {
375
- $plugin = UTCW_Plugin::get_instance();
376
- echo $plugin->utcw_shortcode( $args );
377
- }