/,'');o.content=o.content.replace(/<\/pre>\s*$/,'');if(o.set)o.content=''+o.content+' ';});}if(s.verify_css_classes){t.serializer.attribValueFilter=function(n,v){var s,cl;if(n=='class'){if(!t.classesRE){cl=t.dom.getClasses();if(cl.length>0){s='';each(cl,function(o){s+=(s?'|':'')+o['class'];});t.classesRE=new RegExp('('+s+')','gi');}}return!t.classesRE||/(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v)||t.classesRE.test(v)?v:'';}return v;};}if(s.convert_fonts_to_spans)t._convertFonts();if(s.inline_styles)t._convertInlineElements();if(s.cleanup_callback){t.onBeforeSetContent.add(function(ed,o){o.content=t.execCallback('cleanup_callback','insert_to_editor',o.content,o);});t.onPreProcess.add(function(ed,o){if(o.set)t.execCallback('cleanup_callback','insert_to_editor_dom',o.node,o);if(o.get)t.execCallback('cleanup_callback','get_from_editor_dom',o.node,o);});t.onPostProcess.add(function(ed,o){if(o.set)o.content=t.execCallback('cleanup_callback','insert_to_editor',o.content,o);if(o.get)o.content=t.execCallback('cleanup_callback','get_from_editor',o.content,o);});}if(s.save_callback){t.onGetContent.add(function(ed,o){if(o.save)o.content=t.execCallback('save_callback',t.id,o.content,t.getBody());});}if(s.handle_event_callback){t.onEvent.add(function(ed,e,o){if(t.execCallback('handle_event_callback',e,ed,o)===false)Event.cancel(e);});}t.onSetContent.add(function(){t.addVisual(t.getBody());});if(s.padd_empty_editor){t.onPostProcess.add(function(ed,o){o.content=o.content.replace(/^(]*>( | |\s|\u00a0|)<\/p>[\r\n]*| [\r\n]*)$/,'');});}if(isGecko&&!s.readonly){try{d.designMode='Off';d.designMode='On';}catch(ex){}}setTimeout(function(){if(t.removed)return;t.load({initial:true,format:(s.cleanup_on_startup?'html':'raw')});t.startContent=t.getContent({format:'raw'});t.undoManager.add({initial:true});t.initialized=true;t.onInit.dispatch(t);t.execCallback('setupcontent_callback',t.id,t.getBody(),t.getDoc());t.execCallback('init_instance_callback',t);t.focus(true);t.nodeChanged({initial:1});if(s.content_css){tinymce.each(explode(s.content_css),function(u){t.dom.loadCSS(t.documentBaseURI.toAbsolute(u));});}if(s.auto_focus){setTimeout(function(){var ed=EditorManager.get(s.auto_focus);ed.selection.select(ed.getBody(),1);ed.selection.collapse(1);ed.getWin().focus();},100);}},1);e=null;},focus:function(sf){var oed,t=this,ce=t.settings.content_editable;if(!sf){if(!ce&&(!isIE||t.selection.getNode().ownerDocument!=t.getDoc()))t.getWin().focus();}if(EditorManager.activeEditor!=t){if((oed=EditorManager.activeEditor)!=null)oed.onDeactivate.dispatch(oed,t);t.onActivate.dispatch(t,oed);}EditorManager._setActive(t);},execCallback:function(n){var t=this,f=t.settings[n],s;if(!f)return;if(t.callbackLookup&&(s=t.callbackLookup[n])){f=s.func;s=s.scope;}if(is(f,'string')){s=f.replace(/\.\w+$/,'');s=s?tinymce.resolve(s):0;f=tinymce.resolve(f);t.callbackLookup=t.callbackLookup||{};t.callbackLookup[n]={func:f,scope:s};}return f.apply(s||t,Array.prototype.slice.call(arguments,1));},translate:function(s){var c=this.settings.language||'en',i18n=EditorManager.i18n;if(!s)return'';return i18n[c+'.'+s]||s.replace(/{\#([^}]+)\}/g,function(a,b){return i18n[c+'.'+b]||'{#'+b+'}';});},getLang:function(n,dv){return EditorManager.i18n[(this.settings.language||'en')+'.'+n]||(is(dv)?dv:'{#'+n+'}');},getParam:function(n,dv,ty){var tr=tinymce.trim,v=is(this.settings[n])?this.settings[n]:dv,o;if(ty==='hash'){o={};if(is(v,'string')){each(v.indexOf('=')>0?v.split(/[;,](?![^=;,]*(?:[;,]|$))/):v.split(','),function(v){v=v.split('=');if(v.length>1)o[tr(v[0])]=tr(v[1]);else o[tr(v[0])]=tr(v);});}else o=v;return o;}return v;},nodeChanged:function(o){var t=this,s=t.selection,n=s.getNode()||t.getBody();if(t.initialized){t.onNodeChange.dispatch(t,o?o.controlManager||t.controlManager:t.controlManager,isIE&&n.ownerDocument!=t.getDoc()?t.getBody():n,s.isCollapsed(),o);}},addButton:function(n,s){var t=this;t.buttons=t.buttons||{};t.buttons[n]=s;},addCommand:function(n,f,s){this.execCommands[n]={func:f,scope:s||this};},addQueryStateHandler:function(n,f,s){this.queryStateCommands[n]={func:f,scope:s||this};},addQueryValueHandler:function(n,f,s){this.queryValueCommands[n]={func:f,scope:s||this};},addShortcut:function(pa,desc,cmd_func,sc){var t=this,c;if(!t.settings.custom_shortcuts)return false;t.shortcuts=t.shortcuts||{};if(is(cmd_func,'string')){c=cmd_func;cmd_func=function(){t.execCommand(c,false,null);};}if(is(cmd_func,'object')){c=cmd_func;cmd_func=function(){t.execCommand(c[0],c[1],c[2]);};}each(explode(pa),function(pa){var o={func:cmd_func,scope:sc||this,desc:desc,alt:false,ctrl:false,shift:false};each(explode(pa,'+'),function(v){switch(v){case'alt':case'ctrl':case'shift':o[v]=true;break;default:o.charCode=v.charCodeAt(0);o.keyCode=v.toUpperCase().charCodeAt(0);}});t.shortcuts[(o.ctrl?'ctrl':'')+','+(o.alt?'alt':'')+','+(o.shift?'shift':'')+','+o.keyCode]=o;});return true;},execCommand:function(cmd,ui,val,a){var t=this,s=0,o,st;if(!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd)&&(!a||!a.skip_focus))t.focus();o={};t.onBeforeExecCommand.dispatch(t,cmd,ui,val,o);if(o.terminate)return false;if(t.execCallback('execcommand_callback',t.id,t.selection.getNode(),cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);return true;}if(o=t.execCommands[cmd]){st=o.func.call(o.scope,ui,val);if(st!==true){t.onExecCommand.dispatch(t,cmd,ui,val,a);return st;}}each(t.plugins,function(p){if(p.execCommand&&p.execCommand(cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);s=1;return false;}});if(s)return true;if(t.theme.execCommand&&t.theme.execCommand(cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);return true;}if(t.editorCommands.execCommand(cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);return true;}t.getDoc().execCommand(cmd,ui,val);t.onExecCommand.dispatch(t,cmd,ui,val,a);},queryCommandState:function(c){var t=this,o,s;if(t._isHidden())return;if(o=t.queryStateCommands[c]){s=o.func.call(o.scope);if(s!==true)return s;}o=t.editorCommands.queryCommandState(c);if(o!==-1)return o;try{return this.getDoc().queryCommandState(c);}catch(ex){}},queryCommandValue:function(c){var t=this,o,s;if(t._isHidden())return;if(o=t.queryValueCommands[c]){s=o.func.call(o.scope);if(s!==true)return s;}o=t.editorCommands.queryCommandValue(c);if(is(o))return o;try{return this.getDoc().queryCommandValue(c);}catch(ex){}},show:function(){var t=this;DOM.show(t.getContainer());DOM.hide(t.id);t.load();},hide:function(){var t=this,d=t.getDoc();if(isIE&&d)d.execCommand('SelectAll');t.save();DOM.hide(t.getContainer());DOM.setStyle(t.id,'display',t.orgDisplay);},isHidden:function(){return!DOM.isHidden(this.id);},setProgressState:function(b,ti,o){this.onSetProgressState.dispatch(this,b,ti,o);return b;},resizeToContent:function(){var t=this;DOM.setStyle(t.id+"_ifr",'height',t.getBody().scrollHeight);},load:function(o){var t=this,e=t.getElement(),h;if(e){o=o||{};o.load=true;h=t.setContent(is(e.value)?e.value:e.innerHTML,o);o.element=e;if(!o.no_events)t.onLoadContent.dispatch(t,o);o.element=e=null;return h;}},save:function(o){var t=this,e=t.getElement(),h,f;if(!e||!t.initialized)return;o=o||{};o.save=true;if(!o.no_events){t.undoManager.typing=0;t.undoManager.add();}o.element=e;h=o.content=t.getContent(o);if(!o.no_events)t.onSaveContent.dispatch(t,o);h=o.content;if(!/TEXTAREA|INPUT/i.test(e.nodeName)){e.innerHTML=h;if(f=DOM.getParent(t.id,'form')){each(f.elements,function(e){if(e.name==t.id){e.value=h;return false;}});}}else e.value=h;o.element=e=null;return h;},setContent:function(h,o){var t=this;o=o||{};o.format=o.format||'html';o.set=true;o.content=h;if(!o.no_events)t.onBeforeSetContent.dispatch(t,o);if(!tinymce.isIE&&(h.length===0||/^\s+$/.test(h))){o.content=t.dom.setHTML(t.getBody(),' ');o.format='raw';}o.content=t.dom.setHTML(t.getBody(),tinymce.trim(o.content));if(o.format!='raw'&&t.settings.cleanup){o.getInner=true;o.content=t.dom.setHTML(t.getBody(),t.serializer.serialize(t.getBody(),o));}if(!o.no_events)t.onSetContent.dispatch(t,o);return o.content;},getContent:function(o){var t=this,h;o=o||{};o.format=o.format||'html';o.get=true;if(!o.no_events)t.onBeforeGetContent.dispatch(t,o);if(o.format!='raw'&&t.settings.cleanup){o.getInner=true;h=t.serializer.serialize(t.getBody(),o);}else h=t.getBody().innerHTML;h=h.replace(/^\s*|\s*$/g,'');o.content=h;if(!o.no_events)t.onGetContent.dispatch(t,o);return o.content;},isDirty:function(){var t=this;return tinymce.trim(t.startContent)!=tinymce.trim(t.getContent({format:'raw',no_events:1}))&&!t.isNotDirty;},getContainer:function(){var t=this;if(!t.container)t.container=DOM.get(t.editorContainer||t.id+'_parent');return t.container;},getContentAreaContainer:function(){return this.contentAreaContainer;},getElement:function(){return DOM.get(this.settings.content_element||this.id);},getWin:function(){var t=this,e;if(!t.contentWindow){e=DOM.get(t.id+"_ifr");if(e)t.contentWindow=e.contentWindow;}return t.contentWindow;},getDoc:function(){var t=this,w;if(!t.contentDocument){w=t.getWin();if(w)t.contentDocument=w.document;}return t.contentDocument;},getBody:function(){return this.bodyElement||this.getDoc().body;},convertURL:function(u,n,e){var t=this,s=t.settings;if(s.urlconverter_callback)return t.execCallback('urlconverter_callback',u,e,true,n);if(!s.convert_urls||(e&&e.nodeName=='LINK')||u.indexOf('file:')===0)return u;if(s.relative_urls)return t.documentBaseURI.toRelative(u);u=t.documentBaseURI.toAbsolute(u,s.remove_script_host);return u;},addVisual:function(e){var t=this,s=t.settings;e=e||t.getBody();if(!is(t.hasVisual))t.hasVisual=s.visual;each(t.dom.select('table,a',e),function(e){var v;switch(e.nodeName){case'TABLE':v=t.dom.getAttrib(e,'border');if(!v||v=='0'){if(t.hasVisual)t.dom.addClass(e,s.visual_table_class);else t.dom.removeClass(e,s.visual_table_class);}return;case'A':v=t.dom.getAttrib(e,'name');if(v){if(t.hasVisual)t.dom.addClass(e,'mceItemAnchor');else t.dom.removeClass(e,'mceItemAnchor');}return;}});t.onVisualAid.dispatch(t,e,t.hasVisual);},remove:function(){var t=this,e=t.getContainer();t.removed=1;t.hide();t.execCallback('remove_instance_callback',t);t.onRemove.dispatch(t);t.onExecCommand.listeners=[];EditorManager.remove(t);DOM.remove(e);},destroy:function(s){var t=this;if(t.destroyed)return;if(!s){tinymce.removeUnload(t.destroy);tinyMCE.onBeforeUnload.remove(t._beforeUnload);if(t.theme.destroy)t.theme.destroy();t.controlManager.destroy();t.selection.destroy();t.dom.destroy();if(!t.settings.content_editable){Event.clear(t.getWin());Event.clear(t.getDoc());}Event.clear(t.getBody());Event.clear(t.formElement);}if(t.formElement){t.formElement.submit=t.formElement._mceOldSubmit;t.formElement._mceOldSubmit=null;}t.contentAreaContainer=t.formElement=t.container=t.settings.content_element=t.bodyElement=t.contentDocument=t.contentWindow=null;if(t.selection)t.selection=t.selection.win=t.selection.dom=t.selection.dom.doc=null;t.destroyed=1;},_addEvents:function(){var t=this,i,s=t.settings,lo={mouseup:'onMouseUp',mousedown:'onMouseDown',click:'onClick',keyup:'onKeyUp',keydown:'onKeyDown',keypress:'onKeyPress',submit:'onSubmit',reset:'onReset',contextmenu:'onContextMenu',dblclick:'onDblClick',paste:'onPaste'};function eventHandler(e,o){var ty=e.type;if(t.removed)return;if(t.onEvent.dispatch(t,e,o)!==false){t[lo[e.fakeType||e.type]].dispatch(t,e,o);}};each(lo,function(v,k){switch(k){case'contextmenu':if(tinymce.isOpera){Event.add(t.getBody(),'mousedown',function(e){if(e.ctrlKey){e.fakeType='contextmenu';eventHandler(e);}});}else Event.add(t.getBody(),k,eventHandler);break;case'paste':Event.add(t.getBody(),k,function(e){var tx,h,el,r;if(e.clipboardData)tx=e.clipboardData.getData('text/plain');else if(tinymce.isIE)tx=t.getWin().clipboardData.getData('Text');eventHandler(e,{text:tx,html:h});});break;case'submit':case'reset':Event.add(t.getElement().form||DOM.getParent(t.id,'form'),k,eventHandler);break;default:Event.add(s.content_editable?t.getBody():t.getDoc(),k,eventHandler);}});Event.add(s.content_editable?t.getBody():(isGecko?t.getDoc():t.getWin()),'focus',function(e){t.focus(true);});if(tinymce.isGecko){Event.add(t.getDoc(),'DOMNodeInserted',function(e){var v;e=e.target;if(e.nodeType===1&&e.nodeName==='IMG'&&(v=e.getAttribute('mce_src')))e.src=t.documentBaseURI.toAbsolute(v);});}if(isGecko){function setOpts(){var t=this,d=t.getDoc(),s=t.settings;if(isGecko&&!s.readonly){if(t._isHidden()){try{if(!s.content_editable)d.designMode='On';}catch(ex){}}try{d.execCommand("styleWithCSS",0,false);}catch(ex){if(!t._isHidden())try{d.execCommand("useCSS",0,true);}catch(ex){}}if(!s.table_inline_editing)try{d.execCommand('enableInlineTableEditing',false,false);}catch(ex){}if(!s.object_resizing)try{d.execCommand('enableObjectResizing',false,false);}catch(ex){}}};t.onBeforeExecCommand.add(setOpts);t.onMouseDown.add(setOpts);}t.onMouseUp.add(t.nodeChanged);t.onClick.add(t.nodeChanged);t.onKeyUp.add(function(ed,e){var c=e.keyCode;if((c>=33&&c<=36)||(c>=37&&c<=40)||c==13||c==45||c==46||c==8||(tinymce.isMac&&(c==91||c==93))||e.ctrlKey)t.nodeChanged();});t.onReset.add(function(){t.setContent(t.startContent,{format:'raw'});});if(t.getParam('tab_focus')){function tabCancel(ed,e){if(e.keyCode===9)return Event.cancel(e);};function tabHandler(ed,e){var x,i,f,el,v;function find(d){f=DOM.getParent(ed.id,'form');el=f.elements;if(f){each(el,function(e,i){if(e.id==ed.id){x=i;return false;}});if(d>0){for(i=x+1;i=0;i--){if(el[i].type!='hidden')return el[i];}}}return null;};if(e.keyCode===9){v=explode(ed.getParam('tab_focus'));if(v.length==1){v[1]=v[0];v[0]=':prev';}if(e.shiftKey){if(v[0]==':prev')el=find(-1);else el=DOM.get(v[0]);}else{if(v[1]==':next')el=find(1);else el=DOM.get(v[1]);}if(el){if(ed=EditorManager.get(el.id||el.name))ed.focus();else window.setTimeout(function(){window.focus();el.focus();},10);return Event.cancel(e);}}};t.onKeyUp.add(tabCancel);if(isGecko){t.onKeyPress.add(tabHandler);t.onKeyDown.add(tabCancel);}else t.onKeyDown.add(tabHandler);}if(s.custom_shortcuts){if(s.custom_undo_redo_keyboard_shortcuts){t.addShortcut('ctrl+z',t.getLang('undo_desc'),'Undo');t.addShortcut('ctrl+y',t.getLang('redo_desc'),'Redo');}if(isGecko){t.addShortcut('ctrl+b',t.getLang('bold_desc'),'Bold');t.addShortcut('ctrl+i',t.getLang('italic_desc'),'Italic');t.addShortcut('ctrl+u',t.getLang('underline_desc'),'Underline');}for(i=1;i<=6;i++)t.addShortcut('ctrl+'+i,'',['FormatBlock',false,'']);t.addShortcut('ctrl+7','',['FormatBlock',false,'']);t.addShortcut('ctrl+8','',['FormatBlock',false,'
']);t.addShortcut('ctrl+9','',['FormatBlock',false,'
']);function find(e){var v=null;if(!e.altKey&&!e.ctrlKey&&!e.metaKey)return v;each(t.shortcuts,function(o){if(tinymce.isMac&&o.ctrl!=e.metaKey)return;else if(!tinymce.isMac&&o.ctrl!=e.ctrlKey)return;if(o.alt!=e.altKey)return;if(o.shift!=e.shiftKey)return;if(e.keyCode==o.keyCode||(e.charCode&&e.charCode==o.charCode)){v=o;return false;}});return v;};t.onKeyUp.add(function(ed,e){var o=find(e);if(o)return Event.cancel(e);});t.onKeyPress.add(function(ed,e){var o=find(e);if(o)return Event.cancel(e);});t.onKeyDown.add(function(ed,e){var o=find(e);if(o){o.func.call(o.scope);return Event.cancel(e);}});}if(tinymce.isIE){Event.add(t.getDoc(),'controlselect',function(e){var re=t.resizeInfo,cb;e=e.target;if(e.nodeName!=='IMG')return;if(re)Event.remove(re.node,re.ev,re.cb);if(!t.dom.hasClass(e,'mceItemNoResize')){ev='resizeend';cb=Event.add(e,ev,function(e){var v;e=e.target;if(v=t.dom.getStyle(e,'width')){t.dom.setAttrib(e,'width',v.replace(/[^0-9%]+/g,''));t.dom.setStyle(e,'width','');}if(v=t.dom.getStyle(e,'height')){t.dom.setAttrib(e,'height',v.replace(/[^0-9%]+/g,''));t.dom.setStyle(e,'height','');}});}else{ev='resizestart';cb=Event.add(e,'resizestart',Event.cancel,Event);}re=t.resizeInfo={node:e,ev:ev,cb:cb};});t.onKeyDown.add(function(ed,e){switch(e.keyCode){case 8:if(t.selection.getRng().item){t.selection.getRng().item(0).removeNode();return Event.cancel(e);}}});}if(tinymce.isOpera){t.onClick.add(function(ed,e){Event.prevent(e);});}if(s.custom_undo_redo){function addUndo(){t.undoManager.typing=0;t.undoManager.add();};if(tinymce.isIE){Event.add(t.getWin(),'blur',function(e){var n;if(t.selection){n=t.selection.getNode();if(!t.removed&&n.ownerDocument&&n.ownerDocument!=t.getDoc())addUndo();}});}else{Event.add(t.getDoc(),'blur',function(){if(t.selection&&!t.removed)addUndo();});}t.onMouseDown.add(addUndo);t.onKeyUp.add(function(ed,e){if((e.keyCode>=33&&e.keyCode<=36)||(e.keyCode>=37&&e.keyCode<=40)||e.keyCode==13||e.keyCode==45||e.ctrlKey){t.undoManager.typing=0;t.undoManager.add();}});t.onKeyDown.add(function(ed,e){if((e.keyCode>=33&&e.keyCode<=36)||(e.keyCode>=37&&e.keyCode<=40)||e.keyCode==13||e.keyCode==45){if(t.undoManager.typing){t.undoManager.add();t.undoManager.typing=0;}return;}if(!t.undoManager.typing){t.undoManager.add();t.undoManager.typing=1;}});}},_convertInlineElements:function(){var t=this,s=t.settings,dom=t.dom,v,e,na,st,sp;function convert(ed,o){if(!s.inline_styles)return;if(o.get){each(t.dom.select('table,u,strike',o.node),function(n){switch(n.nodeName){case'TABLE':if(v=dom.getAttrib(n,'height')){dom.setStyle(n,'height',v);dom.setAttrib(n,'height','');}break;case'U':case'STRIKE':n.style.textDecoration=n.nodeName=='U'?'underline':'line-through';dom.setAttrib(n,'mce_style','');dom.setAttrib(n,'mce_name','span');break;}});}else if(o.set){each(t.dom.select('table,span',o.node).reverse(),function(n){if(n.nodeName=='TABLE'){if(v=dom.getStyle(n,'height'))dom.setAttrib(n,'height',v.replace(/[^0-9%]+/g,''));}else{if(n.style.textDecoration=='underline')na='u';else if(n.style.textDecoration=='line-through')na='strike';else na='';if(na){n.style.textDecoration='';dom.setAttrib(n,'mce_style','');e=dom.create(na,{style:dom.getAttrib(n,'style')});dom.replace(e,n,1);}}});}};t.onPreProcess.add(convert);if(!s.cleanup_on_startup){t.onSetContent.add(function(ed,o){if(o.initial)convert(t,{node:t.getBody(),set:1});});}},_convertFonts:function(){var t=this,s=t.settings,dom=t.dom,fz,fzn,sl,cl;if(!s.inline_styles)return;fz=[8,10,12,14,18,24,36];fzn=['xx-small','x-small','small','medium','large','x-large','xx-large'];if(sl=s.font_size_style_values)sl=explode(sl);if(cl=s.font_size_classes)cl=explode(cl);function process(no){var n,sp,nl,x;if(!s.inline_styles)return;nl=t.dom.select('font',no);for(x=nl.length-1;x>=0;x--){n=nl[x];sp=dom.create('span',{style:dom.getAttrib(n,'style'),'class':dom.getAttrib(n,'class')});dom.setStyles(sp,{fontFamily:dom.getAttrib(n,'face'),color:dom.getAttrib(n,'color'),backgroundColor:n.style.backgroundColor});if(n.size){if(sl)dom.setStyle(sp,'fontSize',sl[parseInt(n.size)-1]);else dom.setAttrib(sp,'class',cl[parseInt(n.size)-1]);}dom.setAttrib(sp,'mce_style','');dom.replace(sp,n,1);}};t.onPreProcess.add(function(ed,o){if(o.get)process(o.node);});t.onSetContent.add(function(ed,o){if(o.initial)process(o.node);});},_isHidden:function(){var s;if(!isGecko)return 0;s=this.selection.getSel();return(!s||!s.rangeCount||s.rangeCount==0);},_fixNesting:function(s){var d=[],i;s=s.replace(/<(\/)?([^\s>]+)[^>]*?>/g,function(a,b,c){var e;if(b==='/'){if(!d.length)return'';if(c!==d[d.length-1].tag){for(i=d.length-1;i>=0;i--){if(d[i].tag===c){d[i].close=1;break;}}return'';}else{d.pop();if(d.length&&d[d.length-1].close){a=a+'';d.pop();}}}else{if(/^(br|hr|input|meta|img|link|param)$/i.test(c))return a;if(/\/>$/.test(a))return a;d.push({tag:c});}return a;});for(i=d.length-1;i>=0;i--)s+='';return s;}});})();(function(){var each=tinymce.each,isIE=tinymce.isIE,isGecko=tinymce.isGecko,isOpera=tinymce.isOpera,isWebKit=tinymce.isWebKit;function isBlock(n){return/^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n.nodeName);};tinymce.create('tinymce.EditorCommands',{EditorCommands:function(ed){this.editor=ed;},execCommand:function(cmd,ui,val){var t=this,ed=t.editor,f;switch(cmd){case'Cut':case'Copy':case'Paste':try{ed.getDoc().execCommand(cmd,ui,val);}catch(ex){if(isGecko){ed.windowManager.confirm(ed.getLang('clipboard_msg'),function(s){if(s)window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html','mceExternal');});}else ed.windowManager.alert(ed.getLang('clipboard_no_support'));}return true;case'mceResetDesignMode':case'mceBeginUndoLevel':return true;case'unlink':t.UnLink();return true;case'JustifyLeft':case'JustifyCenter':case'JustifyRight':case'JustifyFull':t.mceJustify(cmd,cmd.substring(7).toLowerCase());return true;case'mceEndUndoLevel':case'mceAddUndoLevel':ed.undoManager.add();return true;default:f=this[cmd];if(f){f.call(this,ui,val);return true;}}return false;},Indent:function(){var ed=this.editor,d=ed.dom,s=ed.selection,e,iv,iu;iv=ed.settings.indentation;iu=/[a-z%]+$/i.exec(iv);iv=parseInt(iv);if(ed.settings.inline_styles&&(!this.queryStateInsertUnorderedList()&&!this.queryStateInsertOrderedList())){each(this._getSelectedBlocks(),function(e){d.setStyle(e,'paddingLeft',(parseInt(e.style.paddingLeft||0)+iv)+iu);});return;}ed.getDoc().execCommand('Indent',false,null);if(isIE){d.getParent(s.getNode(),function(n){if(n.nodeName=='BLOCKQUOTE'){n.dir=n.style.cssText='';}});}},Outdent:function(){var ed=this.editor,d=ed.dom,s=ed.selection,e,v,iv,iu;iv=ed.settings.indentation;iu=/[a-z%]+$/i.exec(iv);iv=parseInt(iv);if(ed.settings.inline_styles&&(!this.queryStateInsertUnorderedList()&&!this.queryStateInsertOrderedList())){each(this._getSelectedBlocks(),function(e){v=Math.max(0,parseInt(e.style.paddingLeft||0)-iv);d.setStyle(e,'paddingLeft',v?v+iu:'');});return;}ed.getDoc().execCommand('Outdent',false,null);},mceSetAttribute:function(u,v){var ed=this.editor,d=ed.dom,e;if(e=d.getParent(ed.selection.getNode(),d.isBlock))d.setAttrib(e,v.name,v.value);},mceSetContent:function(u,v){this.editor.setContent(v);},mceToggleVisualAid:function(){var ed=this.editor;ed.hasVisual=!ed.hasVisual;ed.addVisual();},mceReplaceContent:function(u,v){var s=this.editor.selection;s.setContent(v.replace(/\{\$selection\}/g,s.getContent({format:'text'})));},mceInsertLink:function(u,v){var ed=this.editor,s=ed.selection,e=ed.dom.getParent(s.getNode(),'A');if(tinymce.is(v,'string'))v={href:v};function set(e){each(v,function(v,k){ed.dom.setAttrib(e,k,v);});};if(!e){ed.execCommand('CreateLink',false,'javascript:mctmp(0);');each(ed.dom.select('a'),function(e){if(e.href=='javascript:mctmp(0);')set(e);});}else{if(v.href)set(e);else ed.dom.remove(e,1);}},UnLink:function(){var ed=this.editor,s=ed.selection;if(s.isCollapsed())s.select(s.getNode());ed.getDoc().execCommand('unlink',false,null);s.collapse(0);},FontName:function(u,v){var t=this,ed=t.editor,s=ed.selection,e;if(!v){if(s.isCollapsed())s.select(s.getNode());t.RemoveFormat();}else{if(ed.settings.convert_fonts_to_spans)t._applyInlineStyle('span',{style:{fontFamily:v}});else ed.getDoc().execCommand('FontName',false,v);}},FontSize:function(u,v){var ed=this.editor,s=ed.settings,fc,fs;if(s.convert_fonts_to_spans&&v>=1&&v<=7){fs=tinymce.explode(s.font_size_style_values);fc=tinymce.explode(s.font_size_classes);if(fc)v=fc[v-1]||v;else v=fs[v-1]||v;}if(v>=1&&v<=7)ed.getDoc().execCommand('FontSize',false,v);else this._applyInlineStyle('span',{style:{fontSize:v}});},queryCommandValue:function(c){var f=this['queryValue'+c];if(f)return f.call(this,c);return false;},queryCommandState:function(cmd){var f;switch(cmd){case'JustifyLeft':case'JustifyCenter':case'JustifyRight':case'JustifyFull':return this.queryStateJustify(cmd,cmd.substring(7).toLowerCase());default:if(f=this['queryState'+cmd])return f.call(this,cmd);}return-1;},_queryState:function(c){try{return this.editor.getDoc().queryCommandState(c);}catch(ex){}},_queryVal:function(c){try{return this.editor.getDoc().queryCommandValue(c);}catch(ex){}},queryValueFontSize:function(){var ed=this.editor,v=0,p;if(p=ed.dom.getParent(ed.selection.getNode(),'SPAN'))v=p.style.fontSize;if(!v&&(isOpera||isWebKit)){if(p=ed.dom.getParent(ed.selection.getNode(),'FONT'))v=p.size;return v;}return v||this._queryVal('FontSize');},queryValueFontName:function(){var ed=this.editor,v=0,p;if(p=ed.dom.getParent(ed.selection.getNode(),'FONT'))v=p.face;if(p=ed.dom.getParent(ed.selection.getNode(),'SPAN'))v=p.style.fontFamily.replace(/, /g,',').replace(/[\'\"]/g,'').toLowerCase();if(!v)v=this._queryVal('FontName');return v;},mceJustify:function(c,v){var ed=this.editor,se=ed.selection,n=se.getNode(),nn=n.nodeName,bl,nb,dom=ed.dom,rm;if(ed.settings.inline_styles&&this.queryStateJustify(c,v))rm=1;bl=dom.getParent(n,ed.dom.isBlock);if(nn=='IMG'){if(v=='full')return;if(rm){if(v=='center')dom.setStyle(bl||n.parentNode,'textAlign','');dom.setStyle(n,'float','');this.mceRepaint();return;}if(v=='center'){if(bl&&/^(TD|TH)$/.test(bl.nodeName))bl=0;if(!bl||bl.childNodes.length>1){nb=dom.create('p');nb.appendChild(n.cloneNode(false));if(bl)dom.insertAfter(nb,bl);else dom.insertAfter(nb,n);dom.remove(n);n=nb.firstChild;bl=nb;}dom.setStyle(bl,'textAlign',v);dom.setStyle(n,'float','');}else{dom.setStyle(n,'float',v);dom.setStyle(bl||n.parentNode,'textAlign','');}this.mceRepaint();return;}if(ed.settings.inline_styles&&ed.settings.forced_root_block){if(rm)v='';each(this._getSelectedBlocks(dom.getParent(se.getStart(),dom.isBlock),dom.getParent(se.getEnd(),dom.isBlock)),function(e){dom.setAttrib(e,'align','');dom.setStyle(e,'textAlign',v=='full'?'justify':v);});return;}else if(!rm)ed.getDoc().execCommand(c,false,null);if(ed.settings.inline_styles){if(rm){dom.getParent(ed.selection.getNode(),function(n){if(n.style&&n.style.textAlign)dom.setStyle(n,'textAlign','');});return;}each(dom.select('*'),function(n){var v=n.align;if(v){if(v=='full')v='justify';dom.setStyle(n,'textAlign',v);dom.setAttrib(n,'align','');}});}},mceSetCSSClass:function(u,v){this.mceSetStyleInfo(0,{command:'setattrib',name:'class',value:v});},getSelectedElement:function(){var t=this,ed=t.editor,dom=ed.dom,se=ed.selection,r=se.getRng(),r1,r2,sc,ec,so,eo,e,sp,ep,re;if(se.isCollapsed()||r.item)return se.getNode();re=ed.settings.merge_styles_invalid_parents;if(tinymce.is(re,'string'))re=new RegExp(re,'i');if(isIE){r1=r.duplicate();r1.collapse(true);sc=r1.parentElement();r2=r.duplicate();r2.collapse(false);ec=r2.parentElement();if(sc!=ec){r1.move('character',1);sc=r1.parentElement();}if(sc==ec){r1=r.duplicate();r1.moveToElementText(sc);if(r1.compareEndPoints('StartToStart',r)==0&&r1.compareEndPoints('EndToEnd',r)==0)return re&&re.test(sc.nodeName)?null:sc;}}else{function getParent(n){return dom.getParent(n,function(n){return n.nodeType==1;});};sc=r.startContainer;ec=r.endContainer;so=r.startOffset;eo=r.endOffset;if(!r.collapsed){if(sc==ec){if(so-eo<2){if(sc.hasChildNodes()){sp=sc.childNodes[so];return re&&re.test(sp.nodeName)?null:sp;}}}}if(sc.nodeType!=3||ec.nodeType!=3)return null;if(so==0){sp=getParent(sc);if(sp&&sp.firstChild!=sc)sp=null;}if(so==sc.nodeValue.length){e=sc.nextSibling;if(e&&e.nodeType==1)sp=sc.nextSibling;}if(eo==0){e=ec.previousSibling;if(e&&e.nodeType==1)ep=e;}if(eo==ec.nodeValue.length){ep=getParent(ec);if(ep&&ep.lastChild!=ec)ep=null;}if(sp==ep)return re&&sp&&re.test(sp.nodeName)?null:sp;}return null;},InsertHorizontalRule:function(){if(isGecko||isIE)this.editor.selection.setContent(' ');else this.editor.getDoc().execCommand('InsertHorizontalRule',false,'');},RemoveFormat:function(){var t=this,ed=t.editor,s=ed.selection,b;if(isWebKit)s.setContent(s.getContent({format:'raw'}).replace(/(<(span|b|i|strong|em|strike) [^>]+>|<(span|b|i|strong|em|strike)>|<\/(span|b|i|strong|em|strike)>|)/g,''),{format:'raw'});else ed.getDoc().execCommand('RemoveFormat',false,null);t.mceSetStyleInfo(0,{command:'removeformat'});ed.addVisual();},mceSetStyleInfo:function(u,v){var t=this,ed=t.editor,d=ed.getDoc(),dom=ed.dom,e,b,s=ed.selection,nn=v.wrapper||'span',b=s.getBookmark(),re;function set(n,e){if(n.nodeType==1){switch(v.command){case'setattrib':return dom.setAttrib(n,v.name,v.value);case'setstyle':return dom.setStyle(n,v.name,v.value);case'removeformat':return dom.setAttrib(n,'class','');}}};re=ed.settings.merge_styles_invalid_parents;if(tinymce.is(re,'string'))re=new RegExp(re,'i');if((e=t.getSelectedElement())&&!ed.settings.force_span_wrappers)set(e,1);else{d.execCommand('FontName',false,'__');each(isWebKit?dom.select('span'):dom.select('font'),function(n){var sp,e;if(dom.getAttrib(n,'face')=='__'||n.style.fontFamily==='__'){sp=dom.create(nn,{mce_new:'1'});set(sp);each(n.childNodes,function(n){sp.appendChild(n.cloneNode(true));});dom.replace(sp,n);}});}each(dom.select(nn).reverse(),function(n){var p=n.parentNode;if(!dom.getAttrib(n,'mce_new')){p=dom.getParent(n,function(n){return n.nodeType==1&&dom.getAttrib(n,'mce_new');});if(p)dom.remove(n,1);}});each(dom.select(nn).reverse(),function(n){var p=n.parentNode;if(!p||!dom.getAttrib(n,'mce_new'))return;if(ed.settings.force_span_wrappers&&p.nodeName!='SPAN')return;if(p.nodeName==nn.toUpperCase()&&p.childNodes.length==1)return dom.remove(p,1);if(n.nodeType==1&&(!re||!re.test(p.nodeName))&&p.childNodes.length==1){set(p);dom.setAttrib(n,'class','');}});each(dom.select(nn).reverse(),function(n){if(dom.getAttrib(n,'mce_new')||(dom.getAttribs(n).length<=1&&n.className==='')){if(!dom.getAttrib(n,'class')&&!dom.getAttrib(n,'style'))return dom.remove(n,1);dom.setAttrib(n,'mce_new','');}});s.moveToBookmark(b);},queryStateJustify:function(c,v){var ed=this.editor,n=ed.selection.getNode(),dom=ed.dom;if(n&&n.nodeName=='IMG'){if(dom.getStyle(n,'float')==v)return 1;return n.parentNode.style.textAlign==v;}n=dom.getParent(ed.selection.getStart(),function(n){return n.nodeType==1&&n.style.textAlign;});if(v=='full')v='justify';if(ed.settings.inline_styles)return(n&&n.style.textAlign==v);return this._queryState(c);},ForeColor:function(ui,v){var ed=this.editor;if(ed.settings.convert_fonts_to_spans){this._applyInlineStyle('span',{style:{color:v}});return;}else ed.getDoc().execCommand('ForeColor',false,v);},HiliteColor:function(ui,val){var t=this,ed=t.editor,d=ed.getDoc();if(ed.settings.convert_fonts_to_spans){this._applyInlineStyle('span',{style:{backgroundColor:val}});return;}function set(s){if(!isGecko)return;try{d.execCommand("styleWithCSS",0,s);}catch(ex){d.execCommand("useCSS",0,!s);}};if(isGecko||isOpera){set(true);d.execCommand('hilitecolor',false,val);set(false);}else d.execCommand('BackColor',false,val);},Undo:function(){var ed=this.editor;if(ed.settings.custom_undo_redo){ed.undoManager.undo();ed.nodeChanged();}else ed.getDoc().execCommand('Undo',false,null);},Redo:function(){var ed=this.editor;if(ed.settings.custom_undo_redo){ed.undoManager.redo();ed.nodeChanged();}else ed.getDoc().execCommand('Redo',false,null);},FormatBlock:function(ui,val){var t=this,ed=t.editor,s=ed.selection,dom=ed.dom,bl,nb,b;function isBlock(n){return/^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(n.nodeName);};bl=dom.getParent(s.getNode(),function(n){return isBlock(n);});if(bl){if((isIE&&isBlock(bl.parentNode))||bl.nodeName=='DIV'){nb=ed.dom.create(val);each(dom.getAttribs(bl),function(v){dom.setAttrib(nb,v.nodeName,dom.getAttrib(bl,v.nodeName));});b=s.getBookmark();dom.replace(nb,bl,1);s.moveToBookmark(b);ed.nodeChanged();return;}}val=ed.settings.forced_root_block?(val||''):val;if(val.indexOf('<')==-1)val='<'+val+'>';if(tinymce.isGecko)val=val.replace(/<(div|blockquote|code|dt|dd|dl|samp)>/gi,'$1');ed.getDoc().execCommand('FormatBlock',false,val);},mceCleanup:function(){var ed=this.editor,s=ed.selection,b=s.getBookmark();ed.setContent(ed.getContent());s.moveToBookmark(b);},mceRemoveNode:function(ui,val){var ed=this.editor,s=ed.selection,b,n=val||s.getNode();if(n==ed.getBody())return;b=s.getBookmark();ed.dom.remove(n,1);s.moveToBookmark(b);ed.nodeChanged();},mceSelectNodeDepth:function(ui,val){var ed=this.editor,s=ed.selection,c=0;ed.dom.getParent(s.getNode(),function(n){if(n.nodeType==1&&c++==val){s.select(n);ed.nodeChanged();return false;}},ed.getBody());},mceSelectNode:function(u,v){this.editor.selection.select(v);},mceInsertContent:function(ui,val){this.editor.selection.setContent(val);},mceInsertRawHTML:function(ui,val){var ed=this.editor;ed.selection.setContent('tiny_mce_marker');ed.setContent(ed.getContent().replace(/tiny_mce_marker/g,val));},mceRepaint:function(){var s,b,e=this.editor;if(tinymce.isGecko){try{s=e.selection;b=s.getBookmark(true);if(s.getSel())s.getSel().selectAllChildren(e.getBody());s.collapse(true);s.moveToBookmark(b);}catch(ex){}}},queryStateUnderline:function(){var ed=this.editor,n=ed.selection.getNode();if(n&&n.nodeName=='A')return false;return this._queryState('Underline');},queryStateOutdent:function(){var ed=this.editor,n;if(ed.settings.inline_styles){if((n=ed.dom.getParent(ed.selection.getStart(),ed.dom.isBlock))&&parseInt(n.style.paddingLeft)>0)return true;if((n=ed.dom.getParent(ed.selection.getEnd(),ed.dom.isBlock))&&parseInt(n.style.paddingLeft)>0)return true;}return this.queryStateInsertUnorderedList()||this.queryStateInsertOrderedList()||(!ed.settings.inline_styles&&!!ed.dom.getParent(ed.selection.getNode(),'BLOCKQUOTE'));},queryStateInsertUnorderedList:function(){return this.editor.dom.getParent(this.editor.selection.getNode(),'UL');},queryStateInsertOrderedList:function(){return this.editor.dom.getParent(this.editor.selection.getNode(),'OL');},queryStatemceBlockQuote:function(){return!!this.editor.dom.getParent(this.editor.selection.getStart(),function(n){return n.nodeName==='BLOCKQUOTE';});},mceBlockQuote:function(){var t=this,ed=t.editor,s=ed.selection,dom=ed.dom,sb,eb,n,bm,bq,r,bq2,i,nl;function getBQ(e){return dom.getParent(e,function(n){return n.nodeName==='BLOCKQUOTE';});};sb=dom.getParent(s.getStart(),isBlock);eb=dom.getParent(s.getEnd(),isBlock);if(bq=getBQ(sb)){if(sb!=eb||sb.childNodes.length>1||(sb.childNodes.length==1&&sb.firstChild.nodeName!='BR'))bm=s.getBookmark();if(getBQ(eb)){bq2=bq.cloneNode(false);while(n=eb.nextSibling)bq2.appendChild(n.parentNode.removeChild(n));}if(bq2)dom.insertAfter(bq2,bq);nl=t._getSelectedBlocks(sb,eb);for(i=nl.length-1;i>=0;i--){dom.insertAfter(nl[i],bq);}if(/^\s*$/.test(bq.innerHTML))dom.remove(bq,1);if(bq2&&/^\s*$/.test(bq2.innerHTML))dom.remove(bq2,1);if(!bm){if(!isIE){r=ed.getDoc().createRange();r.setStart(sb,0);r.setEnd(sb,0);s.setRng(r);}else{s.select(sb);s.collapse(0);if(dom.getParent(s.getStart(),isBlock)!=sb){r=s.getRng();r.move('character',-1);r.select();}}}else t.editor.selection.moveToBookmark(bm);return;}if(isIE&&!sb&&!eb){t.editor.getDoc().execCommand('Indent');n=getBQ(s.getNode());n.style.margin=n.dir='';return;}if(!sb||!eb)return;if(sb!=eb||sb.childNodes.length>1||(sb.childNodes.length==1&&sb.firstChild.nodeName!='BR'))bm=s.getBookmark();each(t._getSelectedBlocks(getBQ(s.getStart()),getBQ(s.getEnd())),function(e){if(e.nodeName=='BLOCKQUOTE'&&!bq){bq=e;return;}if(!bq){bq=dom.create('blockquote');e.parentNode.insertBefore(bq,e);}if(e.nodeName=='BLOCKQUOTE'&&bq){n=e.firstChild;while(n){bq.appendChild(n.cloneNode(true));n=n.nextSibling;}dom.remove(e);return;}bq.appendChild(dom.remove(e));});if(!bm){if(!isIE){r=ed.getDoc().createRange();r.setStart(sb,0);r.setEnd(sb,0);s.setRng(r);}else{s.select(sb);s.collapse(1);}}else s.moveToBookmark(bm);},_applyInlineStyle:function(na,at,op){var t=this,ed=t.editor,dom=ed.dom,bm,lo={},kh;na=na.toUpperCase();if(op&&op.check_classes&&at['class'])op.check_classes.push(at['class']);function replaceFonts(){var bm;each(dom.select(tinymce.isWebKit&&!tinymce.isAir?'span':'font'),function(n){if(n.style.fontFamily=='mceinline'||n.face=='mceinline'){if(!bm)bm=ed.selection.getBookmark();at._mce_new='1';dom.replace(dom.create(na,at),n,1);}});each(dom.select(na),function(n){if(n.getAttribute('_mce_new')){function removeStyle(n){if(n.nodeType==1){each(at.style,function(v,k){dom.setStyle(n,k,'');});if(at['class']&&n.className&&op){each(op.check_classes,function(c){if(dom.hasClass(n,c))dom.removeClass(n,c);});}}};each(dom.select(na,n),removeStyle);if(n.parentNode&&n.parentNode.nodeType==1&&n.parentNode.childNodes.length==1)removeStyle(n.parentNode);dom.getParent(n.parentNode,function(pn){if(pn.nodeType==1){if(at.style){each(at.style,function(v,k){var sv;if(!lo[k]&&(sv=dom.getStyle(pn,k))){if(sv===v)dom.setStyle(n,k,'');lo[k]=1;}});}if(at['class']&&pn.className&&op){each(op.check_classes,function(c){if(dom.hasClass(pn,c))dom.removeClass(n,c);});}}return false;});n.removeAttribute('_mce_new');}});each(dom.select(na).reverse(),function(n){var c=0;each(dom.getAttribs(n),function(an){if(an.nodeName.substring(0,1)!='_'&&dom.getAttrib(n,an.nodeName)!=''){c++;}});if(c==0)dom.remove(n,1);});ed.selection.moveToBookmark(bm);return!!bm;};ed.focus();ed.getDoc().execCommand('FontName',false,'mceinline');replaceFonts();if(kh=t._applyInlineStyle.keyhandler){ed.onKeyUp.remove(kh);ed.onKeyPress.remove(kh);ed.onKeyDown.remove(kh);ed.onSetContent.remove(t._applyInlineStyle.chandler);}if(ed.selection.isCollapsed()){t._pendingStyles=tinymce.extend(t._pendingStyles||{},at.style);t._applyInlineStyle.chandler=ed.onSetContent.add(function(){delete t._pendingStyles;});t._applyInlineStyle.keyhandler=kh=function(e){if(t._pendingStyles){at.style=t._pendingStyles;delete t._pendingStyles;}if(replaceFonts()){ed.onKeyDown.remove(t._applyInlineStyle.keyhandler);ed.onKeyPress.remove(t._applyInlineStyle.keyhandler);}if(e.type=='keyup')ed.onKeyUp.remove(t._applyInlineStyle.keyhandler);};ed.onKeyDown.add(kh);ed.onKeyPress.add(kh);ed.onKeyUp.add(kh);}else t._pendingStyles=0;},_getSelectedBlocks:function(st,en){var ed=this.editor,dom=ed.dom,s=ed.selection,sb,eb,n,bl=[];sb=dom.getParent(st||s.getStart(),isBlock);eb=dom.getParent(en||s.getEnd(),isBlock);if(sb)bl.push(sb);if(sb&&eb&&sb!=eb){n=sb;while((n=n.nextSibling)&&n!=eb){if(isBlock(n))bl.push(n);}}if(eb&&sb!=eb)bl.push(eb);return bl;}});})();tinymce.create('tinymce.UndoManager',{index:0,data:null,typing:0,UndoManager:function(ed){var t=this,Dispatcher=tinymce.util.Dispatcher;t.editor=ed;t.data=[];t.onAdd=new Dispatcher(this);t.onUndo=new Dispatcher(this);t.onRedo=new Dispatcher(this);},add:function(l){var t=this,i,ed=t.editor,b,s=ed.settings,la;l=l||{};l.content=l.content||ed.getContent({format:'raw',no_events:1});l.content=l.content.replace(/^\s*|\s*$/g,'');la=t.data[t.index>0&&(t.index==0||t.index==t.data.length)?t.index-1:t.index];if(!l.initial&&la&&l.content==la.content)return null;if(s.custom_undo_redo_levels){if(t.data.length>s.custom_undo_redo_levels){for(i=0;i0){if(t.index==t.data.length&&t.index>1){i=t.index;t.typing=0;if(!t.add())t.index=i;--t.index;}l=t.data[--t.index];ed.setContent(l.content,{format:'raw'});ed.selection.moveToBookmark(l.bookmark);t.onUndo.dispatch(t,l);}return l;},redo:function(){var t=this,ed=t.editor,l=null;if(t.index','gi');t.rePadd=new RegExp(']+)><\\\/p>|
]+)\\\/>|
]+)>\\s+<\\\/p>|
<\\\/p>|
|
\\s+<\\\/p>'.replace(/p/g,elm),'gi');t.reNbsp2BR1=new RegExp('
]+)>[\\s\\u00a0]+<\\\/p>|
[\\s\\u00a0]+<\\\/p>'.replace(/p/g,elm),'gi');t.reNbsp2BR2=new RegExp('
]+)>( | )<\\\/p>|
( | )<\\\/p>'.replace(/p/g,elm),'gi');t.reBR2Nbsp=new RegExp('
]+)>\\s* \\s*<\\\/p>|
\\s* \\s*<\\\/p>'.replace(/p/g,elm),'gi');t.reTrailBr=new RegExp('\\s* \\s*<\\\/p>'.replace(/p/g,elm),'gi');function padd(ed,o){if(isOpera)o.content=o.content.replace(t.reOpera,'');o.content=o.content.replace(t.rePadd,'<'+elm+'$1$2$3$4$5$6>\u00a0');if(!isIE&&!isOpera&&o.set){o.content=o.content.replace(t.reNbsp2BR1,'<'+elm+'$1$2> ');o.content=o.content.replace(t.reNbsp2BR2,'<'+elm+'$1$2> ');}else{o.content=o.content.replace(t.reBR2Nbsp,'<'+elm+'$1$2>\u00a0');o.content=o.content.replace(t.reTrailBr,'');}};ed.onBeforeSetContent.add(padd);ed.onPostProcess.add(padd);if(s.forced_root_block){ed.onInit.add(t.forceRoots,t);ed.onSetContent.add(t.forceRoots,t);ed.onBeforeGetContent.add(t.forceRoots,t);}},setup:function(){var t=this,ed=t.editor,s=ed.settings;if(s.forced_root_block){ed.onKeyUp.add(t.forceRoots,t);ed.onPreProcess.add(t.forceRoots,t);}if(s.force_br_newlines){if(isIE){ed.onKeyPress.add(function(ed,e){var n,s=ed.selection;if(e.keyCode==13&&s.getNode().nodeName!='LI'){s.setContent(' ',{format:'raw'});n=ed.dom.get('__');n.removeAttribute('id');s.select(n);s.collapse();return Event.cancel(e);}});}return;}if(!isIE&&s.force_p_newlines){ed.onKeyPress.add(function(ed,e){if(e.keyCode==13&&!e.shiftKey){if(!t.insertPara(e))Event.cancel(e);}});if(isGecko){ed.onKeyDown.add(function(ed,e){if((e.keyCode==8||e.keyCode==46)&&!e.shiftKey)t.backspaceDelete(e,e.keyCode==8);});}}function ren(rn,na){var ne=ed.dom.create(na);each(rn.attributes,function(a){if(a.specified&&a.nodeValue)ne.setAttribute(a.nodeName.toLowerCase(),a.nodeValue);});each(rn.childNodes,function(n){ne.appendChild(n.cloneNode(true));});rn.parentNode.replaceChild(ne,rn);return ne;};if(isIE&&s.element!='P'){ed.onKeyPress.add(function(ed,e){t.lastElm=ed.selection.getNode().nodeName;});ed.onKeyUp.add(function(ed,e){var bl,sel=ed.selection,n=sel.getNode(),b=ed.getBody();if(b.childNodes.length===1&&n.nodeName=='P'){n=ren(n,s.element);sel.select(n);sel.collapse();ed.nodeChanged();}else if(e.keyCode==13&&!e.shiftKey&&t.lastElm!='P'){bl=ed.dom.getParent(n,'P');if(bl){ren(bl,s.element);ed.nodeChanged();}}});}},find:function(n,t,s){var ed=this.editor,w=ed.getDoc().createTreeWalker(n,4,null,false),c=-1;while(n=w.nextNode()){c++;if(t==0&&n==s)return c;if(t==1&&c==s)return n;}return-1;},forceRoots:function(ed,e){var t=this,ed=t.editor,b=ed.getBody(),d=ed.getDoc(),se=ed.selection,s=se.getSel(),r=se.getRng(),si=-2,ei,so,eo,tr,c=-0xFFFFFF;var nx,bl,bp,sp,le,nl=b.childNodes,i,n,eid;for(i=nl.length-1;i>=0;i--){nx=nl[i];if(nx.nodeType==3||(!t.dom.isBlock(nx)&&nx.nodeType!=8)){if(!bl){if(nx.nodeType!=3||/[^\s]/g.test(nx.nodeValue)){if(si==-2&&r){if(!isIE){if(r.startContainer.nodeType==1&&(n=r.startContainer.childNodes[r.startOffset])&&n.nodeType==1){eid=n.getAttribute("id");n.setAttribute("id","__mce");}else{if(ed.dom.getParent(r.startContainer,function(e){return e===b;})){so=r.startOffset;eo=r.endOffset;si=t.find(b,0,r.startContainer);ei=t.find(b,0,r.endContainer);}}}else{tr=d.body.createTextRange();tr.moveToElementText(b);tr.collapse(1);bp=tr.move('character',c)*-1;tr=r.duplicate();tr.collapse(1);sp=tr.move('character',c)*-1;tr=r.duplicate();tr.collapse(0);le=(tr.move('character',c)*-1)-sp;si=sp-bp;ei=le;}}bl=ed.dom.create(ed.settings.forced_root_block);bl.appendChild(nx.cloneNode(1));nx.parentNode.replaceChild(bl,nx);}}else{if(bl.hasChildNodes())bl.insertBefore(nx,bl.firstChild);else bl.appendChild(nx);}}else bl=null;}if(si!=-2){if(!isIE){bl=b.getElementsByTagName(ed.settings.element)[0];r=d.createRange();if(si!=-1)r.setStart(t.find(b,1,si),so);else r.setStart(bl,0);if(ei!=-1)r.setEnd(t.find(b,1,ei),eo);else r.setEnd(bl,0);if(s){s.removeAllRanges();s.addRange(r);}}else{try{r=s.createRange();r.moveToElementText(b);r.collapse(1);r.moveStart('character',si);r.moveEnd('character',ei);r.select();}catch(ex){}}}else if(!isIE&&(n=ed.dom.get('__mce'))){if(eid)n.setAttribute('id',eid);else n.removeAttribute('id');r=d.createRange();r.setStartBefore(n);r.setEndBefore(n);se.setRng(r);}},getParentBlock:function(n){var d=this.dom;return d.getParent(n,d.isBlock);},insertPara:function(e){var t=this,ed=t.editor,dom=ed.dom,d=ed.getDoc(),se=ed.settings,s=ed.selection.getSel(),r=s.getRangeAt(0),b=d.body;var rb,ra,dir,sn,so,en,eo,sb,eb,bn,bef,aft,sc,ec,n,vp=dom.getViewPort(ed.getWin()),y,ch,car;function isEmpty(n){n=n.innerHTML;n=n.replace(/<(img|hr|table)/gi,'-');n=n.replace(/<[^>]+>/g,'');return n.replace(/[ \t\r\n]+/g,'')=='';};rb=d.createRange();rb.setStart(s.anchorNode,s.anchorOffset);rb.collapse(true);ra=d.createRange();ra.setStart(s.focusNode,s.focusOffset);ra.collapse(true);dir=rb.compareBoundaryPoints(rb.START_TO_END,ra)<0;sn=dir?s.anchorNode:s.focusNode;so=dir?s.anchorOffset:s.focusOffset;en=dir?s.focusNode:s.anchorNode;eo=dir?s.focusOffset:s.anchorOffset;if(sn===en&&/^(TD|TH)$/.test(sn.nodeName)){dom.remove(sn.firstChild);ed.dom.add(sn,se.element,null,' ');aft=ed.dom.add(sn,se.element,null,' ');r=d.createRange();r.selectNodeContents(aft);r.collapse(1);ed.selection.setRng(r);return false;}if(sn==b&&en==b&&b.firstChild&&ed.dom.isBlock(b.firstChild)){sn=en=sn.firstChild;so=eo=0;rb=d.createRange();rb.setStart(sn,0);ra=d.createRange();ra.setStart(en,0);}sn=sn.nodeName=="HTML"?d.body:sn;sn=sn.nodeName=="BODY"?sn.firstChild:sn;en=en.nodeName=="HTML"?d.body:en;en=en.nodeName=="BODY"?en.firstChild:en;sb=t.getParentBlock(sn);eb=t.getParentBlock(en);bn=sb?sb.nodeName:se.element;if(t.dom.getParent(sb,function(n){return/OL|UL|PRE/.test(n.nodeName);}))return true;if(sb&&(sb.nodeName=='CAPTION'||/absolute|relative|static/gi.test(sb.style.position))){bn=se.element;sb=null;}if(eb&&(eb.nodeName=='CAPTION'||/absolute|relative|static/gi.test(eb.style.position))){bn=se.element;eb=null;}if(/(TD|TABLE|TH|CAPTION)/.test(bn)||(sb&&bn=="DIV"&&/left|right/gi.test(sb.style.cssFloat))){bn=se.element;sb=eb=null;}bef=(sb&&sb.nodeName==bn)?sb.cloneNode(0):ed.dom.create(bn);aft=(eb&&eb.nodeName==bn)?eb.cloneNode(0):ed.dom.create(bn);aft.removeAttribute('id');if(/^(H[1-6])$/.test(bn)&&sn.nodeValue&&so==sn.nodeValue.length)aft=ed.dom.create(se.element);n=sc=sn;do{if(n==b||n.nodeType==9||t.dom.isBlock(n)||/(TD|TABLE|TH|CAPTION)/.test(n.nodeName))break;sc=n;}while((n=n.previousSibling?n.previousSibling:n.parentNode));n=ec=en;do{if(n==b||n.nodeType==9||t.dom.isBlock(n)||/(TD|TABLE|TH|CAPTION)/.test(n.nodeName))break;ec=n;}while((n=n.nextSibling?n.nextSibling:n.parentNode));if(sc.nodeName==bn)rb.setStart(sc,0);else rb.setStartBefore(sc);rb.setEnd(sn,so);bef.appendChild(rb.cloneContents()||d.createTextNode(''));try{ra.setEndAfter(ec);}catch(ex){}ra.setStart(en,eo);aft.appendChild(ra.cloneContents()||d.createTextNode(''));r=d.createRange();if(!sc.previousSibling&&sc.parentNode.nodeName==bn){r.setStartBefore(sc.parentNode);}else{if(rb.startContainer.nodeName==bn&&rb.startOffset==0)r.setStartBefore(rb.startContainer);else r.setStart(rb.startContainer,rb.startOffset);}if(!ec.nextSibling&&ec.parentNode.nodeName==bn)r.setEndAfter(ec.parentNode);else r.setEnd(ra.endContainer,ra.endOffset);r.deleteContents();if(isOpera)ed.getWin().scrollTo(0,vp.y);if(bef.firstChild&&bef.firstChild.nodeName==bn)bef.innerHTML=bef.firstChild.innerHTML;if(aft.firstChild&&aft.firstChild.nodeName==bn)aft.innerHTML=aft.firstChild.innerHTML;if(isEmpty(bef))bef.innerHTML=' ';function appendStyles(e,en){var nl=[],nn,n,i;e.innerHTML='';if(se.keep_styles){n=en;do{if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)){nn=n.cloneNode(false);dom.setAttrib(nn,'id','');nl.push(nn);}}while(n=n.parentNode);}if(nl.length>0){for(i=nl.length-1,nn=e;i>=0;i--)nn=nn.appendChild(nl[i]);nl[0].innerHTML=isOpera?' ':' ';return nl[0];}else e.innerHTML=isOpera?' ':' ';};if(isEmpty(aft))car=appendStyles(aft,en);if(isOpera&&parseFloat(opera.version())<9.5){r.insertNode(bef);r.insertNode(aft);}else{r.insertNode(aft);r.insertNode(bef);}aft.normalize();bef.normalize();function first(n){return d.createTreeWalker(n,NodeFilter.SHOW_TEXT,null,false).nextNode()||n;};r=d.createRange();r.selectNodeContents(isGecko?first(car||aft):car||aft);r.collapse(1);s.removeAllRanges();s.addRange(r);y=ed.dom.getPos(aft).y;ch=aft.clientHeight;if(yvp.y+vp.h){ed.getWin().scrollTo(0,y');
+ tinymce.ScriptLoader.markDone(u);
+ }
+ }
+ },
+
+ pickColor : function(e, element_id) {
+ this.execCommand('mceColorPicker', true, {
+ color : document.getElementById(element_id).value,
+ func : function(c) {
+ document.getElementById(element_id).value = c;
+
+ try {
+ document.getElementById(element_id).onchange();
+ } catch (ex) {
+ // Try fire event, ignore errors
+ }
+ }
+ });
+ },
+
+ openBrowser : function(element_id, type, option) {
+ tinyMCEPopup.restoreSelection();
+ this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window);
+ },
+
+ confirm : function(t, cb, s) {
+ this.editor.windowManager.confirm(t, cb, s, window);
+ },
+
+ alert : function(tx, cb, s) {
+ this.editor.windowManager.alert(tx, cb, s, window);
+ },
+
+ close : function() {
+ var t = this;
+
+ // To avoid domain relaxing issue in Opera
+ function close() {
+ t.editor.windowManager.close(window);
+ tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup
+ };
+
+ if (tinymce.isOpera)
+ t.getWin().setTimeout(close, 0);
+ else
+ close();
+ },
+
+ // Internal functions
+
+ _restoreSelection : function() {
+ var e = window.event.srcElement;
+
+ if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button'))
+ tinyMCEPopup.restoreSelection();
+ },
+
+/* _restoreSelection : function() {
+ var e = window.event.srcElement;
+
+ // If user focus a non text input or textarea
+ if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text')
+ tinyMCEPopup.restoreSelection();
+ },*/
+
+ _onDOMLoaded : function() {
+ var t = this, ti = document.title, bm, h, nv;
+
+ // Translate page
+ if (t.features.translate_i18n !== false) {
+ h = document.body.innerHTML;
+
+ // Replace a=x with a="x" in IE
+ if (tinymce.isIE)
+ h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"')
+
+ document.dir = t.editor.getParam('directionality','');
+
+ if ((nv = t.editor.translate(h)) && nv != h)
+ document.body.innerHTML = nv;
+
+ if ((nv = t.editor.translate(ti)) && nv != ti)
+ document.title = ti = nv;
+ }
+
+ document.body.style.display = '';
+
+ // Restore selection in IE when focus is placed on a non textarea or input element of the type text
+ if (tinymce.isIE)
+ document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection);
+
+ t.restoreSelection();
+ t.resizeToInnerSize();
+
+ // Set inline title
+ if (!t.isWindow)
+ t.editor.windowManager.setTitle(window, ti);
+ else
+ window.focus();
+
+ if (!tinymce.isIE && !t.isWindow) {
+ tinymce.dom.Event._add(document, 'focus', function() {
+ t.editor.windowManager.focus(t.id)
+ });
+ }
+
+ // Patch for accessibility
+ tinymce.each(t.dom.select('select'), function(e) {
+ e.onkeydown = tinyMCEPopup._accessHandler;
+ });
+
+ // Call onInit
+ // Init must be called before focus so the selection won't get lost by the focus call
+ tinymce.each(t.listeners, function(o) {
+ o.func.call(o.scope, t.editor);
+ });
+
+ // Move focus to window
+ if (t.getWindowArg('mce_auto_focus', true)) {
+ window.focus();
+
+ // Focus element with mceFocus class
+ tinymce.each(document.forms, function(f) {
+ tinymce.each(f.elements, function(e) {
+ if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) {
+ e.focus();
+ return false; // Break loop
+ }
+ });
+ });
+ }
+
+ document.onkeyup = tinyMCEPopup._closeWinKeyHandler;
+ },
+
+ _accessHandler : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 13 || e.keyCode == 32) {
+ e = e.target || e.srcElement;
+
+ if (e.onchange)
+ e.onchange();
+
+ return tinymce.dom.Event.cancel(e);
+ }
+ },
+
+ _closeWinKeyHandler : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 27)
+ tinyMCEPopup.close();
+ },
+
+ _wait : function() {
+ var t = this, ti;
+
+ if (tinymce.isIE && document.location.protocol != 'https:') {
+ // Fake DOMContentLoaded on IE
+ document.write('
+
+
+text_direction) ) : ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Rich editing, also called WYSIWYG for What You See Is What You Get, means your text is formatted as you type. The rich editor creates HTML code behind the scenes while you concentrate on writing. Font styles, links and images all appear approximately as they will on the internet.') ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
( )
+
by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.'), '') ?>
+ Moxiecode Systems AB , All rights reserved.') ?>
+
TinyMCE website.') ?>
+
+
+
+
+
+
+
+
+
+
diff -uNr a/blog/wp-includes/js/tw-sack.js b/blog/wp-includes/js/tw-sack.js
--- a/blog/wp-includes/js/tw-sack.js false
+++ b/blog/wp-includes/js/tw-sack.js c1c40de55a85ca6606c301881f5f55be2615450d1696530c08252ebd9c1db81acb934591157aa099382e5a0e7506e9c47337213774795582393046599bdb131e
@@ -0,0 +1,193 @@
+/* Simple AJAX Code-Kit (SACK) v1.6.1 */
+/* ©2005 Gregory Wild-Smith */
+/* www.twilightuniverse.com */
+/* Software licenced under a modified X11 licence,
+ see documentation or authors website for more details */
+
+function sack(file) {
+ this.xmlhttp = null;
+
+ this.resetData = function() {
+ this.method = "POST";
+ this.queryStringSeparator = "?";
+ this.argumentSeparator = "&";
+ this.URLString = "";
+ this.encodeURIString = true;
+ this.execute = false;
+ this.element = null;
+ this.elementObj = null;
+ this.requestFile = file;
+ this.vars = new Object();
+ this.responseStatus = new Array(2);
+ };
+
+ this.resetFunctions = function() {
+ this.onLoading = function() { };
+ this.onLoaded = function() { };
+ this.onInteractive = function() { };
+ this.onCompletion = function() { };
+ this.onError = function() { };
+ this.onFail = function() { };
+ };
+
+ this.reset = function() {
+ this.resetFunctions();
+ this.resetData();
+ };
+
+ this.createAJAX = function() {
+ try {
+ this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e1) {
+ try {
+ this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+ } catch (e2) {
+ this.xmlhttp = null;
+ }
+ }
+
+ if (! this.xmlhttp) {
+ if (typeof XMLHttpRequest != "undefined") {
+ this.xmlhttp = new XMLHttpRequest();
+ } else {
+ this.failed = true;
+ }
+ }
+ };
+
+ this.setVar = function(name, value){
+ this.vars[name] = Array(value, false);
+ };
+
+ this.encVar = function(name, value, returnvars) {
+ if (true == returnvars) {
+ return Array(encodeURIComponent(name), encodeURIComponent(value));
+ } else {
+ this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value), true);
+ }
+ }
+
+ this.processURLString = function(string, encode) {
+ encoded = encodeURIComponent(this.argumentSeparator);
+ regexp = new RegExp(this.argumentSeparator + "|" + encoded);
+ varArray = string.split(regexp);
+ for (i = 0; i < varArray.length; i++){
+ urlVars = varArray[i].split("=");
+ if (true == encode){
+ this.encVar(urlVars[0], urlVars[1]);
+ } else {
+ this.setVar(urlVars[0], urlVars[1]);
+ }
+ }
+ }
+
+ this.createURLString = function(urlstring) {
+ if (this.encodeURIString && this.URLString.length) {
+ this.processURLString(this.URLString, true);
+ }
+
+ if (urlstring) {
+ if (this.URLString.length) {
+ this.URLString += this.argumentSeparator + urlstring;
+ } else {
+ this.URLString = urlstring;
+ }
+ }
+
+ // prevents caching of URLString
+ this.setVar("rndval", new Date().getTime());
+
+ urlstringtemp = new Array();
+ for (key in this.vars) {
+ if (false == this.vars[key][1] && true == this.encodeURIString) {
+ encoded = this.encVar(key, this.vars[key][0], true);
+ delete this.vars[key];
+ this.vars[encoded[0]] = Array(encoded[1], true);
+ key = encoded[0];
+ }
+
+ urlstringtemp[urlstringtemp.length] = key + "=" + this.vars[key][0];
+ }
+ if (urlstring){
+ this.URLString += this.argumentSeparator + urlstringtemp.join(this.argumentSeparator);
+ } else {
+ this.URLString += urlstringtemp.join(this.argumentSeparator);
+ }
+ }
+
+ this.runResponse = function() {
+ eval(this.response);
+ }
+
+ this.runAJAX = function(urlstring) {
+ if (this.failed) {
+ this.onFail();
+ } else {
+ this.createURLString(urlstring);
+ if (this.element) {
+ this.elementObj = document.getElementById(this.element);
+ }
+ if (this.xmlhttp) {
+ var self = this;
+ if (this.method == "GET") {
+ totalurlstring = this.requestFile + this.queryStringSeparator + this.URLString;
+ this.xmlhttp.open(this.method, totalurlstring, true);
+ } else {
+ this.xmlhttp.open(this.method, this.requestFile, true);
+ try {
+ this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
+ } catch (e) { }
+ }
+
+ this.xmlhttp.onreadystatechange = function() {
+ switch (self.xmlhttp.readyState) {
+ case 1:
+ self.onLoading();
+ break;
+ case 2:
+ self.onLoaded();
+ break;
+ case 3:
+ self.onInteractive();
+ break;
+ case 4:
+ self.response = self.xmlhttp.responseText;
+ self.responseXML = self.xmlhttp.responseXML;
+ self.responseStatus[0] = self.xmlhttp.status;
+ self.responseStatus[1] = self.xmlhttp.statusText;
+
+ if (self.execute) {
+ self.runResponse();
+ }
+
+ if (self.elementObj) {
+ elemNodeName = self.elementObj.nodeName;
+ elemNodeName.toLowerCase();
+ if (elemNodeName == "input"
+ || elemNodeName == "select"
+ || elemNodeName == "option"
+ || elemNodeName == "textarea") {
+ self.elementObj.value = self.response;
+ } else {
+ self.elementObj.innerHTML = self.response;
+ }
+ }
+ if (self.responseStatus[0] == "200") {
+ self.onCompletion();
+ } else {
+ self.onError();
+ }
+
+ self.URLString = "";
+ break;
+ }
+ };
+
+ this.xmlhttp.send(this.URLString);
+ }
+ }
+ };
+
+ this.reset();
+ this.createAJAX();
+}
diff -uNr a/blog/wp-includes/js/wp-ajax-response.js b/blog/wp-includes/js/wp-ajax-response.js
--- a/blog/wp-includes/js/wp-ajax-response.js false
+++ b/blog/wp-includes/js/wp-ajax-response.js cc8356fa3ea1fcc1848af7a2f608dac5ac4bae43ff5f91bd838d0b6090bd77405aab3e73c082f93a69f61bddd4dbe600c4a9f6722c77b25f63e8aaada3f73418
@@ -0,0 +1,60 @@
+wpAjax = jQuery.extend( {
+ unserialize: function( s ) {
+ var r = {}; if ( !s ) { return r; }
+ var q = s.split('?'); if ( q[1] ) { s = q[1]; }
+ var pp = s.split('&');
+ for ( var i in pp ) {
+ if ( jQuery.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
+ var p = pp[i].split('=');
+ r[p[0]] = p[1];
+ }
+ return r;
+ },
+ parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
+ var parsed = {};
+ var re = jQuery('#' + r).html('');
+ if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
+ parsed.responses = [];
+ parsed.errors = false;
+ var err = '';
+ jQuery('response', x).each( function() {
+ var th = jQuery(this);
+ var child = jQuery(this.firstChild);
+ var response = { action: th.attr('action'), what: child.get(0).nodeName, id: child.attr('id'), oldId: child.attr('old_id'), position: child.attr('position') };
+ response.data = jQuery( 'response_data', child ).text();
+ response.supplemental = {};
+ if ( !jQuery( 'supplemental', child ).children().each( function() {
+ response.supplemental[this.nodeName] = jQuery(this).text();
+ } ).size() ) { response.supplemental = false }
+ response.errors = [];
+ if ( !jQuery('wp_error', child).each( function() {
+ var code = jQuery(this).attr('code');
+ var anError = { code: code, message: this.firstChild.nodeValue, data: false };
+ var errorData = jQuery('wp_error_data[code="' + code + '"]', x);
+ if ( errorData ) { anError.data = errorData.get(); }
+ var formField = jQuery( 'form-field', errorData ).text();
+ if ( formField ) { code = formField; }
+ if ( e ) { wpAjax.invalidateForm( jQuery('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') ); }
+ err += '
' + anError.message + '
';
+ response.errors.push( anError );
+ parsed.errors = true;
+ } ).size() ) { response.errors = false; }
+ parsed.responses.push( response );
+ } );
+ if ( err.length ) { re.html( '
' + err + '
' ); }
+ return parsed;
+ }
+ if ( isNaN(x) ) { return !re.html('
'); }
+ x = parseInt(x,10);
+ if ( -1 == x ) { return !re.html('
'); }
+ else if ( 0 === x ) { return !re.html('
'); }
+ return true;
+ },
+ invalidateForm: function ( selector ) {
+ return jQuery( selector ).addClass( 'form-invalid' ).change( function() { jQuery(this).removeClass( 'form-invalid' ); } );
+ },
+ validateForm: function( selector ) {
+ selector = jQuery( selector );
+ return !wpAjax.invalidateForm( selector.find('.form-required').andSelf().filter('.form-required:has(:input[value=""]), .form-required:input[value=""]') ).size();
+ }
+}, wpAjax || { noPerm: 'You do not have permission to do that.', broken: 'An unidentified error has occurred.' } );
diff -uNr a/blog/wp-includes/js/wp-lists.js b/blog/wp-includes/js/wp-lists.js
--- a/blog/wp-includes/js/wp-lists.js false
+++ b/blog/wp-includes/js/wp-lists.js 82d4772f9af87b8762ddd5040227f8fe0d473fe40ca42f9ce00260c0d50ddd7fae785bec5b4f23331b525306b4e29f49fe273a683aca21b244fc70f1999e5fd5
@@ -0,0 +1,374 @@
+(function($) {
+var currentFormEl = false;
+var fs = {add:'ajaxAdd',del:'ajaxDel',dim:'ajaxDim',process:'process',recolor:'recolor'};
+
+var wpList = {
+ settings: {
+ url: wpListL10n.url, type: 'POST',
+ response: 'ajax-response',
+
+ what: '',
+ alt: 'alternate', altOffset: 0,
+ addColor: null, delColor: null, dimAddColor: null, dimDelColor: null,
+
+ confirm: null,
+ addBefore: null, addAfter: null,
+ delBefore: null, delAfter: null,
+ dimBefore: null, dimAfter: null
+ },
+
+ nonce: function(e,s) {
+ var url = wpAjax.unserialize(e.attr('href'));
+ return s.nonce || url._ajax_nonce || $('#' + s.element + ' input[name=_ajax_nonce]').val() || url._wpnonce || $('#' + s.element + ' input[name=_wpnonce]').val() || 0;
+ },
+
+ parseClass: function(e,t) {
+ var c = [], cl;
+ try {
+ cl = $(e).attr('class') || '';
+ cl = cl.match(new RegExp(t+':[\\S]+'));
+ if ( cl ) { c = cl[0].split(':'); }
+ } catch(r) {}
+ return c;
+ },
+
+ pre: function(e,s,a) {
+ var bg; var r;
+ s = $.extend( {}, this.wpList.settings, {
+ element: null,
+ nonce: 0,
+ target: e.get(0)
+ }, s || {} );
+ if ( $.isFunction( s.confirm ) ) {
+ if ( 'add' != a ) {
+ bg = $('#' + s.element).css('backgroundColor');
+ $('#' + s.element).css('backgroundColor', '#FF9966');
+ }
+ r = s.confirm.call(this,e,s,a,bg);
+ if ( 'add' != a ) { $('#' + s.element).css('backgroundColor', bg ); }
+ if ( !r ) { return false; }
+ }
+ return s;
+ },
+
+ ajaxAdd: function( e, s ) {
+ var list = this; e = $(e); s = s || {};
+ var cls = wpList.parseClass(e,'add');
+ s = wpList.pre.call( list, e, s, 'add' );
+
+ s.element = cls[2] || e.attr( 'id' ) || s.element || null;
+ if ( cls[3] ) { s.addColor = '#' + cls[3]; }
+ else { s.addColor = s.addColor || '#FFFF33'; }
+
+ if ( !s ) { return false; }
+
+ if ( !e.is("[class^=add:" + list.id + ":]") ) { return !wpList.add.call( list, e, s ); }
+
+ if ( !s.element ) { return true; }
+
+ s.action = 'add-' + s.what;
+
+ s.nonce = wpList.nonce(e,s);
+
+ var es = $('#' + s.element + ' :input').not('[name=_ajax_nonce], [name=_wpnonce], [name=action]');
+ var valid = wpAjax.validateForm( '#' + s.element );
+ if ( !valid ) { return false; }
+
+ s.data = $.param( $.extend( { _ajax_nonce: s.nonce, action: s.action }, wpAjax.unserialize( cls[4] || '' ) ) );
+ var formData = $.isFunction(es.fieldSerialize) ? es.fieldSerialize() : es.serialize();
+ if ( formData ) { s.data += '&' + formData; }
+
+ if ( $.isFunction(s.addBefore) ) {
+ s = s.addBefore( s );
+ if ( !s ) { return true; }
+ }
+ if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) ) { return true; }
+
+ s.success = function(r) {
+ var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+ if ( !res || res.errors ) { return false; }
+
+ if ( true === res ) { return true; }
+
+ jQuery.each( res.responses, function() {
+ wpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue
+ pos: this.position || 0,
+ id: this.id || 0,
+ oldId: this.oldId || null
+ } ) );
+ } );
+
+ if ( $.isFunction(s.addAfter) ) {
+ var o = this.complete;
+ this.complete = function(x,st) {
+ var _s = $.extend( { xml: x, status: st, parsed: res }, s );
+ s.addAfter( r, _s );
+ if ( $.isFunction(o) ) { o(x,st); }
+ };
+ }
+ list.wpList.recolor();
+ wpList.clear.call(list,'#' + s.element);
+ };
+
+ $.ajax( s );
+ return false;
+ },
+
+ ajaxDel: function( e, s ) {
+ var list = this; e = $(e); s = s || {};
+ var cls = wpList.parseClass(e,'delete');
+ s = wpList.pre.call( list, e, s, 'delete' );
+
+ s.element = cls[2] || s.element || null;
+ if ( cls[3] ) { s.delColor = '#' + cls[3]; }
+ else { s.delColor = s.delColor || '#FF3333'; }
+
+ if ( !s || !s.element ) { return false; }
+
+ s.action = 'delete-' + s.what;
+
+ s.nonce = wpList.nonce(e,s);
+
+ s.data = $.extend(
+ { action: s.action, id: s.element.split('-').pop(), _ajax_nonce: s.nonce },
+ wpAjax.unserialize( cls[4] || '' )
+ );
+
+ if ( $.isFunction(s.delBefore) ) {
+ s = s.delBefore( s );
+ if ( !s ) { return true; }
+ }
+ if ( !s.data._ajax_nonce ) { return true; }
+
+ var element = $('#' + s.element);
+
+ if ( 'none' != s.delColor ) {
+ var anim = 'slideUp';
+ if ( element.css( 'display' ).match(/table/) )
+ anim = 'fadeOut'; // Can't slideup table rows and other table elements. Known jQuery bug
+ element
+ .animate( { backgroundColor: s.delColor }, 'fast' )[anim]( 'fast' )
+ .queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
+ } else {
+ list.wpList.recolor();
+ }
+
+ s.success = function(r) {
+ var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+ if ( !res || res.errors ) {
+ element.stop().stop().css( 'backgroundColor', '#FF3333' ).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
+ return false;
+ }
+ if ( $.isFunction(s.delAfter) ) {
+ var o = this.complete;
+ this.complete = function(x,st) {
+ element.queue( function() {
+ var _s = $.extend( { xml: x, status: st, parsed: res }, s );
+ s.delAfter( r, _s );
+ if ( $.isFunction(o) ) { o(x,st); }
+ } ).dequeue();
+ };
+ }
+ };
+ $.ajax( s );
+ return false;
+ },
+
+ ajaxDim: function( e, s ) {
+ if ( $(e).parent().css('display') == 'none' ) // Prevent hidden links from being clicked by hotkeys
+ return false;
+ var list = this; e = $(e); s = s || {};
+ var cls = wpList.parseClass(e,'dim');
+ s = wpList.pre.call( list, e, s, 'dim' );
+
+ s.element = cls[2] || s.element || null;
+ s.dimClass = cls[3] || s.dimClass || null;
+ if ( cls[4] ) { s.dimAddColor = '#' + cls[4]; }
+ else { s.dimAddColor = s.dimAddColor || '#FFFF33'; }
+ if ( cls[5] ) { s.dimDelColor = '#' + cls[5]; }
+ else { s.dimDelColor = s.dimDelColor || '#FF3333'; }
+
+ if ( !s || !s.element || !s.dimClass ) { return true; }
+
+ s.action = 'dim-' + s.what;
+
+ s.nonce = wpList.nonce(e,s);
+
+ s.data = $.extend(
+ { action: s.action, id: s.element.split('-').pop(), dimClass: s.dimClass, _ajax_nonce : s.nonce },
+ wpAjax.unserialize( cls[6] || '' )
+ );
+
+ if ( $.isFunction(s.dimBefore) ) {
+ s = s.dimBefore( s );
+ if ( !s ) { return true; }
+ }
+
+ var element = $('#' + s.element);
+ var isClass = element.toggleClass(s.dimClass).is('.' + s.dimClass);
+ var color = wpList.getColor( element );
+ element.toggleClass( s.dimClass )
+ var dimColor = isClass ? s.dimAddColor : s.dimDelColor;
+ if ( 'none' != dimColor ) {
+ element
+ .animate( { backgroundColor: dimColor }, 'fast' )
+ .queue( function() { element.toggleClass(s.dimClass); $(this).dequeue(); } )
+ .animate( { backgroundColor: color }, { complete: function() { $(this).css( 'backgroundColor', '' ); } } );
+ }
+
+ if ( !s.data._ajax_nonce ) { return true; }
+
+ s.success = function(r) {
+ var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+ if ( !res || res.errors ) {
+ element.stop().stop().css( 'backgroundColor', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
+ return false;
+ }
+ if ( $.isFunction(s.dimAfter) ) {
+ var o = this.complete;
+ this.complete = function(x,st) {
+ element.queue( function() {
+ var _s = $.extend( { xml: x, status: st, parsed: res }, s );
+ s.dimAfter( r, _s );
+ if ( $.isFunction(o) ) { o(x,st); }
+ } ).dequeue();
+ };
+ }
+ };
+
+ $.ajax( s );
+ return false;
+ },
+
+ // From jquery.color.js: jQuery Color Animation by John Resig
+ getColor: function( el ) {
+ if ( el.constructor == Object )
+ el = el.get(0);
+ var elem = el, color, rgbaTrans = new RegExp( "rgba\\(\\s*0,\\s*0,\\s*0,\\s*0\\s*\\)", "i" );
+ do {
+ color = jQuery.curCSS(elem, 'backgroundColor');
+ if ( color != '' && color != 'transparent' && !color.match(rgbaTrans) || jQuery.nodeName(elem, "body") )
+ break;
+ } while ( elem = elem.parentNode );
+ return color || '#ffffff';
+ },
+
+ add: function( e, s ) {
+ var list = $(this);
+ e = $(e);
+
+ var old = false;
+ var _s = { pos: 0, id: 0, oldId: null };
+ if ( 'string' == typeof s ) { s = { what: s }; }
+ s = $.extend(_s, this.wpList.settings, s);
+ if ( !e.size() || !s.what ) { return false; }
+ if ( s.oldId ) { old = $('#' + s.what + '-' + s.oldId); }
+ if ( s.id && ( s.id != s.oldId || !old || !old.size() ) ) { $('#' + s.what + '-' + s.id).remove(); }
+
+ if ( old && old.size() ) {
+ old.replaceWith(e);
+ } else if ( isNaN(s.pos) ) {
+ var ba = 'after';
+ if ( '-' == s.pos.substr(0,1) ) {
+ s.pos = s.pos.substr(1);
+ ba = 'before';
+ }
+ var ref = list.find( '#' + s.pos );
+ if ( 1 === ref.size() ) { ref[ba](e); }
+ else { list.append(e); }
+ } else if ( s.pos < 0 ) {
+ list.prepend(e);
+ } else {
+ list.append(e);
+ }
+
+ if ( s.alt ) {
+ if ( ( list.children(':visible').index( e[0] ) + s.altOffset ) % 2 ) { e.removeClass( s.alt ); }
+ else { e.addClass( s.alt ); }
+ }
+
+ if ( 'none' != s.addColor ) {
+ var color = wpList.getColor( e );
+ e.css( 'backgroundColor', s.addColor ).animate( { backgroundColor: color }, { complete: function() { $(this).css( 'backgroundColor', '' ); } } );
+ }
+ list.each( function() { this.wpList.process( e ); } );
+ return e;
+ },
+
+ clear: function(e) {
+ var list = this;
+ e = $(e);
+ if ( list.wpList && e.parents( '#' + list.id ).size() ) { return; }
+ e.find(':input').each( function() {
+ if ( $(this).parents('.form-no-clear').size() )
+ return;
+ var t = this.type.toLowerCase(); var tag = this.tagName.toLowerCase();
+ if ( 'text' == t || 'password' == t || 'textarea' == tag ) { this.value = ''; }
+ else if ( 'checkbox' == t || 'radio' == t ) { this.checked = false; }
+ else if ( 'select' == tag ) { this.selectedIndex = null; }
+ });
+ },
+
+ process: function(el) {
+ var list = this;
+ $("[class^=add:" + list.id + ":]", el || null)
+ .filter('form').submit( function() { return list.wpList.add(this); } ).end()
+ .not('form').click( function() { return list.wpList.add(this); } ).each( function() {
+ var addEl = this;
+ var c = wpList.parseClass(this,'add')[2] || addEl.id;
+ if ( !c ) { return; }
+ var forms = []; var ins = []; // this is all really inefficient
+ $('#' + c + ' :input').focus( function() { currentFormEl = this; } ).blur( function() { currentFormEl = false; } ).each( function() {
+ ins.push(this);
+ var f = $(this).parents('form:first').get(0);
+ if ( $.inArray(f,forms) < 0 ) { forms.push(f); }
+ } );
+ $(forms).submit( function() {
+ if ( 0 <= $.inArray(currentFormEl,ins) ) {
+ $(addEl).trigger( 'click' );
+ $(currentFormEl).focus();
+ return false;
+ }
+ } );
+ } );
+ $("[class^=delete:" + list.id + ":]", el || null).click( function() { return list.wpList.del(this); } );
+ $("[class^=dim:" + list.id + ":]", el || null).click( function() { return list.wpList.dim(this); } );
+ },
+
+ recolor: function() {
+ var list = this;
+ if ( !list.wpList.settings.alt ) { return; }
+ var items = $('.list-item:visible', list);
+ if ( !items.size() ) { items = $(list).children(':visible'); }
+ var eo = [':even',':odd'];
+ if ( list.wpList.settings.altOffset % 2 ) { eo.reverse(); }
+ items.filter(eo[0]).addClass(list.wpList.settings.alt).end().filter(eo[1]).removeClass(list.wpList.settings.alt);
+ },
+
+ init: function() {
+ var lists = this;
+ lists.wpList.process = function(a) {
+ lists.each( function() {
+ this.wpList.process(a);
+ } );
+ };
+ lists.wpList.recolor = function() {
+ lists.each( function() {
+ this.wpList.recolor();
+ } );
+ };
+ }
+};
+
+$.fn.wpList = function( settings ) {
+ this.each( function() {
+ var _this = this;
+ this.wpList = { settings: $.extend( {}, wpList.settings, { what: wpList.parseClass(this,'list')[1] || '' }, settings ) };
+ $.each( fs, function(i,f) { _this.wpList[i] = function( e, s ) { return wpList[f].call( _this, e, s ); }; } );
+ } );
+ wpList.init.call(this);
+ this.wpList.process();
+ return this;
+};
+
+})(jQuery);
diff -uNr a/blog/wp-includes/kses.php b/blog/wp-includes/kses.php
--- a/blog/wp-includes/kses.php false
+++ b/blog/wp-includes/kses.php 2daa9c70fee5ac2290de8d1b2e9daefbe18e123b2da4338c8e7cc6d2f159e7bfe1706a213e92009596eda9f9a511c508d871e32e6d3887ca57ce50db7301b11b
@@ -0,0 +1,1128 @@
+
+ *
+ * @package External
+ * @subpackage KSES
+ *
+ * @internal
+ * *** CONTACT INFORMATION ***
+ * E-mail: metaur at users dot sourceforge dot net
+ * Web page: http://sourceforge.net/projects/kses
+ * Paper mail: Ulf Harnhammar
+ * Ymergatan 17 C
+ * 753 25 Uppsala
+ * SWEDEN
+ *
+ * [kses strips evil scripts!]
+ */
+
+/**
+ * You can override this in your my-hacks.php file You can also override this
+ * in a plugin file. The my-hacks.php is deprecated in its usage.
+ *
+ * @since 1.2.0
+ */
+if (!defined('CUSTOM_TAGS'))
+ define('CUSTOM_TAGS', false);
+
+if (!CUSTOM_TAGS) {
+ /**
+ * Kses global for default allowable HTML tags.
+ *
+ * Can be override by using CUSTOM_TAGS constant.
+ *
+ * @global array $allowedposttags
+ * @since 2.0.0
+ */
+ $allowedposttags = array(
+ 'address' => array(),
+ 'a' => array(
+ 'class' => array (),
+ 'href' => array (),
+ 'id' => array (),
+ 'title' => array (),
+ 'rel' => array (),
+ 'rev' => array (),
+ 'name' => array (),
+ 'target' => array()),
+ 'abbr' => array(
+ 'class' => array (),
+ 'title' => array ()),
+ 'acronym' => array(
+ 'title' => array ()),
+ 'b' => array(),
+ 'big' => array(),
+ 'blockquote' => array(
+ 'id' => array (),
+ 'cite' => array (),
+ 'class' => array(),
+ 'lang' => array(),
+ 'xml:lang' => array()),
+ 'br' => array (
+ 'class' => array ()),
+ 'button' => array(
+ 'disabled' => array (),
+ 'name' => array (),
+ 'type' => array (),
+ 'value' => array ()),
+ 'caption' => array(
+ 'align' => array (),
+ 'class' => array ()),
+ 'cite' => array (
+ 'class' => array(),
+ 'dir' => array(),
+ 'lang' => array(),
+ 'title' => array ()),
+ 'code' => array (
+ 'style' => array()),
+ 'col' => array(
+ 'align' => array (),
+ 'char' => array (),
+ 'charoff' => array (),
+ 'span' => array (),
+ 'dir' => array(),
+ 'style' => array (),
+ 'valign' => array (),
+ 'width' => array ()),
+ 'del' => array(
+ 'datetime' => array ()),
+ 'dd' => array(),
+ 'div' => array(
+ 'align' => array (),
+ 'class' => array (),
+ 'dir' => array (),
+ 'lang' => array(),
+ 'style' => array (),
+ 'xml:lang' => array()),
+ 'dl' => array(),
+ 'dt' => array(),
+ 'em' => array(),
+ 'fieldset' => array(),
+ 'font' => array(
+ 'color' => array (),
+ 'face' => array (),
+ 'size' => array ()),
+ 'form' => array(
+ 'action' => array (),
+ 'accept' => array (),
+ 'accept-charset' => array (),
+ 'enctype' => array (),
+ 'method' => array (),
+ 'name' => array (),
+ 'target' => array ()),
+ 'h1' => array(
+ 'align' => array (),
+ 'class' => array ()),
+ 'h2' => array(
+ 'align' => array (),
+ 'class' => array ()),
+ 'h3' => array(
+ 'align' => array (),
+ 'class' => array ()),
+ 'h4' => array(
+ 'align' => array (),
+ 'class' => array ()),
+ 'h5' => array(
+ 'align' => array (),
+ 'class' => array ()),
+ 'h6' => array(
+ 'align' => array (),
+ 'class' => array ()),
+ 'hr' => array(
+ 'align' => array (),
+ 'class' => array (),
+ 'noshade' => array (),
+ 'size' => array (),
+ 'width' => array ()),
+ 'i' => array(),
+ 'img' => array(
+ 'alt' => array (),
+ 'align' => array (),
+ 'border' => array (),
+ 'class' => array (),
+ 'height' => array (),
+ 'hspace' => array (),
+ 'longdesc' => array (),
+ 'vspace' => array (),
+ 'src' => array (),
+ 'style' => array (),
+ 'width' => array ()),
+ 'ins' => array(
+ 'datetime' => array (),
+ 'cite' => array ()),
+ 'kbd' => array(),
+ 'label' => array(
+ 'for' => array ()),
+ 'legend' => array(
+ 'align' => array ()),
+ 'li' => array (
+ 'align' => array (),
+ 'class' => array ()),
+ 'p' => array(
+ 'class' => array (),
+ 'align' => array (),
+ 'dir' => array(),
+ 'lang' => array(),
+ 'style' => array (),
+ 'xml:lang' => array()),
+ 'pre' => array(
+ 'style' => array(),
+ 'width' => array ()),
+ 'q' => array(
+ 'cite' => array ()),
+ 's' => array(),
+ 'span' => array (
+ 'class' => array (),
+ 'dir' => array (),
+ 'align' => array (),
+ 'lang' => array (),
+ 'style' => array (),
+ 'title' => array (),
+ 'xml:lang' => array()),
+ 'strike' => array(),
+ 'strong' => array(),
+ 'sub' => array(),
+ 'sup' => array(),
+ 'table' => array(
+ 'align' => array (),
+ 'bgcolor' => array (),
+ 'border' => array (),
+ 'cellpadding' => array (),
+ 'cellspacing' => array (),
+ 'class' => array (),
+ 'dir' => array(),
+ 'id' => array(),
+ 'rules' => array (),
+ 'style' => array (),
+ 'summary' => array (),
+ 'width' => array ()),
+ 'tbody' => array(
+ 'align' => array (),
+ 'char' => array (),
+ 'charoff' => array (),
+ 'valign' => array ()),
+ 'td' => array(
+ 'abbr' => array (),
+ 'align' => array (),
+ 'axis' => array (),
+ 'bgcolor' => array (),
+ 'char' => array (),
+ 'charoff' => array (),
+ 'class' => array (),
+ 'colspan' => array (),
+ 'dir' => array(),
+ 'headers' => array (),
+ 'height' => array (),
+ 'nowrap' => array (),
+ 'rowspan' => array (),
+ 'scope' => array (),
+ 'style' => array (),
+ 'valign' => array (),
+ 'width' => array ()),
+ 'textarea' => array(
+ 'cols' => array (),
+ 'rows' => array (),
+ 'disabled' => array (),
+ 'name' => array (),
+ 'readonly' => array ()),
+ 'tfoot' => array(
+ 'align' => array (),
+ 'char' => array (),
+ 'class' => array (),
+ 'charoff' => array (),
+ 'valign' => array ()),
+ 'th' => array(
+ 'abbr' => array (),
+ 'align' => array (),
+ 'axis' => array (),
+ 'bgcolor' => array (),
+ 'char' => array (),
+ 'charoff' => array (),
+ 'class' => array (),
+ 'colspan' => array (),
+ 'headers' => array (),
+ 'height' => array (),
+ 'nowrap' => array (),
+ 'rowspan' => array (),
+ 'scope' => array (),
+ 'valign' => array (),
+ 'width' => array ()),
+ 'thead' => array(
+ 'align' => array (),
+ 'char' => array (),
+ 'charoff' => array (),
+ 'class' => array (),
+ 'valign' => array ()),
+ 'title' => array(),
+ 'tr' => array(
+ 'align' => array (),
+ 'bgcolor' => array (),
+ 'char' => array (),
+ 'charoff' => array (),
+ 'class' => array (),
+ 'style' => array (),
+ 'valign' => array ()),
+ 'tt' => array(),
+ 'u' => array(),
+ 'ul' => array (
+ 'class' => array (),
+ 'style' => array (),
+ 'type' => array ()),
+ 'ol' => array (
+ 'class' => array (),
+ 'start' => array (),
+ 'style' => array (),
+ 'type' => array ()),
+ 'var' => array ());
+
+ /**
+ * Kses allowed HTML elements.
+ *
+ * @global array $allowedtags
+ * @since 1.0.0
+ */
+ $allowedtags = array(
+ 'a' => array(
+ 'href' => array (),
+ 'title' => array ()),
+ 'abbr' => array(
+ 'title' => array ()),
+ 'acronym' => array(
+ 'title' => array ()),
+ 'b' => array(),
+ 'blockquote' => array(
+ 'cite' => array ()),
+ // 'br' => array(),
+ 'cite' => array (),
+ 'code' => array(),
+ 'del' => array(
+ 'datetime' => array ()),
+ // 'dd' => array(),
+ // 'dl' => array(),
+ // 'dt' => array(),
+ 'em' => array (), 'i' => array (),
+ // 'ins' => array('datetime' => array(), 'cite' => array()),
+ // 'li' => array(),
+ // 'ol' => array(),
+ // 'p' => array(),
+ 'q' => array(
+ 'cite' => array ()),
+ 'strike' => array(),
+ 'strong' => array(),
+ // 'sub' => array(),
+ // 'sup' => array(),
+ // 'u' => array(),
+ // 'ul' => array(),
+ );
+}
+
+/**
+ * Filters content and keeps only allowable HTML elements.
+ *
+ * This function makes sure that only the allowed HTML element names, attribute
+ * names and attribute values plus only sane HTML entities will occur in
+ * $string. You have to remove any slashes from PHP's magic quotes before you
+ * call this function.
+ *
+ * The default allowed protocols are 'http', 'https', 'ftp', 'mailto', 'news',
+ * 'irc', 'gopher', 'nntp', 'feed', and finally 'telnet. This covers all common
+ * link protocols, except for 'javascript' which should not be allowed for
+ * untrusted users.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter through kses
+ * @param array $allowed_html List of allowed HTML elements
+ * @param array $allowed_protocols Optional. Allowed protocol in links.
+ * @return string Filtered content with only allowed HTML elements
+ */
+function wp_kses($string, $allowed_html, $allowed_protocols = array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet')) {
+ $string = wp_kses_no_null($string);
+ $string = wp_kses_js_entities($string);
+ $string = wp_kses_normalize_entities($string);
+ $allowed_html_fixed = wp_kses_array_lc($allowed_html);
+ $string = wp_kses_hook($string, $allowed_html_fixed, $allowed_protocols); // WP changed the order of these funcs and added args to wp_kses_hook
+ return wp_kses_split($string, $allowed_html_fixed, $allowed_protocols);
+}
+
+/**
+ * You add any kses hooks here.
+ *
+ * There is currently only one kses WordPress hook and it is called here. All
+ * parameters are passed to the hooks and expected to recieve a string.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter through kses
+ * @param array $allowed_html List of allowed HTML elements
+ * @param array $allowed_protocols Allowed protocol in links
+ * @return string Filtered content through 'pre_kses' hook
+ */
+function wp_kses_hook($string, $allowed_html, $allowed_protocols) {
+ $string = apply_filters('pre_kses', $string, $allowed_html, $allowed_protocols);
+ return $string;
+}
+
+/**
+ * This function returns kses' version number.
+ *
+ * @since 1.0.0
+ *
+ * @return string KSES Version Number
+ */
+function wp_kses_version() {
+ return '0.2.2';
+}
+
+/**
+ * Searches for HTML tags, no matter how malformed.
+ *
+ * It also matches stray ">" characters.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter
+ * @param array $allowed_html Allowed HTML elements
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Content with fixed HTML tags
+ */
+function wp_kses_split($string, $allowed_html, $allowed_protocols) {
+ return preg_replace_callback('%((|$))|(<[^>]*(>|$)|>))%',
+ function($match) {
+ return wp_kses_split2($match[1], $allowed_html, $allowed_protocols);
+ }, $string);
+}
+
+/**
+ * Callback for wp_kses_split for fixing malformed HTML tags.
+ *
+ * This function does a lot of work. It rejects some very malformed things like
+ * <:::>. It returns an empty string, if the element isn't allowed (look ma, no
+ * strip_tags()!). Otherwise it splits the tag into an element and an attribute
+ * list.
+ *
+ * After the tag is split into an element and an attribute list, it is run
+ * through another filter which will remove illegal attributes and once that is
+ * completed, will be returned.
+ *
+ * @access private
+ * @since 1.0.0
+ * @uses wp_kses_attr()
+ *
+ * @param string $string Content to filter
+ * @param array $allowed_html Allowed HTML elements
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Fixed HTML element
+ */
+function wp_kses_split2($string, $allowed_html, $allowed_protocols) {
+ $string = wp_kses_stripslashes($string);
+
+ if (substr($string, 0, 1) != '<')
+ return '>';
+ # It matched a ">" character
+
+ if (preg_match('%^)?$%', $string, $matches)) {
+ $string = str_replace(array(''), '', $matches[1]);
+ while ( $string != $newstring = wp_kses($string, $allowed_html, $allowed_protocols) )
+ $string = $newstring;
+ if ( $string == '' )
+ return '';
+ // prevent multiple dashes in comments
+ $string = preg_replace('/--+/', '-', $string);
+ // prevent three dashes closing a comment
+ $string = preg_replace('/-$/', '', $string);
+ return "";
+ }
+ # Allow HTML comments
+
+ if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
+ return '';
+ # It's seriously malformed
+
+ $slash = trim($matches[1]);
+ $elem = $matches[2];
+ $attrlist = $matches[3];
+
+ if (!@isset($allowed_html[strtolower($elem)]))
+ return '';
+ # They are using a not allowed HTML element
+
+ if ($slash != '')
+ return "<$slash$elem>";
+ # No attributes are allowed for closing elements
+
+ return wp_kses_attr("$slash$elem", $attrlist, $allowed_html, $allowed_protocols);
+}
+
+/**
+ * Removes all attributes, if none are allowed for this element.
+ *
+ * If some are allowed it calls wp_kses_hair() to split them further, and then
+ * it builds up new HTML code from the data that kses_hair() returns. It also
+ * removes "<" and ">" characters, if there are any left. One more thing it does
+ * is to check if the tag has a closing XHTML slash, and if it does, it puts one
+ * in the returned code as well.
+ *
+ * @since 1.0.0
+ *
+ * @param string $element HTML element/tag
+ * @param string $attr HTML attributes from HTML element to closing HTML element tag
+ * @param array $allowed_html Allowed HTML elements
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Sanitized HTML element
+ */
+function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
+ # Is there a closing XHTML slash at the end of the attributes?
+
+ $xhtml_slash = '';
+ if (preg_match('%\s/\s*$%', $attr))
+ $xhtml_slash = ' /';
+
+ # Are any attributes allowed at all for this element?
+
+ if (@ count($allowed_html[strtolower($element)]) == 0)
+ return "<$element$xhtml_slash>";
+
+ # Split it
+
+ $attrarr = wp_kses_hair($attr, $allowed_protocols);
+
+ # Go through $attrarr, and save the allowed attributes for this element
+ # in $attr2
+
+ $attr2 = '';
+
+ foreach ($attrarr as $arreach) {
+ if (!@ isset ($allowed_html[strtolower($element)][strtolower($arreach['name'])]))
+ continue; # the attribute is not allowed
+
+ $current = $allowed_html[strtolower($element)][strtolower($arreach['name'])];
+ if ($current == '')
+ continue; # the attribute is not allowed
+
+ if (!is_array($current))
+ $attr2 .= ' '.$arreach['whole'];
+ # there are no checks
+
+ else {
+ # there are some checks
+ $ok = true;
+ foreach ($current as $currkey => $currval)
+ if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
+ $ok = false;
+ break;
+ }
+
+ if ($ok)
+ $attr2 .= ' '.$arreach['whole']; # it passed them
+ } # if !is_array($current)
+ } # foreach
+
+ # Remove any "<" or ">" characters
+
+ $attr2 = preg_replace('/[<>]/', '', $attr2);
+
+ return "<$element$attr2$xhtml_slash>";
+}
+
+/**
+ * Builds an attribute list from string containing attributes.
+ *
+ * This function does a lot of work. It parses an attribute list into an array
+ * with attribute data, and tries to do the right thing even if it gets weird
+ * input. It will add quotes around attribute values that don't have any quotes
+ * or apostrophes around them, to make it easier to produce HTML code that will
+ * conform to W3C's HTML specification. It will also remove bad URL protocols
+ * from attribute values. It also reduces duplicate attributes by using the
+ * attribute defined first (foo='bar' foo='baz' will result in foo='bar').
+ *
+ * @since 1.0.0
+ *
+ * @param string $attr Attribute list from HTML element to closing HTML element tag
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return array List of attributes after parsing
+ */
+function wp_kses_hair($attr, $allowed_protocols) {
+ $attrarr = array ();
+ $mode = 0;
+ $attrname = '';
+ $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action');
+
+ # Loop through the whole attribute list
+
+ while (strlen($attr) != 0) {
+ $working = 0; # Was the last operation successful?
+
+ switch ($mode) {
+ case 0 : # attribute name, href for instance
+
+ if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
+ $attrname = $match[1];
+ $working = $mode = 1;
+ $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
+ }
+
+ break;
+
+ case 1 : # equals sign or valueless ("selected")
+
+ if (preg_match('/^\s*=\s*/', $attr)) # equals sign
+ {
+ $working = 1;
+ $mode = 2;
+ $attr = preg_replace('/^\s*=\s*/', '', $attr);
+ break;
+ }
+
+ if (preg_match('/^\s+/', $attr)) # valueless
+ {
+ $working = 1;
+ $mode = 0;
+ if(FALSE === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
+ }
+ $attr = preg_replace('/^\s+/', '', $attr);
+ }
+
+ break;
+
+ case 2 : # attribute value, a URL after href= for instance
+
+ if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match))
+ # "value"
+ {
+ $thisval = $match[1];
+ if ( in_array($attrname, $uris) )
+ $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
+
+ if(FALSE === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
+ }
+ $working = 1;
+ $mode = 0;
+ $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
+ break;
+ }
+
+ if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match))
+ # 'value'
+ {
+ $thisval = $match[1];
+ if ( in_array($attrname, $uris) )
+ $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
+
+ if(FALSE === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n');
+ }
+ $working = 1;
+ $mode = 0;
+ $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
+ break;
+ }
+
+ if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match))
+ # value
+ {
+ $thisval = $match[1];
+ if ( in_array($attrname, $uris) )
+ $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
+
+ if(FALSE === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
+ }
+ # We add quotes to conform to W3C's HTML spec.
+ $working = 1;
+ $mode = 0;
+ $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
+ }
+
+ break;
+ } # switch
+
+ if ($working == 0) # not well formed, remove and try again
+ {
+ $attr = wp_kses_html_error($attr);
+ $mode = 0;
+ }
+ } # while
+
+ if ($mode == 1 && FALSE === array_key_exists($attrname, $attrarr))
+ # special case, for when the attribute list ends with a valueless
+ # attribute like "selected"
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
+
+ return $attrarr;
+}
+
+/**
+ * Performs different checks for attribute values.
+ *
+ * The currently implemented checks are "maxlen", "minlen", "maxval", "minval"
+ * and "valueless" with even more checks to come soon.
+ *
+ * @since 1.0.0
+ *
+ * @param string $value Attribute value
+ * @param string $vless Whether the value is valueless or not. Use 'y' or 'n'
+ * @param string $checkname What $checkvalue is checking for.
+ * @param mixed $checkvalue What constraint the value should pass
+ * @return bool Whether check passes (true) or not (false)
+ */
+function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) {
+ $ok = true;
+
+ switch (strtolower($checkname)) {
+ case 'maxlen' :
+ # The maxlen check makes sure that the attribute value has a length not
+ # greater than the given value. This can be used to avoid Buffer Overflows
+ # in WWW clients and various Internet servers.
+
+ if (strlen($value) > $checkvalue)
+ $ok = false;
+ break;
+
+ case 'minlen' :
+ # The minlen check makes sure that the attribute value has a length not
+ # smaller than the given value.
+
+ if (strlen($value) < $checkvalue)
+ $ok = false;
+ break;
+
+ case 'maxval' :
+ # The maxval check does two things: it checks that the attribute value is
+ # an integer from 0 and up, without an excessive amount of zeroes or
+ # whitespace (to avoid Buffer Overflows). It also checks that the attribute
+ # value is not greater than the given value.
+ # This check can be used to avoid Denial of Service attacks.
+
+ if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
+ $ok = false;
+ if ($value > $checkvalue)
+ $ok = false;
+ break;
+
+ case 'minval' :
+ # The minval check checks that the attribute value is a positive integer,
+ # and that it is not smaller than the given value.
+
+ if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
+ $ok = false;
+ if ($value < $checkvalue)
+ $ok = false;
+ break;
+
+ case 'valueless' :
+ # The valueless check checks if the attribute has a value
+ # (like
) or not (). If the given value
+ # is a "y" or a "Y", the attribute must not have a value.
+ # If the given value is an "n" or an "N", the attribute must have one.
+
+ if (strtolower($checkvalue) != $vless)
+ $ok = false;
+ break;
+ } # switch
+
+ return $ok;
+}
+
+/**
+ * Sanitize string from bad protocols.
+ *
+ * This function removes all non-allowed protocols from the beginning of
+ * $string. It ignores whitespace and the case of the letters, and it does
+ * understand HTML entities. It does its work in a while loop, so it won't be
+ * fooled by a string like "javascript:javascript:alert(57)".
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter bad protocols from
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Filtered content
+ */
+function wp_kses_bad_protocol($string, $allowed_protocols) {
+ $string = wp_kses_no_null($string);
+ $string = preg_replace('/\xad+/', '', $string); # deals with Opera "feature"
+ $string2 = $string.'a';
+
+ while ($string != $string2) {
+ $string2 = $string;
+ $string = wp_kses_bad_protocol_once($string, $allowed_protocols);
+ } # while
+
+ return $string;
+}
+
+/**
+ * Removes any NULL characters in $string.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string
+ * @return string
+ */
+function wp_kses_no_null($string) {
+ $string = preg_replace('/\0+/', '', $string);
+ $string = preg_replace('/(\\\\0)+/', '', $string);
+
+ return $string;
+}
+
+/**
+ * Strips slashes from in front of quotes.
+ *
+ * This function changes the character sequence \" to just ". It leaves all
+ * other slashes alone. It's really weird, but the quoting from
+ * preg_replace(//e) seems to require this.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string String to strip slashes
+ * @return string Fixed strings with quoted slashes
+ */
+function wp_kses_stripslashes($string) {
+ return preg_replace('%\\\\"%', '"', $string);
+}
+
+/**
+ * Goes through an array and changes the keys to all lower case.
+ *
+ * @since 1.0.0
+ *
+ * @param array $inarray Unfiltered array
+ * @return array Fixed array with all lowercase keys
+ */
+function wp_kses_array_lc($inarray) {
+ $outarray = array ();
+
+ foreach ( (array) $inarray as $inkey => $inval) {
+ $outkey = strtolower($inkey);
+ $outarray[$outkey] = array ();
+
+ foreach ( (array) $inval as $inkey2 => $inval2) {
+ $outkey2 = strtolower($inkey2);
+ $outarray[$outkey][$outkey2] = $inval2;
+ } # foreach $inval
+ } # foreach $inarray
+
+ return $outarray;
+}
+
+/**
+ * Removes the HTML JavaScript entities found in early versions of Netscape 4.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string
+ * @return string
+ */
+function wp_kses_js_entities($string) {
+ return preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
+}
+
+/**
+ * Handles parsing errors in wp_kses_hair().
+ *
+ * The general plan is to remove everything to and including some whitespace,
+ * but it deals with quotes and apostrophes as well.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string
+ * @return string
+ */
+function wp_kses_html_error($string) {
+ return preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $string);
+}
+
+/**
+ * Sanitizes content from bad protocols and other characters.
+ *
+ * This function searches for URL protocols at the beginning of $string, while
+ * handling whitespace and HTML entities.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to check for bad protocols
+ * @param string $allowed_protocols Allowed protocols
+ * @return string Sanitized content
+ */
+function wp_kses_bad_protocol_once($string, $allowed_protocols) {
+ global $_kses_allowed_protocols;
+ $_kses_allowed_protocols = $allowed_protocols;
+
+ $string2 = preg_split('/:|:|:/i', $string, 2);
+ if ( isset($string2[1]) && !preg_match('%/\?%', $string2[0]) )
+ $string = wp_kses_bad_protocol_once2($string2[0]) . trim($string2[1]);
+ else
+ $string = preg_replace_callback('/^((&[^;]*;|[\sA-Za-z0-9])*)'.'(:|:|&#[Xx]3[Aa];)\s*/', 'wp_kses_bad_protocol_once2', $string);
+
+ return $string;
+}
+
+/**
+ * Callback for wp_kses_bad_protocol_once() regular expression.
+ *
+ * This function processes URL protocols, checks to see if they're in the
+ * white-list or not, and returns different data depending on the answer.
+ *
+ * @access private
+ * @since 1.0.0
+ *
+ * @param mixed $matches string or preg_replace_callback() matches array to check for bad protocols
+ * @return string Sanitized content
+ */
+function wp_kses_bad_protocol_once2($matches) {
+ global $_kses_allowed_protocols;
+
+ if ( is_array($matches) ) {
+ if ( ! isset($matches[1]) || empty($matches[1]) )
+ return '';
+
+ $string = $matches[1];
+ } else {
+ $string = $matches;
+ }
+
+ $string2 = wp_kses_decode_entities($string);
+ $string2 = preg_replace('/\s/', '', $string2);
+ $string2 = wp_kses_no_null($string2);
+ $string2 = preg_replace('/\xad+/', '', $string2);
+ # deals with Opera "feature"
+ $string2 = strtolower($string2);
+
+ $allowed = false;
+ foreach ( (array) $_kses_allowed_protocols as $one_protocol)
+ if (strtolower($one_protocol) == $string2) {
+ $allowed = true;
+ break;
+ }
+
+ if ($allowed)
+ return "$string2:";
+ else
+ return '';
+}
+
+/**
+ * Converts and fixes HTML entities.
+ *
+ * This function normalizes HTML entities. It will convert "AT&T" to the correct
+ * "AT&T", ":" to ":", "&#XYZZY;" to "&#XYZZY;" and so on.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to normalize entities
+ * @return string Content with normalized entities
+ */
+function wp_kses_normalize_entities($string) {
+ # Disarm all entities by converting & to &
+
+ $string = str_replace('&', '&', $string);
+
+ # Change back the allowed entities in our entity whitelist
+
+ $string = preg_replace('/&([A-Za-z][A-Za-z0-9]{0,19});/', '&\\1;', $string);
+ $string = preg_replace_callback('/�*([0-9]{1,5});/', 'wp_kses_normalize_entities2', $string);
+ $string = preg_replace_callback('/&#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/', 'wp_kses_normalize_entities3', $string);
+
+ return $string;
+}
+
+/**
+ * Callback for wp_kses_normalize_entities() regular expression.
+ *
+ * This function helps wp_kses_normalize_entities() to only accept 16 bit values
+ * and nothing more for &#number; entities.
+ *
+ * @access private
+ * @since 1.0.0
+ *
+ * @param array $matches preg_replace_callback() matches array
+ * @return string Correctly encoded entity
+ */
+function wp_kses_normalize_entities2($matches) {
+ if ( ! isset($matches[1]) || empty($matches[1]) )
+ return '';
+
+ $i = $matches[1];
+ return ( ( ! valid_unicode($i) ) || ($i > 65535) ? "&#$i;" : "&#$i;" );
+}
+
+/**
+ * Callback for wp_kses_normalize_entities() for regular expression.
+ *
+ * This function helps wp_kses_normalize_entities() to only accept valid Unicode
+ * numeric entities in hex form.
+ *
+ * @access private
+ *
+ * @param array $matches preg_replace_callback() matches array
+ * @return string Correctly encoded entity
+ */
+function wp_kses_normalize_entities3($matches) {
+ if ( ! isset($matches[2]) || empty($matches[2]) )
+ return '';
+
+ $hexchars = $matches[2];
+ return ( ( ! valid_unicode(hexdec($hexchars)) ) ? "&#x$hexchars;" : "&#x$hexchars;" );
+}
+
+/**
+ * Helper function to determine if a Unicode value is valid.
+ *
+ * @param int $i Unicode value
+ * @return bool true if the value was a valid Unicode number
+ */
+function valid_unicode($i) {
+ return ( $i == 0x9 || $i == 0xa || $i == 0xd ||
+ ($i >= 0x20 && $i <= 0xd7ff) ||
+ ($i >= 0xe000 && $i <= 0xfffd) ||
+ ($i >= 0x10000 && $i <= 0x10ffff) );
+}
+
+/**
+ * Convert all entities to their character counterparts.
+ *
+ * This function decodes numeric HTML entities (A and A). It doesn't do
+ * anything with other entities like ä, but we don't need them in the URL
+ * protocol whitelisting system anyway.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to change entities
+ * @return string Content after decoded entities
+ */
+function wp_kses_decode_entities($string) {
+ $string = preg_replace_callback('/&#([0-9]+);/', function($match) {
+ return chr($match[1]);
+ }, $string);
+ $string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', function($match) {
+ return chr(hexdec($match[1]));
+ }, $string);
+
+ return $string;
+}
+
+/**
+ * Sanitize content with allowed HTML Kses rules.
+ *
+ * @since 1.0.0
+ * @uses $allowedtags
+ *
+ * @param string $data Content to filter
+ * @return string Filtered content
+ */
+function wp_filter_kses($data) {
+ global $allowedtags;
+ return addslashes( wp_kses(stripslashes( $data ), $allowedtags) );
+}
+
+/**
+ * Sanitize content for allowed HTML tags for post content.
+ *
+ * Post content refers to the page contents of the 'post' type and not $_POST
+ * data from forms.
+ *
+ * @since 2.0.0
+ * @uses $allowedposttags
+ *
+ * @param string $data Post content to filter
+ * @return string Filtered post content with allowed HTML tags and attributes intact.
+ */
+function wp_filter_post_kses($data) {
+ global $allowedposttags;
+ return addslashes ( wp_kses(stripslashes( $data ), $allowedposttags) );
+}
+
+/**
+ * Strips all of the HTML in the content.
+ *
+ * @since 2.1.0
+ *
+ * @param string $data Content to strip all HTML from
+ * @return string Filtered content without any HTML
+ */
+function wp_filter_nohtml_kses($data) {
+ return addslashes ( wp_kses(stripslashes( $data ), array()) );
+}
+
+/**
+ * Adds all Kses input form content filters.
+ *
+ * All hooks have default priority. The wp_filter_kses() function is added to
+ * the 'pre_comment_content' and 'title_save_pre' hooks.
+ *
+ * The wp_filter_post_kses() function is added to the 'content_save_pre',
+ * 'excerpt_save_pre', and 'content_filtered_save_pre' hooks.
+ *
+ * @since 2.0.0
+ * @uses add_filter() See description for what functions are added to what hooks.
+ */
+function kses_init_filters() {
+ // Normal filtering.
+ add_filter('pre_comment_content', 'wp_filter_kses');
+ add_filter('title_save_pre', 'wp_filter_kses');
+
+ // Post filtering
+ add_filter('content_save_pre', 'wp_filter_post_kses');
+ add_filter('excerpt_save_pre', 'wp_filter_post_kses');
+ add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
+}
+
+/**
+ * Removes all Kses input form content filters.
+ *
+ * A quick procedural method to removing all of the filters that kses uses for
+ * content in WordPress Loop.
+ *
+ * Does not remove the kses_init() function from 'init' hook (priority is
+ * default). Also does not remove kses_init() function from 'set_current_user'
+ * hook (priority is also default).
+ *
+ * @since 2.0.6
+ */
+function kses_remove_filters() {
+ // Normal filtering.
+ remove_filter('pre_comment_content', 'wp_filter_kses');
+ remove_filter('title_save_pre', 'wp_filter_kses');
+
+ // Post filtering
+ remove_filter('content_save_pre', 'wp_filter_post_kses');
+ remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
+ remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
+}
+
+/**
+ * Sets up most of the Kses filters for input form content.
+ *
+ * If you remove the kses_init() function from 'init' hook and
+ * 'set_current_user' (priority is default), then none of the Kses filter hooks
+ * will be added.
+ *
+ * First removes all of the Kses filters in case the current user does not need
+ * to have Kses filter the content. If the user does not have unfiltered html
+ * capability, then Kses filters are added.
+ *
+ * @uses kses_remove_filters() Removes the Kses filters
+ * @uses kses_init_filters() Adds the Kses filters back if the user
+ * does not have unfiltered HTML capability.
+ * @since 2.0.0
+ */
+function kses_init() {
+ kses_remove_filters();
+
+ if (current_user_can('unfiltered_html') == false)
+ kses_init_filters();
+}
+
+add_action('init', 'kses_init');
+add_action('set_current_user', 'kses_init');
+?>
diff -uNr a/blog/wp-includes/l10n.php b/blog/wp-includes/l10n.php
--- a/blog/wp-includes/l10n.php false
+++ b/blog/wp-includes/l10n.php e395f6f2e1b74aa7afd931df5941535dee440c577080a01df45543b248ae3645401a37f1ec193fe8d6ff99d4cd746745b0d391192f7ba38ee6097dd2943e3347
@@ -0,0 +1,343 @@
+translate($text), $text, $domain);
+ else
+ return apply_filters('gettext', $text, $text, $domain);
+}
+
+function before_last_bar( $string ) {
+ $last_bar = strrpos( $string, '|' );
+ if ( false == $last_bar )
+ return $string;
+ else
+ return substr( $string, 0, $last_bar );
+}
+
+/**
+ * Retrieve the translated text and strip context.
+ *
+ * If the domain is set in the $l10n global, then the text is run through the
+ * domain's translate method. After it is passed to the 'gettext' filter hook,
+ * along with the untranslated text as the second parameter.
+ *
+ * If the domain is not set, the $text is just returned.
+ *
+ * @since 2.5
+ * @uses translate()
+ *
+ * @param string $text Text to translate
+ * @param string $domain Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function translate_with_context( $text, $domain = 'default' ) {
+ return before_last_bar( translate( $text, $domain ) );
+
+}
+
+/**
+ * Retrieves the translated string from the translate().
+ *
+ * @see translate() An alias of translate()
+ * @since 2.1.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function __($text, $domain = 'default') {
+ return translate($text, $domain);
+}
+
+/**
+ * Displays the returned translated text from translate().
+ *
+ * @see translate() Echos returned translate() string
+ * @since 1.2.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ */
+function _e($text, $domain = 'default') {
+ echo translate($text, $domain);
+}
+
+/**
+ * Retrieve context translated string.
+ *
+ * Quite a few times, there will be collisions with similar translatable text
+ * found in more than two places but with different translated context.
+ *
+ * In order to use the separate contexts, the _c() function is used and the
+ * translatable string uses a pipe ('|') which has the context the string is in.
+ *
+ * When the translated string is returned, it is everything before the pipe, not
+ * including the pipe character. If there is no pipe in the translated text then
+ * everything is returned.
+ *
+ * @since 2.2.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated context string without pipe
+ */
+function _c($text, $domain = 'default') {
+ return translate_with_context($text, $domain);
+}
+
+/**
+ * Retrieve the plural or single form based on the amount.
+ *
+ * If the domain is not set in the $l10n list, then a comparsion will be made
+ * and either $plural or $single parameters returned.
+ *
+ * If the domain does exist, then the parameters $single, $plural, and $number
+ * will first be passed to the domain's ngettext method. Then it will be passed
+ * to the 'ngettext' filter hook along with the same parameters. The expected
+ * type will be a string.
+ *
+ * @since 1.2.0
+ * @uses $l10n Gets list of domain translated string (gettext_reader) objects
+ * @uses apply_filters() Calls 'ngettext' hook on domains text returned,
+ * along with $single, $plural, and $number parameters. Expected to return string.
+ *
+ * @param string $single The text that will be used if $number is 1
+ * @param string $plural The text that will be used if $number is not 1
+ * @param int $number The number to compare against to use either $single or $plural
+ * @param string $domain Optional. The domain identifier the text should be retrieved in
+ * @return string Either $single or $plural translated text
+ */
+function __ngettext($single, $plural, $number, $domain = 'default') {
+ global $l10n;
+
+ if (isset($l10n[$domain])) {
+ return apply_filters('ngettext', $l10n[$domain]->ngettext($single, $plural, $number), $single, $plural, $number);
+ } else {
+ if ($number != 1)
+ return $plural;
+ else
+ return $single;
+ }
+}
+
+/**
+ * @see __ngettext() An alias of __ngettext
+ *
+ */
+function _n() {
+ $args = func_get_args();
+ return call_user_func_array('__ngettext', $args);
+}
+
+/**
+ * @see _n() A version of _n(), which supports contexts --
+ * strips everything from the translation after the last bar
+ *
+ */
+function _nc( $single, $plural, $number, $domain = 'default' ) {
+ return before_last_bar( __ngettext( $single, $plural, $number, $domain ) );
+}
+
+/**
+ * Register plural strings in POT file, but don't translate them.
+ *
+ * Used when you want do keep structures with translatable plural strings and
+ * use them later.
+ *
+ * Example:
+ * $messages = array(
+ * 'post' => ngettext_noop('%s post', '%s posts'),
+ * 'page' => ngettext_noop('%s pages', '%s pages')
+ * );
+ * ...
+ * $message = $messages[$type];
+ * $usable_text = sprintf(__ngettext($message[0], $message[1], $count), $count);
+ *
+ * @since 2.5
+ * @param $single Single form to be i18ned
+ * @param $plural Plural form to be i18ned
+ * @param $number Not used, here for compatibility with __ngettext, optional
+ * @param $domain Not used, here for compatibility with __ngettext, optional
+ * @return array array($single, $plural)
+ */
+function __ngettext_noop($single, $plural, $number=1, $domain = 'default') {
+ return array($single, $plural);
+}
+
+/**
+ * @see __ngettext_noop() An alias of __ngettext_noop()
+ *
+ */
+function _n_noop() {
+ $args = func_get_args();
+ return call_user_func_array('__ngettext_noop', $args);
+}
+
+/**
+ * Loads MO file into the list of domains.
+ *
+ * If the domain already exists, the inclusion will fail. If the MO file is not
+ * readable, the inclusion will fail.
+ *
+ * On success, the mofile will be placed in the $l10n global by $domain and will
+ * be an gettext_reader object.
+ *
+ * @since 1.5.0
+ * @uses $l10n Gets list of domain translated string (gettext_reader) objects
+ * @uses CacheFileReader Reads the MO file
+ * @uses gettext_reader Allows for retrieving translated strings
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ * @param string $mofile Path to the .mo file
+ * @return null On failure returns null and also on success returns nothing.
+ */
+function load_textdomain($domain, $mofile) {
+ global $l10n;
+
+ if ( is_readable($mofile))
+ $input = new CachedFileReader($mofile);
+ else
+ return;
+
+ $gettext = new gettext_reader($input);
+
+ if (isset($l10n[$domain])) {
+ $l10n[$domain]->load_tables();
+ $gettext->load_tables();
+ $l10n[$domain]->cache_translations = array_merge($gettext->cache_translations, $l10n[$domain]->cache_translations);
+ } else
+ $l10n[$domain] = $gettext;
+
+ unset($input, $gettext);
+}
+
+/**
+ * Loads default translated strings based on locale.
+ *
+ * Loads the .mo file in WP_LANG_DIR constant path from WordPress root. The
+ * translated (.mo) file is named based off of the locale.
+ *
+ * @since 1.5.0
+ */
+function load_default_textdomain() {
+ $locale = get_locale();
+
+ $mofile = WP_LANG_DIR . "/$locale.mo";
+
+ load_textdomain('default', $mofile);
+}
+
+/**
+ * Loads the plugin's translated strings.
+ *
+ * If the path is not given then it will be the root of the plugin directory.
+ * The .mo file should be named based on the domain with a dash followed by a
+ * dash, and then the locale exactly.
+ *
+ * @since 1.5.0
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ * @param string $abs_rel_path Optional. Relative path to ABSPATH of a folder,
+ * where the .mo file resides. Deprecated, but still functional until 2.7
+ * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR. This is the preferred argument to use. It takes precendence over $abs_rel_path
+ */
+function load_plugin_textdomain($domain, $abs_rel_path = false, $plugin_rel_path = false) {
+ $locale = get_locale();
+
+ if ( false !== $plugin_rel_path )
+ $path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/');
+ else if ( false !== $abs_rel_path)
+ $path = ABSPATH . trim( $abs_rel_path, '/');
+ else
+ $path = WP_PLUGIN_DIR;
+
+ $mofile = $path . '/'. $domain . '-' . $locale . '.mo';
+ load_textdomain($domain, $mofile);
+}
+
+/**
+ * Loads the theme's translated strings.
+ *
+ * If the current locale exists as a .mo file in the theme's root directory, it
+ * will be included in the translated strings by the $domain.
+ *
+ * The .mo files must be named based on the locale exactly.
+ *
+ * @since 1.5.0
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ */
+function load_theme_textdomain($domain, $path = false) {
+ $locale = get_locale();
+
+ $path = ( empty( $path ) ) ? get_template_directory() : $path;
+
+ $mofile = "$path/$locale.mo";
+ load_textdomain($domain, $mofile);
+}
+
+?>
diff -uNr a/blog/wp-includes/link-template.php b/blog/wp-includes/link-template.php
--- a/blog/wp-includes/link-template.php false
+++ b/blog/wp-includes/link-template.php e2c1d3245b7d7175d721dee6ef840116de001639908def35ac1b76ac9667e12e12d839a1873dbcff519720694b7a2e8c056b5d877fdb565edeb1593b555a2302
@@ -0,0 +1,1507 @@
+use_trailing_slashes )
+ $string = trailingslashit($string);
+ else
+ $string = untrailingslashit($string);
+
+ // Note that $type_of_url can be one of following:
+ // single, single_trackback, single_feed, single_paged, feed, category, page, year, month, day, paged
+ $string = apply_filters('user_trailingslashit', $string, $type_of_url);
+ return $string;
+}
+
+/**
+ * Display permalink anchor for current post.
+ *
+ * The permalink mode title will use the post title for the 'a' element 'id'
+ * attribute. The id mode uses 'post-' with the post ID for the 'id' attribute.
+ *
+ * @since 0.71
+ *
+ * @param string $mode Permalink mode can be either 'title', 'id', or default, which is 'id'.
+ */
+function permalink_anchor($mode = 'id') {
+ global $post;
+ switch ( strtolower($mode) ) {
+ case 'title':
+ $title = sanitize_title($post->post_title) . '-' . $post->ID;
+ echo ' ';
+ break;
+ case 'id':
+ default:
+ echo '
';
+ break;
+ }
+}
+
+/**
+ * Retrieve full permalink for current post or post ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $leavename Optional, defaults to false. Whether to keep post name or page name.
+ * @return string
+ */
+function get_permalink($id = 0, $leavename = false) {
+ $rewritecode = array(
+ '%year%',
+ '%monthnum%',
+ '%day%',
+ '%hour%',
+ '%minute%',
+ '%second%',
+ $leavename? '' : '%postname%',
+ '%post_id%',
+ '%category%',
+ '%author%',
+ $leavename? '' : '%pagename%',
+ );
+
+ $post = &get_post($id);
+
+ if ( empty($post->ID) ) return false;
+
+ if ( $post->post_type == 'page' )
+ return get_page_link($post->ID, $leavename);
+ elseif ($post->post_type == 'attachment')
+ return get_attachment_link($post->ID);
+
+ $permalink = get_option('permalink_structure');
+
+ if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending')) ) {
+ $unixtime = strtotime($post->post_date);
+
+ $category = '';
+ if ( strpos($permalink, '%category%') !== false ) {
+ $cats = get_the_category($post->ID);
+ if ( $cats ) {
+ usort($cats, '_usort_terms_by_ID'); // order by ID
+ $category = $cats[0]->slug;
+ if ( $parent = $cats[0]->parent )
+ $category = get_category_parents($parent, false, '/', true) . $category;
+ }
+ // show default category in permalinks, without
+ // having to assign it explicitly
+ if ( empty($category) ) {
+ $default_category = get_category( get_option( 'default_category' ) );
+ $category = is_wp_error( $default_category ) ? '' : $default_category->slug;
+ }
+ }
+
+ $author = '';
+ if ( strpos($permalink, '%author%') !== false ) {
+ $authordata = get_userdata($post->post_author);
+ $author = $authordata->user_nicename;
+ }
+
+ $date = explode(" ",date('Y m d H i s', $unixtime));
+ $rewritereplace =
+ array(
+ $date[0],
+ $date[1],
+ $date[2],
+ $date[3],
+ $date[4],
+ $date[5],
+ $post->post_name,
+ $post->ID,
+ $category,
+ $author,
+ $post->post_name,
+ );
+ $permalink = get_option('home') . str_replace($rewritecode, $rewritereplace, $permalink);
+ $permalink = user_trailingslashit($permalink, 'single');
+ return apply_filters('post_link', $permalink, $post, $leavename);
+ } else { // if they're not using the fancy permalink option
+ $permalink = get_option('home') . '/?p=' . $post->ID;
+ return apply_filters('post_link', $permalink, $post, $leavename);
+ }
+}
+
+/**
+ * Retrieve permalink from post ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @param mixed $deprecated Not used.
+ * @return string
+ */
+function post_permalink($post_id = 0, $deprecated = '') {
+ return get_permalink($post_id);
+}
+
+/**
+ * Retrieve the permalink for current page or page ID.
+ *
+ * Respects page_on_front. Use this one.
+ *
+ * @since 1.5.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $leavename Optional, defaults to false. Whether to keep post name or page name.
+ * @return string
+ */
+function get_page_link($id = false, $leavename = false) {
+ global $post;
+
+ $id = (int) $id;
+ if ( !$id )
+ $id = (int) $post->ID;
+
+ if ( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') )
+ $link = get_option('home');
+ else
+ $link = _get_page_link( $id , $leavename );
+
+ return apply_filters('page_link', $link, $id);
+}
+
+/**
+ * Retrieve the page permalink.
+ *
+ * Ignores page_on_front. Internal use only.
+ *
+ * @since 2.1.0
+ * @access private
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $leavename Optional. Leave name.
+ * @return string
+ */
+function _get_page_link( $id = false, $leavename = false ) {
+ global $post, $wp_rewrite;
+
+ if ( !$id )
+ $id = (int) $post->ID;
+ else
+ $post = &get_post($id);
+
+ $pagestruct = $wp_rewrite->get_page_permastruct();
+
+ if ( '' != $pagestruct && isset($post->post_status) && 'draft' != $post->post_status ) {
+ $link = get_page_uri($id);
+ $link = ( $leavename ) ? $pagestruct : str_replace('%pagename%', $link, $pagestruct);
+ $link = get_option('home') . "/$link";
+ $link = user_trailingslashit($link, 'page');
+ } else {
+ $link = get_option('home') . "/?page_id=$id";
+ }
+
+ return apply_filters( '_get_page_link', $link, $id );
+}
+
+/**
+ * Retrieve permalink for attachment.
+ *
+ * This can be used in the WordPress Loop or outside of it.
+ *
+ * @since 2.0.0
+ *
+ * @param int $id Optional. Post ID.
+ * @return string
+ */
+function get_attachment_link($id = false) {
+ global $post, $wp_rewrite;
+
+ $link = false;
+
+ if (! $id) {
+ $id = (int) $post->ID;
+ }
+
+ $object = get_post($id);
+ if ( $wp_rewrite->using_permalinks() && ($object->post_parent > 0) && ($object->post_parent != $id) ) {
+ $parent = get_post($object->post_parent);
+ if ( 'page' == $parent->post_type )
+ $parentlink = _get_page_link( $object->post_parent ); // Ignores page_on_front
+ else
+ $parentlink = get_permalink( $object->post_parent );
+ if ( is_numeric($object->post_name) || false !== strpos(get_option('permalink_structure'), '%category%') )
+ $name = 'attachment/' . $object->post_name; //
// is paged so we use the explicit attachment marker
+ else
+ $name = $object->post_name;
+ if (strpos($parentlink, '?') === false)
+ $link = user_trailingslashit( trailingslashit($parentlink) . $name );
+ }
+
+ if (! $link ) {
+ $link = get_bloginfo('url') . "/?attachment_id=$id";
+ }
+
+ return apply_filters('attachment_link', $link, $id);
+}
+
+/**
+ * Retrieve the permalink for the year archives.
+ *
+ * @since 1.5.0
+ *
+ * @param int|bool $year False for current year or year for permalink.
+ * @return string
+ */
+function get_year_link($year) {
+ global $wp_rewrite;
+ if ( !$year )
+ $year = gmdate('Y', time()+(get_option('gmt_offset') * 3600));
+ $yearlink = $wp_rewrite->get_year_permastruct();
+ if ( !empty($yearlink) ) {
+ $yearlink = str_replace('%year%', $year, $yearlink);
+ return apply_filters('year_link', get_option('home') . user_trailingslashit($yearlink, 'year'), $year);
+ } else {
+ return apply_filters('year_link', get_option('home') . '/?m=' . $year, $year);
+ }
+}
+
+/**
+ * Retrieve the permalink for the month archives with year.
+ *
+ * @since 1.0.0
+ *
+ * @param bool|int $year False for current year. Integer of year.
+ * @param bool|int $month False for current month. Integer of month.
+ * @return string
+ */
+function get_month_link($year, $month) {
+ global $wp_rewrite;
+ if ( !$year )
+ $year = gmdate('Y', time()+(get_option('gmt_offset') * 3600));
+ if ( !$month )
+ $month = gmdate('m', time()+(get_option('gmt_offset') * 3600));
+ $monthlink = $wp_rewrite->get_month_permastruct();
+ if ( !empty($monthlink) ) {
+ $monthlink = str_replace('%year%', $year, $monthlink);
+ $monthlink = str_replace('%monthnum%', zeroise(intval($month), 2), $monthlink);
+ return apply_filters('month_link', get_option('home') . user_trailingslashit($monthlink, 'month'), $year, $month);
+ } else {
+ return apply_filters('month_link', get_option('home') . '/?m=' . $year . zeroise($month, 2), $year, $month);
+ }
+}
+
+/**
+ * Retrieve the permalink for the day archives with year and month.
+ *
+ * @since 1.0.0
+ *
+ * @param bool|int $year False for current year. Integer of year.
+ * @param bool|int $month False for current month. Integer of month.
+ * @param bool|int $day False for current day. Integer of day.
+ * @return string
+ */
+function get_day_link($year, $month, $day) {
+ global $wp_rewrite;
+ if ( !$year )
+ $year = gmdate('Y', time()+(get_option('gmt_offset') * 3600));
+ if ( !$month )
+ $month = gmdate('m', time()+(get_option('gmt_offset') * 3600));
+ if ( !$day )
+ $day = gmdate('j', time()+(get_option('gmt_offset') * 3600));
+
+ $daylink = $wp_rewrite->get_day_permastruct();
+ if ( !empty($daylink) ) {
+ $daylink = str_replace('%year%', $year, $daylink);
+ $daylink = str_replace('%monthnum%', zeroise(intval($month), 2), $daylink);
+ $daylink = str_replace('%day%', zeroise(intval($day), 2), $daylink);
+ return apply_filters('day_link', get_option('home') . user_trailingslashit($daylink, 'day'), $year, $month, $day);
+ } else {
+ return apply_filters('day_link', get_option('home') . '/?m=' . $year . zeroise($month, 2) . zeroise($day, 2), $year, $month, $day);
+ }
+}
+
+/**
+ * Retrieve the permalink for the feed type.
+ *
+ * @since 1.5.0
+ *
+ * @param string $feed Optional, defaults to default feed. Feed type.
+ * @return string
+ */
+function get_feed_link($feed = '') {
+ global $wp_rewrite;
+
+ $permalink = $wp_rewrite->get_feed_permastruct();
+ if ( '' != $permalink ) {
+ if ( false !== strpos($feed, 'comments_') ) {
+ $feed = str_replace('comments_', '', $feed);
+ $permalink = $wp_rewrite->get_comment_feed_permastruct();
+ }
+
+ if ( get_default_feed() == $feed )
+ $feed = '';
+
+ $permalink = str_replace('%feed%', $feed, $permalink);
+ $permalink = preg_replace('#/+#', '/', "/$permalink");
+ $output = get_option('home') . user_trailingslashit($permalink, 'feed');
+ } else {
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ if ( false !== strpos($feed, 'comments_') )
+ $feed = str_replace('comments_', 'comments-', $feed);
+
+ $output = get_option('home') . "/?feed={$feed}";
+ }
+
+ return apply_filters('feed_link', $output, $feed);
+}
+
+/**
+ * Retrieve the permalink for the post comments feed.
+ *
+ * @since 2.2.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_post_comments_feed_link($post_id = '', $feed = '') {
+ global $id;
+
+ if ( empty($post_id) )
+ $post_id = (int) $id;
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ if ( '' != get_option('permalink_structure') ) {
+ $url = trailingslashit( get_permalink($post_id) ) . 'feed';
+ if ( $feed != get_default_feed() )
+ $url .= "/$feed";
+ $url = user_trailingslashit($url, 'single_feed');
+ } else {
+ $type = get_post_field('post_type', $post_id);
+ if ( 'page' == $type )
+ $url = get_option('home') . "/?feed=$feed&page_id=$post_id";
+ else
+ $url = get_option('home') . "/?feed=$feed&p=$post_id";
+ }
+
+ return apply_filters('post_comments_feed_link', $url);
+}
+
+/**
+ * Display the comment feed link for a post.
+ *
+ * Prints out the comment feed link for a post. Link text is placed in the
+ * anchor. If no link text is specified, default text is used. If no post ID is
+ * specified, the current post is used.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param string $link_text Descriptive text.
+ * @param int $post_id Optional post ID. Default to current post.
+ * @param string $feed Optional. Feed format.
+ * @return string Link to the comment feed for the current post.
+*/
+function post_comments_feed_link( $link_text = '', $post_id = '', $feed = '' ) {
+ $url = get_post_comments_feed_link($post_id, $feed);
+ if ( empty($link_text) )
+ $link_text = __('Comments Feed');
+
+ echo "$link_text ";
+}
+
+/**
+ * Retrieve the feed link for a given author.
+ *
+ * Returns a link to the feed for all posts by a given author. A specific feed
+ * can be requested or left blank to get the default feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param int $author_id ID of an author.
+ * @param string $feed Optional. Feed type.
+ * @return string Link to the feed for the author specified by $author_id.
+*/
+function get_author_feed_link( $author_id, $feed = '' ) {
+ $author_id = (int) $author_id;
+ $permalink_structure = get_option('permalink_structure');
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ if ( '' == $permalink_structure ) {
+ $link = get_option('home') . "?feed=$feed&author=" . $author_id;
+ } else {
+ $link = get_author_posts_url($author_id);
+ if ( $feed == get_default_feed() )
+ $feed_link = 'feed';
+ else
+ $feed_link = "feed/$feed";
+
+ $link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
+ }
+
+ $link = apply_filters('author_feed_link', $link, $feed);
+
+ return $link;
+}
+
+/**
+ * Retrieve the feed link for a category.
+ *
+ * Returns a link to the feed for all post in a given category. A specific feed
+ * can be requested or left blank to get the default feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param int $cat_id ID of a category.
+ * @param string $feed Optional. Feed type.
+ * @return string Link to the feed for the category specified by $cat_id.
+*/
+function get_category_feed_link($cat_id, $feed = '') {
+ $cat_id = (int) $cat_id;
+
+ $category = get_category($cat_id);
+
+ if ( empty($category) || is_wp_error($category) )
+ return false;
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ $permalink_structure = get_option('permalink_structure');
+
+ if ( '' == $permalink_structure ) {
+ $link = get_option('home') . "?feed=$feed&cat=" . $cat_id;
+ } else {
+ $link = get_category_link($cat_id);
+ if( $feed == get_default_feed() )
+ $feed_link = 'feed';
+ else
+ $feed_link = "feed/$feed";
+
+ $link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
+ }
+
+ $link = apply_filters('category_feed_link', $link, $feed);
+
+ return $link;
+}
+
+/**
+ * Retrieve permalink for feed of tag.
+ *
+ * @since 2.3.0
+ *
+ * @param int $tag_id Tag ID.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_tag_feed_link($tag_id, $feed = '') {
+ $tag_id = (int) $tag_id;
+
+ $tag = get_tag($tag_id);
+
+ if ( empty($tag) || is_wp_error($tag) )
+ return false;
+
+ $permalink_structure = get_option('permalink_structure');
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ if ( '' == $permalink_structure ) {
+ $link = get_option('home') . "?feed=$feed&tag=" . $tag->slug;
+ } else {
+ $link = get_tag_link($tag->term_id);
+ if ( $feed == get_default_feed() )
+ $feed_link = 'feed';
+ else
+ $feed_link = "feed/$feed";
+ $link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
+ }
+
+ $link = apply_filters('tag_feed_link', $link, $feed);
+
+ return $link;
+}
+
+/**
+ * Retrieve edit tag link.
+ *
+ * @since 2.7.0
+ *
+ * @param int $tag_id Tag ID
+ * @return string
+ */
+function get_edit_tag_link( $tag_id = 0 ) {
+ $tag = get_term($tag_id, 'post_tag');
+
+ if ( !current_user_can('manage_categories') )
+ return;
+
+ $location = admin_url('edit-tags.php?action=edit&tag_ID=') . $tag->term_id;
+ return apply_filters( 'get_edit_tag_link', $location );
+}
+
+/**
+ * Display or retrieve edit tag link with formatting.
+ *
+ * @since 2.7.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @param int|object $tag Tag object or ID
+ * @return string|null HTML content, if $echo is set to false.
+ */
+function edit_tag_link( $link = '', $before = '', $after = '', $tag = null ) {
+ $tag = get_term($tag, 'post_tag');
+
+ if ( !current_user_can('manage_categories') )
+ return;
+
+ if ( empty($link) )
+ $link = __('Edit This');
+
+ $link = '' . $link . ' ';
+ echo $before . apply_filters( 'edit_tag_link', $link, $tag->term_id ) . $after;
+}
+
+/**
+ * Retrieve the permalink for the feed of the search results.
+ *
+ * @since 2.5.0
+ *
+ * @param string $search_query Optional. Search query.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_search_feed_link($search_query = '', $feed = '') {
+ if ( empty($search_query) )
+ $search = attribute_escape(get_search_query());
+ else
+ $search = attribute_escape(stripslashes($search_query));
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ $link = get_option('home') . "?s=$search&feed=$feed";
+
+ $link = apply_filters('search_feed_link', $link);
+
+ return $link;
+}
+
+/**
+ * Retrieve the permalink for the comments feed of the search results.
+ *
+ * @since 2.5.0
+ *
+ * @param string $search_query Optional. Search query.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_search_comments_feed_link($search_query = '', $feed = '') {
+ if ( empty($search_query) )
+ $search = attribute_escape(get_search_query());
+ else
+ $search = attribute_escape(stripslashes($search_query));
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ $link = get_option('home') . "?s=$search&feed=comments-$feed";
+
+ $link = apply_filters('search_feed_link', $link);
+
+ return $link;
+}
+
+/**
+ * Retrieve edit posts link for post.
+ *
+ * Can be used within the WordPress loop or outside of it. Can be used with
+ * pages, posts, attachments, and revisions.
+ *
+ * @since 2.3.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param string $context Optional, default to display. How to write the '&', defaults to '&'.
+ * @return string
+ */
+function get_edit_post_link( $id = 0, $context = 'display' ) {
+ if ( !$post = &get_post( $id ) )
+ return;
+
+ if ( 'display' == $context )
+ $action = 'action=edit&';
+ else
+ $action = 'action=edit&';
+
+ switch ( $post->post_type ) :
+ case 'page' :
+ if ( !current_user_can( 'edit_page', $post->ID ) )
+ return;
+ $file = 'page';
+ $var = 'post';
+ break;
+ case 'attachment' :
+ if ( !current_user_can( 'edit_post', $post->ID ) )
+ return;
+ $file = 'media';
+ $var = 'attachment_id';
+ break;
+ case 'revision' :
+ if ( !current_user_can( 'edit_post', $post->ID ) )
+ return;
+ $file = 'revision';
+ $var = 'revision';
+ $action = '';
+ break;
+ default :
+ if ( !current_user_can( 'edit_post', $post->ID ) )
+ return;
+ $file = 'post';
+ $var = 'post';
+ break;
+ endswitch;
+
+ return apply_filters( 'get_edit_post_link', admin_url("$file.php?{$action}$var=$post->ID"), $post->ID, $context );
+}
+
+/**
+ * Retrieve edit posts link for post.
+ *
+ * @since 1.0.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ */
+function edit_post_link( $link = 'Edit This', $before = '', $after = '' ) {
+ global $post;
+
+ if ( $post->post_type == 'page' ) {
+ if ( !current_user_can( 'edit_page', $post->ID ) )
+ return;
+ } else {
+ if ( !current_user_can( 'edit_post', $post->ID ) )
+ return;
+ }
+
+ $link = '' . $link . ' ';
+ echo $before . apply_filters( 'edit_post_link', $link, $post->ID ) . $after;
+}
+
+/**
+ * Retrieve edit comment link.
+ *
+ * @since 2.3.0
+ *
+ * @param int $comment_id Optional. Comment ID.
+ * @return string
+ */
+function get_edit_comment_link( $comment_id = 0 ) {
+ $comment = &get_comment( $comment_id );
+ $post = &get_post( $comment->comment_post_ID );
+
+ if ( $post->post_type == 'page' ) {
+ if ( !current_user_can( 'edit_page', $post->ID ) )
+ return;
+ } else {
+ if ( !current_user_can( 'edit_post', $post->ID ) )
+ return;
+ }
+
+ $location = admin_url('comment.php?action=editcomment&c=') . $comment->comment_ID;
+ return apply_filters( 'get_edit_comment_link', $location );
+}
+
+/**
+ * Display or retrieve edit comment link with formatting.
+ *
+ * @since 1.0.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @return string|null HTML content, if $echo is set to false.
+ */
+function edit_comment_link( $link = 'Edit This', $before = '', $after = '' ) {
+ global $comment, $post;
+
+ if ( $post->post_type == 'attachment' ) {
+ } elseif ( $post->post_type == 'page' ) {
+ if ( !current_user_can( 'edit_page', $post->ID ) )
+ return;
+ } else {
+ if ( !current_user_can( 'edit_post', $post->ID ) )
+ return;
+ }
+
+ $link = '' . $link . ' ';
+ echo $before . apply_filters( 'edit_comment_link', $link, $comment->comment_ID ) . $after;
+}
+
+/**
+ * Display edit bookmark (literally a URL external to blog) link.
+ *
+ * @since 2.7.0
+ *
+ * @param int $link Optional. Bookmark ID.
+ * @return string
+ */
+function get_edit_bookmark_link( $link = 0 ) {
+ $link = get_bookmark( $link );
+
+ if ( !current_user_can('manage_links') )
+ return;
+
+ $location = admin_url('link.php?action=edit&link_id=') . $link->link_id;
+ return apply_filters( 'get_edit_bookmark_link', $location, $link->link_id );
+}
+
+/**
+ * Display edit bookmark (literally a URL external to blog) link anchor content.
+ *
+ * @since 2.7.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @param int $bookmark Optional. Bookmark ID.
+ */
+function edit_bookmark_link( $link = '', $before = '', $after = '', $bookmark = null ) {
+ $bookmark = get_bookmark($bookmark);
+
+ if ( !current_user_can('manage_links') )
+ return;
+
+ if ( empty($link) )
+ $link = __('Edit This');
+
+ $link = '' . $link . ' ';
+ echo $before . apply_filters( 'edit_bookmark_link', $link, $bookmark->link_id ) . $after;
+}
+
+// Navigation links
+
+/**
+ * Retrieve previous post link that is adjacent to current post.
+ *
+ * @since 1.5.0
+ *
+ * @param bool $in_same_cat Optional. Whether link should be in same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ * @return string
+ */
+function get_previous_post($in_same_cat = false, $excluded_categories = '') {
+ return get_adjacent_post($in_same_cat, $excluded_categories);
+}
+
+/**
+ * Retrieve next post link that is adjacent to current post.
+ *
+ * @since 1.5.0
+ *
+ * @param bool $in_same_cat Optional. Whether link should be in same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ * @return string
+ */
+function get_next_post($in_same_cat = false, $excluded_categories = '') {
+ return get_adjacent_post($in_same_cat, $excluded_categories, false);
+}
+
+/**
+ * Retrieve adjacent post link.
+ *
+ * Can either be next or previous post link.
+ *
+ * @since 2.5.0
+ *
+ * @param bool $in_same_cat Optional. Whether link should be in same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ * @param bool $previous Optional. Whether to retrieve previous post.
+ * @return string
+ */
+function get_adjacent_post($in_same_cat = false, $excluded_categories = '', $previous = true) {
+ global $post, $wpdb;
+
+ if( empty($post) || !is_single() || is_attachment() )
+ return null;
+
+ $current_post_date = $post->post_date;
+
+ $join = '';
+ $posts_in_ex_cats_sql = '';
+ if ( $in_same_cat || !empty($excluded_categories) ) {
+ $join = " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
+
+ if ( $in_same_cat ) {
+ $cat_array = wp_get_object_terms($post->ID, 'category', 'fields=ids');
+ $join .= " AND tt.taxonomy = 'category' AND tt.term_id IN (" . implode(',', $cat_array) . ")";
+ }
+
+ $posts_in_ex_cats_sql = "AND tt.taxonomy = 'category'";
+ if ( !empty($excluded_categories) ) {
+ $excluded_categories = array_map('intval', explode(' and ', $excluded_categories));
+ if ( !empty($cat_array) ) {
+ $excluded_categories = array_diff($excluded_categories, $cat_array);
+ $posts_in_ex_cats_sql = '';
+ }
+
+ if ( !empty($excluded_categories) ) {
+ $posts_in_ex_cats_sql = " AND tt.taxonomy = 'category' AND tt.term_id NOT IN (" . implode($excluded_categories, ',') . ')';
+ }
+ }
+ }
+
+ $adjacent = $previous ? 'previous' : 'next';
+ $op = $previous ? '<' : '>';
+ $order = $previous ? 'DESC' : 'ASC';
+
+ $join = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_cat, $excluded_categories );
+ $where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare("WHERE p.post_date $op %s AND p.post_type = 'post' AND p.post_status = 'publish' $posts_in_ex_cats_sql", $current_post_date), $in_same_cat, $excluded_categories );
+ $sort = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );
+
+ return $wpdb->get_row("SELECT p.* FROM $wpdb->posts AS p $join $where $sort");
+}
+
+/**
+ * Display previous post link that is adjacent to the current post.
+ *
+ * @since 1.5.0
+ *
+ * @param string $format Optional. Link anchor format.
+ * @param string $link Optional. Link permalink format.
+ * @param bool $in_same_cat Optional. Whether link should be in same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ */
+function previous_post_link($format='« %link', $link='%title', $in_same_cat = false, $excluded_categories = '') {
+ adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, true);
+}
+
+/**
+ * Display next post link that is adjacent to the current post.
+ *
+ * @since 1.5.0
+ *
+ * @param string $format Optional. Link anchor format.
+ * @param string $link Optional. Link permalink format.
+ * @param bool $in_same_cat Optional. Whether link should be in same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ */
+function next_post_link($format='%link »', $link='%title', $in_same_cat = false, $excluded_categories = '') {
+ adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, false);
+}
+
+/**
+ * Display adjacent post link.
+ *
+ * Can be either next post link or previous.
+ *
+ * @since 2.5.0
+ *
+ * @param string $format Link anchor format.
+ * @param string $link Link permalink format.
+ * @param bool $in_same_cat Optional. Whether link should be in same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ * @param bool $previous Optional, default is true. Whether display link to previous post.
+ */
+function adjacent_post_link($format, $link, $in_same_cat = false, $excluded_categories = '', $previous = true) {
+ if ( $previous && is_attachment() )
+ $post = & get_post($GLOBALS['post']->post_parent);
+ else
+ $post = get_adjacent_post($in_same_cat, $excluded_categories, $previous);
+
+ if ( !$post )
+ return;
+
+ $title = $post->post_title;
+
+ if ( empty($post->post_title) )
+ $title = $previous ? __('Previous Post') : __('Next Post');
+
+ $title = apply_filters('the_title', $title, $post);
+ $date = mysql2date(get_option('date_format'), $post->post_date);
+
+ $string = '';
+ $link = str_replace('%title', $title, $link);
+ $link = str_replace('%date', $date, $link);
+ $link = $string . $link . ' ';
+
+ $format = str_replace('%link', $link, $format);
+
+ $adjacent = $previous ? 'previous' : 'next';
+ echo apply_filters( "{$adjacent}_post_link", $format, $link );
+}
+
+/**
+ * Retrieve get links for page numbers.
+ *
+ * @since 1.5.0
+ *
+ * @param int $pagenum Optional. Page ID.
+ * @return string
+ */
+function get_pagenum_link($pagenum = 1) {
+ global $wp_rewrite;
+
+ $pagenum = (int) $pagenum;
+
+ $request = remove_query_arg( 'paged' );
+
+ $home_root = parse_url(get_option('home'));
+ $home_root = ( isset($home_root['path']) ) ? $home_root['path'] : '';
+ $home_root = preg_quote( trailingslashit( $home_root ), '|' );
+
+ $request = preg_replace('|^'. $home_root . '|', '', $request);
+ $request = preg_replace('|^/+|', '', $request);
+
+ if ( !$wp_rewrite->using_permalinks() || is_admin() ) {
+ $base = trailingslashit( get_bloginfo( 'home' ) );
+
+ if ( $pagenum > 1 ) {
+ $result = add_query_arg( 'paged', $pagenum, $base . $request );
+ } else {
+ $result = $base . $request;
+ }
+ } else {
+ $qs_regex = '|\?.*?$|';
+ preg_match( $qs_regex, $request, $qs_match );
+
+ if ( !empty( $qs_match[0] ) ) {
+ $query_string = $qs_match[0];
+ $request = preg_replace( $qs_regex, '', $request );
+ } else {
+ $query_string = '';
+ }
+
+ $request = preg_replace( '|page/\d+/?$|', '', $request);
+ $request = preg_replace( '|^index\.php|', '', $request);
+ $request = ltrim($request, '/');
+
+ $base = trailingslashit( get_bloginfo( 'url' ) );
+
+ if ( $wp_rewrite->using_index_permalinks() && ( $pagenum > 1 || '' != $request ) )
+ $base .= 'index.php/';
+
+ if ( $pagenum > 1 ) {
+ $request = ( ( !empty( $request ) ) ? trailingslashit( $request ) : $request ) . user_trailingslashit( 'page/' . $pagenum, 'paged' );
+ }
+
+ $result = $base . $request . $query_string;
+ }
+
+ $result = apply_filters('get_pagenum_link', $result);
+
+ return $result;
+}
+
+/**
+ * Retrieve next posts pages link.
+ *
+ * Backported from 2.1.3 to 2.0.10.
+ *
+ * @since 2.0.10
+ *
+ * @param int $max_page Optional. Max pages.
+ * @return string
+ */
+function get_next_posts_page_link($max_page = 0) {
+ global $paged;
+
+ if ( !is_single() ) {
+ if ( !$paged )
+ $paged = 1;
+ $nextpage = intval($paged) + 1;
+ if ( !$max_page || $max_page >= $nextpage )
+ return get_pagenum_link($nextpage);
+ }
+}
+
+/**
+ * Display or return the next posts pages link.
+ *
+ * @since 0.71
+ *
+ * @param int $max_page Optional. Max pages.
+ * @param boolean $echo Optional. Echo or return;
+ */
+function next_posts( $max_page = 0, $echo = true ) {
+ $output = clean_url( get_next_posts_page_link( $max_page ) );
+
+ if ( $echo )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Return the next posts pages link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Content for link text.
+ * @param int $max_page Optional. Max pages.
+ * @return string|null
+ */
+function get_next_posts_link( $label = 'Next Page »', $max_page = 0 ) {
+ global $paged, $wp_query;
+
+ if ( !$max_page ) {
+ $max_page = $wp_query->max_num_pages;
+ }
+
+ if ( !$paged )
+ $paged = 1;
+
+ $nextpage = intval($paged) + 1;
+
+ if ( !is_single() && ( empty($paged) || $nextpage <= $max_page) ) {
+ $attr = apply_filters( 'next_posts_link_attributes', '' );
+ return '". preg_replace('/&([^#])(?![a-z]{1,8};)/', '&$1', $label) .' ';
+ }
+}
+
+/**
+ * Display the next posts pages link.
+ *
+ * @since 0.71
+ * @uses get_next_posts_link()
+ *
+ * @param string $label Content for link text.
+ * @param int $max_page Optional. Max pages.
+ */
+function next_posts_link( $label = 'Next Page »', $max_page = 0 ) {
+ echo get_next_posts_link( $label, $max_page );
+}
+
+/**
+ * Retrieve previous post pages link.
+ *
+ * Will only return string, if not on a single page or post.
+ *
+ * Backported to 2.0.10 from 2.1.3.
+ *
+ * @since 2.0.10
+ *
+ * @return string|null
+ */
+function get_previous_posts_page_link() {
+ global $paged;
+
+ if ( !is_single() ) {
+ $nextpage = intval($paged) - 1;
+ if ( $nextpage < 1 )
+ $nextpage = 1;
+ return get_pagenum_link($nextpage);
+ }
+}
+
+/**
+ * Display or return the previous posts pages link.
+ *
+ * @since 0.71
+ *
+ * @param boolean $echo Optional. Echo or return;
+ */
+function previous_posts( $echo = true ) {
+ $output = clean_url( get_previous_posts_page_link() );
+
+ if ( $echo )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Return the previous posts pages link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Optional. Previous page link text.
+ * @return string|null
+ */
+function get_previous_posts_link( $label = '« Previous Page' ) {
+ global $paged;
+
+ if ( !is_single() && $paged > 1 ) {
+ $attr = apply_filters( 'previous_posts_link_attributes', '' );
+ return '". preg_replace( '/&([^#])(?![a-z]{1,8};)/', '&$1', $label ) .' ';
+ }
+}
+
+/**
+ * Display the previous posts page link.
+ *
+ * @since 0.71
+ * @uses get_previous_posts_link()
+ *
+ * @param string $label Optional. Previous page link text.
+ */
+function previous_posts_link( $label = '« Previous Page' ) {
+ echo get_previous_posts_link( $label );
+}
+
+/**
+ * Display post pages link navigation for previous and next pages.
+ *
+ * @since 0.71
+ *
+ * @param string $sep Optional. Separator for posts navigation links.
+ * @param string $prelabel Optional. Label for previous pages.
+ * @param string $nxtlabel Optional Label for next pages.
+ */
+function posts_nav_link( $sep = ' — ', $prelabel = '« Previous Page', $nxtlabel = 'Next Page »' ) {
+ global $wp_query;
+ if ( !is_singular() ) {
+ $max_num_pages = $wp_query->max_num_pages;
+ $paged = get_query_var('paged');
+
+ //only have sep if there's both prev and next results
+ if ($paged < 2 || $paged >= $max_num_pages) {
+ $sep = '';
+ }
+
+ if ( $max_num_pages > 1 ) {
+ previous_posts_link($prelabel);
+ echo preg_replace('/&([^#])(?![a-z]{1,8};)/', '&$1', $sep);
+ next_posts_link($nxtlabel);
+ }
+ }
+}
+
+/**
+ * Retrieve page numbers links.
+ *
+ * @since 2.7.0
+ *
+ * @param int $pagenum Optional. Page number.
+ * @return string
+ */
+function get_comments_pagenum_link( $pagenum = 1, $max_page = 0 ) {
+ global $post, $wp_rewrite;
+
+ $pagenum = (int) $pagenum;
+
+ $result = get_permalink( $post->ID );
+
+ if ( 'newest' == get_option('default_comments_page') ) {
+ if ( $pagenum != $max_page ) {
+ if ( $wp_rewrite->using_permalinks() )
+ $result = user_trailingslashit( trailingslashit($result) . 'comment-page-' . $pagenum, 'commentpaged');
+ else
+ $result = add_query_arg( 'cpage', $pagenum, $result );
+ }
+ } elseif ( $pagenum > 1 ) {
+ if ( $wp_rewrite->using_permalinks() )
+ $result = user_trailingslashit( trailingslashit($result) . 'comment-page-' . $pagenum, 'commentpaged');
+ else
+ $result = add_query_arg( 'cpage', $pagenum, $result );
+ }
+
+ $result .= '#comments';
+
+ $result = apply_filters('get_comments_pagenum_link', $result);
+
+ return $result;
+}
+
+/**
+ * Display link to next comments pages.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Optional. Label for link text.
+ * @param int $max_page Optional. Max page.
+ */
+function next_comments_link($label='', $max_page = 0) {
+ global $wp_query;
+
+ if ( !is_singular() )
+ return;
+
+ $page = get_query_var('cpage');
+
+ if ( !$page )
+ $page = 1;
+
+ $nextpage = intval($page) + 1;
+
+ if ( empty($max_page) )
+ $max_page = $wp_query->max_num_comment_pages;
+
+ if ( empty($max_page) )
+ $max_page = get_comment_pages_count();
+
+ if ( $nextpage > $max_page )
+ return;
+
+ if ( empty($label) )
+ $label = __('Newer Comments »');
+
+ echo '". preg_replace('/&([^#])(?![a-z]{1,8};)/', '&$1', $label) .' ';
+}
+
+/**
+ * Display the previous comments page link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Optional. Label for comments link text.
+ */
+function previous_comments_link($label='') {
+
+ if ( !is_singular() )
+ return;
+
+ $page = get_query_var('cpage');
+
+ if ( !$page )
+ $page = 1;
+
+ if ( $page <= 1 )
+ return;
+
+ $prevpage = intval($page) - 1;
+
+ if ( empty($label) )
+ $label = __('« Older Comments');
+
+ echo '". preg_replace('/&([^#])(?![a-z]{1,8};)/', '&$1', $label) .' ';
+}
+
+/**
+ * Create pagination links for the comments on the current post.
+ *
+ * @see paginate_links()
+ * @since 2.7.0
+ *
+ * @param string|array $args Optional args. See paginate_links.
+ * @return string Markup for pagination links.
+*/
+function paginate_comments_links($args = array()) {
+ global $wp_query, $wp_rewrite;
+
+ if ( !is_singular() )
+ return;
+
+ $page = get_query_var('cpage');
+ if ( !$page )
+ $page = 1;
+ $max_page = get_comment_pages_count();
+ $defaults = array(
+ 'base' => add_query_arg( 'cpage', '%#%' ),
+ 'format' => '',
+ 'total' => $max_page,
+ 'current' => $page,
+ 'echo' => true,
+ 'add_fragment' => '#comments'
+ );
+ if ( $wp_rewrite->using_permalinks() )
+ $defaults['base'] = user_trailingslashit(get_permalink() . 'comment-page-%#%', 'commentpaged');
+
+ $args = wp_parse_args( $args, $defaults );
+ $page_links = paginate_links( $args );
+
+ if ( $args['echo'] )
+ echo $page_links;
+ else
+ return $page_links;
+}
+
+/**
+ * Retrieve shortcut link.
+ *
+ * Use this in 'a' element 'href' attribute.
+ *
+ * @since 2.6.0
+ *
+ * @return string
+ */
+function get_shortcut_link() {
+ $link = "javascript:
+ var d=document,
+ w=window,
+ e=w.getSelection,
+ k=d.getSelection,
+ x=d.selection,
+ s=(e?e():(k)?k():(x?x.createRange().text:0)),
+ f='" . admin_url('press-this.php') . "',
+ l=d.location,
+ e=encodeURIComponent,
+ g=f+'?u='+e(l.href)+'&t='+e(d.title)+'&s='+e(s)+'&v=2';
+ function a(){
+ if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=720,height=570')){
+ l.href=g;
+ }
+ }";
+ if (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false)
+ $link .= 'setTimeout(a,0);';
+ else
+ $link .= 'a();';
+
+ $link .= "void(0);";
+
+ $link = str_replace(array("\r", "\n", "\t"), '', $link);
+
+ return apply_filters('shortcut_link', $link);
+}
+
+/**
+ * Retrieve the site url.
+ *
+ * Returns the 'site_url' option with the appropriate protocol, 'https' if
+ * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
+ * overridden.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional. Path relative to the site url.
+ * @param string $scheme Optional. Scheme to give the site url context. Currently 'http','https', 'login', 'login_post', or 'admin'.
+ * @return string Site url link with optional path appended.
+*/
+function site_url($path = '', $scheme = null) {
+ // should the list of allowed schemes be maintained elsewhere?
+ $orig_scheme = $scheme;
+ if ( !in_array($scheme, array('http', 'https')) ) {
+ if ( ('login_post' == $scheme) && ( force_ssl_login() || force_ssl_admin() ) )
+ $scheme = 'https';
+ elseif ( ('login' == $scheme) && ( force_ssl_admin() ) )
+ $scheme = 'https';
+ elseif ( ('admin' == $scheme) && force_ssl_admin() )
+ $scheme = 'https';
+ else
+ $scheme = ( is_ssl() ? 'https' : 'http' );
+ }
+
+ $url = str_replace( 'http://', "{$scheme}://", get_option('siteurl') );
+
+ if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
+ $url .= '/' . ltrim($path, '/');
+
+ return apply_filters('site_url', $url, $path, $orig_scheme);
+}
+
+/**
+ * Retrieve the url to the admin area.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional path relative to the admin url
+ * @return string Admin url link with optional path appended
+*/
+function admin_url($path = '') {
+ $url = site_url('wp-admin/', 'admin');
+
+ if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
+ $url .= ltrim($path, '/');
+
+ return $url;
+}
+
+/**
+ * Retrieve the url to the includes directory.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional. Path relative to the includes url.
+ * @return string Includes url link with optional path appended.
+*/
+function includes_url($path = '') {
+ $url = site_url() . '/' . WPINC . '/';
+
+ if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
+ $url .= ltrim($path, '/');
+
+ return $url;
+}
+
+/**
+ * Retrieve the url to the content directory.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional. Path relative to the content url.
+ * @return string Content url link with optional path appended.
+*/
+function content_url($path = '') {
+ $scheme = ( is_ssl() ? 'https' : 'http' );
+ $url = WP_CONTENT_URL;
+ if ( 0 === strpos($url, 'http') ) {
+ if ( is_ssl() )
+ $url = str_replace( 'http://', "{$scheme}://", $url );
+ }
+
+ if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
+ $url .= '/' . ltrim($path, '/');
+
+ return $url;
+}
+
+/**
+ * Retrieve the url to the plugins directory.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional. Path relative to the plugins url.
+ * @return string Plugins url link with optional path appended.
+*/
+function plugins_url($path = '') {
+ $scheme = ( is_ssl() ? 'https' : 'http' );
+ $url = WP_PLUGIN_URL;
+ if ( 0 === strpos($url, 'http') ) {
+ if ( is_ssl() )
+ $url = str_replace( 'http://', "{$scheme}://", $url );
+ }
+
+ if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
+ $url .= '/' . ltrim($path, '/');
+
+ return $url;
+}
+
+?>
diff -uNr a/blog/wp-includes/locale.php b/blog/wp-includes/locale.php
--- a/blog/wp-includes/locale.php false
+++ b/blog/wp-includes/locale.php 3a3047660ecd0da7c748310ca48e0693c0c9a6dd951d40ad7b07537efc6d41bd6dc4ffb8c7dec72013d13ae86b0a3e2cc9b74f1660a2852dcb2d919245a38101
@@ -0,0 +1,332 @@
+weekday[0] = __('Sunday');
+ $this->weekday[1] = __('Monday');
+ $this->weekday[2] = __('Tuesday');
+ $this->weekday[3] = __('Wednesday');
+ $this->weekday[4] = __('Thursday');
+ $this->weekday[5] = __('Friday');
+ $this->weekday[6] = __('Saturday');
+
+ // The first letter of each day. The _%day%_initial suffix is a hack to make
+ // sure the day initials are unique.
+ $this->weekday_initial[__('Sunday')] = __('S_Sunday_initial');
+ $this->weekday_initial[__('Monday')] = __('M_Monday_initial');
+ $this->weekday_initial[__('Tuesday')] = __('T_Tuesday_initial');
+ $this->weekday_initial[__('Wednesday')] = __('W_Wednesday_initial');
+ $this->weekday_initial[__('Thursday')] = __('T_Thursday_initial');
+ $this->weekday_initial[__('Friday')] = __('F_Friday_initial');
+ $this->weekday_initial[__('Saturday')] = __('S_Saturday_initial');
+
+ foreach ($this->weekday_initial as $weekday_ => $weekday_initial_) {
+ $this->weekday_initial[$weekday_] = preg_replace('/_.+_initial$/', '', $weekday_initial_);
+ }
+
+ // Abbreviations for each day.
+ $this->weekday_abbrev[__('Sunday')] = __('Sun');
+ $this->weekday_abbrev[__('Monday')] = __('Mon');
+ $this->weekday_abbrev[__('Tuesday')] = __('Tue');
+ $this->weekday_abbrev[__('Wednesday')] = __('Wed');
+ $this->weekday_abbrev[__('Thursday')] = __('Thu');
+ $this->weekday_abbrev[__('Friday')] = __('Fri');
+ $this->weekday_abbrev[__('Saturday')] = __('Sat');
+
+ // The Months
+ $this->month['01'] = __('January');
+ $this->month['02'] = __('February');
+ $this->month['03'] = __('March');
+ $this->month['04'] = __('April');
+ $this->month['05'] = __('May');
+ $this->month['06'] = __('June');
+ $this->month['07'] = __('July');
+ $this->month['08'] = __('August');
+ $this->month['09'] = __('September');
+ $this->month['10'] = __('October');
+ $this->month['11'] = __('November');
+ $this->month['12'] = __('December');
+
+ // Abbreviations for each month. Uses the same hack as above to get around the
+ // 'May' duplication.
+ $this->month_abbrev[__('January')] = __('Jan_January_abbreviation');
+ $this->month_abbrev[__('February')] = __('Feb_February_abbreviation');
+ $this->month_abbrev[__('March')] = __('Mar_March_abbreviation');
+ $this->month_abbrev[__('April')] = __('Apr_April_abbreviation');
+ $this->month_abbrev[__('May')] = __('May_May_abbreviation');
+ $this->month_abbrev[__('June')] = __('Jun_June_abbreviation');
+ $this->month_abbrev[__('July')] = __('Jul_July_abbreviation');
+ $this->month_abbrev[__('August')] = __('Aug_August_abbreviation');
+ $this->month_abbrev[__('September')] = __('Sep_September_abbreviation');
+ $this->month_abbrev[__('October')] = __('Oct_October_abbreviation');
+ $this->month_abbrev[__('November')] = __('Nov_November_abbreviation');
+ $this->month_abbrev[__('December')] = __('Dec_December_abbreviation');
+
+ foreach ($this->month_abbrev as $month_ => $month_abbrev_) {
+ $this->month_abbrev[$month_] = preg_replace('/_.+_abbreviation$/', '', $month_abbrev_);
+ }
+
+ // The Meridiems
+ $this->meridiem['am'] = __(' a.m.');
+ $this->meridiem['pm'] = __(' p.m.');
+ $this->meridiem['AM'] = __(' a.m');
+ $this->meridiem['PM'] = __(' p.m.');
+
+ // Numbers formatting
+ // See http://php.net/number_format
+
+ $trans = _c('number_format_decimals|$decimals argument for http://php.net/number_format, default is 0');
+ $this->number_format['decimals'] = ('number_format_decimals' == $trans) ? 0 : $trans;
+
+ $trans = _c('number_format_decimal_point|$dec_point argument for http://php.net/number_format, default is .');
+ $this->number_format['decimal_point'] = ('number_format_decimal_point' == $trans) ? '.' : $trans;
+
+ $trans = _c('number_format_thousands_sep|$thousands_sep argument for http://php.net/number_format, default is ,');
+ $this->number_format['thousands_sep'] = ('number_format_thousands_sep' == $trans) ? ',' : $trans;
+
+ // Import global locale vars set during inclusion of $locale.php.
+ foreach ( (array) $this->locale_vars as $var ) {
+ if ( isset($GLOBALS[$var]) )
+ $this->$var = $GLOBALS[$var];
+ }
+
+ }
+
+ /**
+ * Retrieve the full translated weekday word.
+ *
+ * Week starts on translated Duminica and can be fetched
+ * by using 0 (zero). So the week starts with 0 (zero)
+ * and ends on Sambata with is fetched by using 6 (six).
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param int $weekday_number 0 for Duminica through 6 Sambata
+ * @return string Full translated weekday
+ */
+ function get_weekday($weekday_number) {
+ return $this->weekday[$weekday_number];
+ }
+
+ /**
+ * Retrieve the translated weekday initial.
+ *
+ * The weekday initial is retrieved by the translated
+ * full weekday word. When translating the weekday initial
+ * pay attention to make sure that the starting letter does
+ * not conflict.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $weekday_name
+ * @return string
+ */
+ function get_weekday_initial($weekday_name) {
+ return $this->weekday_initial[$weekday_name];
+ }
+
+ /**
+ * Retrieve the translated weekday abbreviation.
+ *
+ * The weekday abbreviation is retrieved by the translated
+ * full weekday word.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $weekday_name Full translated weekday word
+ * @return string Translated weekday abbreviation
+ */
+ function get_weekday_abbrev($weekday_name) {
+ return $this->weekday_abbrev[$weekday_name];
+ }
+
+ /**
+ * Retrieve the full translated month by month number.
+ *
+ * The $month_number parameter has to be a string
+ * because it must have the '0' in front of any number
+ * that is less than 10. Starts from '01' and ends at
+ * '12'.
+ *
+ * You can use an integer instead and it will add the
+ * '0' before the numbers less than 10 for you.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string|int $month_number '01' through '12'
+ * @return string Translated full month name
+ */
+ function get_month($month_number) {
+ return $this->month[zeroise($month_number, 2)];
+ }
+
+ /**
+ * Retrieve translated version of month abbreviation string.
+ *
+ * The $month_name parameter is expected to be the translated or
+ * translatable version of the month.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $month_name Translated month to get abbreviated version
+ * @return string Translated abbreviated month
+ */
+ function get_month_abbrev($month_name) {
+ return $this->month_abbrev[$month_name];
+ }
+
+ /**
+ * Retrieve translated version of meridiem string.
+ *
+ * The $meridiem parameter is expected to not be translated.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $meridiem Either 'am', 'pm', 'AM', or 'PM'. Not translated version.
+ * @return string Translated version
+ */
+ function get_meridiem($meridiem) {
+ return $this->meridiem[$meridiem];
+ }
+
+ /**
+ * Global variables are deprecated. For backwards compatibility only.
+ *
+ * @deprecated For backwards compatibility only.
+ * @access private
+ *
+ * @since 2.1.0
+ */
+ function register_globals() {
+ $GLOBALS['weekday'] = $this->weekday;
+ $GLOBALS['weekday_initial'] = $this->weekday_initial;
+ $GLOBALS['weekday_abbrev'] = $this->weekday_abbrev;
+ $GLOBALS['month'] = $this->month;
+ $GLOBALS['month_abbrev'] = $this->month_abbrev;
+ }
+
+ /**
+ * PHP4 style constructor which calls helper methods to set up object variables
+ *
+ * @uses WP_Locale::init()
+ * @uses WP_Locale::register_globals()
+ * @since 2.1.0
+ *
+ * @return WP_Locale
+ */
+ function WP_Locale() {
+ $this->init();
+ $this->register_globals();
+ }
+}
+
+?>
diff -uNr a/blog/wp-includes/media.php b/blog/wp-includes/media.php
--- a/blog/wp-includes/media.php false
+++ b/blog/wp-includes/media.php b6f9e2549a78c9e341bc99cf823fdf0c5583e0b1a9108cf5dc639bc123834a4e78a696ce64029e6348c8d52b9332aef02c5c3fc5f8e149656cc6d486b0e5b1c4
@@ -0,0 +1,769 @@
+ 0 )
+ $max_width = min( intval($content_width), $max_width );
+ }
+ // $size == 'full' has no constraint
+ else {
+ $max_width = $width;
+ $max_height = $height;
+ }
+
+ list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size );
+
+ return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
+}
+
+/**
+ * Retrieve width and height attributes using given width and height values.
+ *
+ * Both attributes are required in the sense that both parameters must have a
+ * value, but are optional in that if you set them to false or null, then they
+ * will not be added to the returned string.
+ *
+ * You can set the value using a string, but it will only take numeric values.
+ * If you wish to put 'px' after the numbers, then it will be stripped out of
+ * the return.
+ *
+ * @since 2.5.0
+ *
+ * @param int|string $width Optional. Width attribute value.
+ * @param int|string $height Optional. Height attribute value.
+ * @return string HTML attributes for width and, or height.
+ */
+function image_hwstring($width, $height) {
+ $out = '';
+ if ($width)
+ $out .= 'width="'.intval($width).'" ';
+ if ($height)
+ $out .= 'height="'.intval($height).'" ';
+ return $out;
+}
+
+/**
+ * Scale an image to fit a particular size (such as 'thumb' or 'medium').
+ *
+ * Array with image url, width, height, and whether is intermediate size, in
+ * that order is returned on success is returned. $is_intermediate is true if
+ * $url is a resized image, false if it is the original.
+ *
+ * The URL might be the original image, or it might be a resized version. This
+ * function won't create a new resized copy, it will just return an already
+ * resized one if it exists.
+ *
+ * A plugin may use the 'image_downsize' filter to hook into and offer image
+ * resizing services for images. The hook must return an array with the same
+ * elements that are returned in the function. The first element being the URL
+ * to the new image that was resized.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'image_downsize' on $id and $size to provide
+ * resize services.
+ *
+ * @param int $id Attachment ID for image.
+ * @param string $size Optional, default is 'medium'. Size of image, can be 'thumbnail'.
+ * @return bool|array False on failure, array on success.
+ */
+function image_downsize($id, $size = 'medium') {
+
+ if ( !wp_attachment_is_image($id) )
+ return false;
+
+ $img_url = wp_get_attachment_url($id);
+ $meta = wp_get_attachment_metadata($id);
+ $width = $height = 0;
+ $is_intermediate = false;
+
+ // plugins can use this to provide resize services
+ if ( $out = apply_filters('image_downsize', false, $id, $size) )
+ return $out;
+
+ // try for a new style intermediate size
+ if ( $intermediate = image_get_intermediate_size($id, $size) ) {
+ $img_url = str_replace(basename($img_url), $intermediate['file'], $img_url);
+ $width = $intermediate['width'];
+ $height = $intermediate['height'];
+ $is_intermediate = true;
+ }
+ elseif ( $size == 'thumbnail' ) {
+ // fall back to the old thumbnail
+ if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) {
+ $img_url = str_replace(basename($img_url), basename($thumb_file), $img_url);
+ $width = $info[0];
+ $height = $info[1];
+ $is_intermediate = true;
+ }
+ }
+ if ( !$width && !$height && isset($meta['width'], $meta['height']) ) {
+ // any other type: use the real image
+ $width = $meta['width'];
+ $height = $meta['height'];
+ }
+
+ if ( $img_url) {
+ // we have the actual image size, but might need to further constrain it if content_width is narrower
+ list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
+
+ return array( $img_url, $width, $height, $is_intermediate );
+ }
+ return false;
+
+}
+
+/**
+ * An tag for an image attachment, scaling it down if requested.
+ *
+ * The filter 'get_image_tag_class' allows for changing the class name for the
+ * image without having to use regular expressions on the HTML content. The
+ * parameters are: what WordPress will use for the class, the Attachment ID,
+ * image align value, and the size the image should be.
+ *
+ * The second filter 'get_image_tag' has the HTML content, which can then be
+ * further manipulated by a plugin to change all attribute values and even HTML
+ * content.
+ *
+ * @since 2.5.0
+ *
+ * @uses apply_filters() The 'get_image_tag_class' filter is the IMG element
+ * class attribute.
+ * @uses apply_filters() The 'get_image_tag' filter is the full IMG element with
+ * all attributes.
+ *
+ * @param int $id Attachment ID.
+ * @param string $alt Image Description for the alt attribute.
+ * @param string $title Image Description for the title attribute.
+ * @param string $align Part of the class name for aligning the image.
+ * @param string $size Optional. Default is 'medium'.
+ * @return string HTML IMG element for given image attachment
+ */
+function get_image_tag($id, $alt, $title, $align, $size='medium') {
+
+ list( $img_src, $width, $height ) = image_downsize($id, $size);
+ $hwstring = image_hwstring($width, $height);
+
+ $class = 'align'.attribute_escape($align).' size-'.attribute_escape($size).' wp-image-'.$id;
+ $class = apply_filters('get_image_tag_class', $class, $id, $align, $size);
+
+ $html = ' ';
+
+ $html = apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
+
+ return $html;
+}
+
+/**
+ * Calculates the new dimentions for a downsampled image.
+ *
+ * Same as {@link wp_shrink_dimensions()}, except the max parameters are
+ * optional. If either width or height are empty, no constraint is applied on
+ * that dimension.
+ *
+ * @since 2.5.0
+ *
+ * @param int $current_width Current width of the image.
+ * @param int $current_height Current height of the image.
+ * @param int $max_width Optional. Maximum wanted width.
+ * @param int $max_height Optional. Maximum wanted height.
+ * @return array First item is the width, the second item is the height.
+ */
+function wp_constrain_dimensions( $current_width, $current_height, $max_width=0, $max_height=0 ) {
+ if ( !$max_width and !$max_height )
+ return array( $current_width, $current_height );
+
+ $width_ratio = $height_ratio = 1.0;
+
+ if ( $max_width > 0 && $current_width > $max_width )
+ $width_ratio = $max_width / $current_width;
+
+ if ( $max_height > 0 && $current_height > $max_height )
+ $height_ratio = $max_height / $current_height;
+
+ // the smaller ratio is the one we need to fit it to the constraining box
+ $ratio = min( $width_ratio, $height_ratio );
+
+ return array( intval($current_width * $ratio), intval($current_height * $ratio) );
+}
+
+/**
+ * Retrieve calculated resized dimensions for use in imagecopyresampled().
+ *
+ * Calculate dimensions and coordinates for a resized image that fits within a
+ * specified width and height. If $crop is true, the largest matching central
+ * portion of the image will be cropped out and resized to the required size.
+ *
+ * @since 2.5.0
+ *
+ * @param int $orig_w Original width.
+ * @param int $orig_h Original height.
+ * @param int $dest_w New width.
+ * @param int $dest_h New height.
+ * @param bool $crop Optional, default is false. Whether to crop image or resize.
+ * @return bool|array False, on failure. Returned array matches parameters for imagecopyresampled() PHP function.
+ */
+function image_resize_dimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop=false) {
+
+ if ($orig_w <= 0 || $orig_h <= 0)
+ return false;
+ // at least one of dest_w or dest_h must be specific
+ if ($dest_w <= 0 && $dest_h <= 0)
+ return false;
+
+ if ( $crop ) {
+ // crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
+ $aspect_ratio = $orig_w / $orig_h;
+ $new_w = min($dest_w, $orig_w);
+ $new_h = min($dest_h, $orig_h);
+ if (!$new_w) {
+ $new_w = intval($new_h * $aspect_ratio);
+ }
+ if (!$new_h) {
+ $new_h = intval($new_w / $aspect_ratio);
+ }
+
+ $size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
+
+ $crop_w = ceil($new_w / $size_ratio);
+ $crop_h = ceil($new_h / $size_ratio);
+
+ $s_x = floor(($orig_w - $crop_w)/2);
+ $s_y = floor(($orig_h - $crop_h)/2);
+ }
+ else {
+ // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
+ $crop_w = $orig_w;
+ $crop_h = $orig_h;
+
+ $s_x = 0;
+ $s_y = 0;
+
+ list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
+ }
+
+ // if the resulting image would be the same size or larger we don't want to resize it
+ if ($new_w >= $orig_w && $new_h >= $orig_h)
+ return false;
+
+ // the return array matches the parameters to imagecopyresampled()
+ // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
+ return array(0, 0, $s_x, $s_y, $new_w, $new_h, $crop_w, $crop_h);
+
+}
+
+/**
+ * Scale down an image to fit a particular size and save a new copy of the image.
+ *
+ * The PNG transparency will be preserved using the function, as well as the
+ * image type. If the file going in is PNG, then the resized image is going to
+ * be PNG. The only supported image types are PNG, GIF, and JPEG.
+ *
+ * Some functionality requires API to exist, so some PHP version may lose out
+ * support. This is not the fault of WordPress (where functionality is
+ * downgraded, not actual defects), but of your PHP version.
+ *
+ * @since 2.5.0
+ *
+ * @param string $file Image file path.
+ * @param int $max_w Maximum width to resize to.
+ * @param int $max_h Maximum height to resize to.
+ * @param bool $crop Optional. Whether to crop image or resize.
+ * @param string $suffix Optional. File Suffix.
+ * @param string $dest_path Optional. New image file path.
+ * @param int $jpeg_quality Optional, default is 90. Image quality percentage.
+ * @return mixed WP_Error on failure. String with new destination path. Array of dimensions from {@link image_resize_dimensions()}
+ */
+function image_resize( $file, $max_w, $max_h, $crop=false, $suffix=null, $dest_path=null, $jpeg_quality=90) {
+
+ $image = wp_load_image( $file );
+ if ( !is_resource( $image ) )
+ return new WP_Error('error_loading_image', $image);
+
+ list($orig_w, $orig_h, $orig_type) = getimagesize( $file );
+ $dims = image_resize_dimensions($orig_w, $orig_h, $max_w, $max_h, $crop);
+ if (!$dims)
+ return $dims;
+ list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims;
+
+ $newimage = imagecreatetruecolor( $dst_w, $dst_h);
+
+ // preserve PNG transparency
+ if ( IMAGETYPE_PNG == $orig_type && function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) {
+ imagealphablending( $newimage, false);
+ imagesavealpha( $newimage, true);
+ }
+
+ imagecopyresampled( $newimage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
+
+ // we don't need the original in memory anymore
+ imagedestroy( $image );
+
+ // $suffix will be appended to the destination filename, just before the extension
+ if ( !$suffix )
+ $suffix = "{$dst_w}x{$dst_h}";
+
+ $info = pathinfo($file);
+ $dir = $info['dirname'];
+ $ext = $info['extension'];
+ $name = basename($file, ".{$ext}");
+ if ( !is_null($dest_path) and $_dest_path = realpath($dest_path) )
+ $dir = $_dest_path;
+ $destfilename = "{$dir}/{$name}-{$suffix}.{$ext}";
+
+ if ( $orig_type == IMAGETYPE_GIF ) {
+ if (!imagegif( $newimage, $destfilename ) )
+ return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
+ }
+ elseif ( $orig_type == IMAGETYPE_PNG ) {
+ if (!imagepng( $newimage, $destfilename ) )
+ return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
+ }
+ else {
+ // all other formats are converted to jpg
+ $destfilename = "{$dir}/{$name}-{$suffix}.jpg";
+ if (!imagejpeg( $newimage, $destfilename, apply_filters( 'jpeg_quality', $jpeg_quality ) ) )
+ return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
+ }
+
+ imagedestroy( $newimage );
+
+ // Set correct file permissions
+ $stat = stat( dirname( $destfilename ));
+ $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
+ @ chmod( $destfilename, $perms );
+
+ return $destfilename;
+}
+
+/**
+ * Resize an image to make a thumbnail or intermediate size.
+ *
+ * The returned array has the file size, the image width, and image height. The
+ * filter 'image_make_intermediate_size' can be used to hook in and change the
+ * values of the returned array. The only parameter is the resized file path.
+ *
+ * @since 2.5.0
+ *
+ * @param string $file File path.
+ * @param int $width Image width.
+ * @param int $height Image height.
+ * @param bool $crop Optional, default is false. Whether to crop image to specified height and width or resize.
+ * @return bool|array False, if no image was created. Metadata array on success.
+ */
+function image_make_intermediate_size($file, $width, $height, $crop=false) {
+ if ( $width || $height ) {
+ $resized_file = image_resize($file, $width, $height, $crop);
+ if ( !is_wp_error($resized_file) && $resized_file && $info = getimagesize($resized_file) ) {
+ $resized_file = apply_filters('image_make_intermediate_size', $resized_file);
+ return array(
+ 'file' => basename( $resized_file ),
+ 'width' => $info[0],
+ 'height' => $info[1],
+ );
+ }
+ }
+ return false;
+}
+
+/**
+ * Retrieve the image's intermediate size (resized) path, width, and height.
+ *
+ * The $size parameter can be an array with the width and height respectively.
+ * If the size matches the 'sizes' metadata array for width and height, then it
+ * will be used. If there is no direct match, then the nearest image size larger
+ * than the specified size will be used. If nothing is found, then the function
+ * will break out and return false.
+ *
+ * The metadata 'sizes' is used for compatible sizes that can be used for the
+ * parameter $size value.
+ *
+ * The url path will be given, when the $size parameter is a string.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Attachment ID for image.
+ * @param array|string $size Optional, default is 'thumbnail'. Size of image, either array or string.
+ * @return bool|array False on failure or array of file path, width, and height on success.
+ */
+function image_get_intermediate_size($post_id, $size='thumbnail') {
+ if ( !is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) )
+ return false;
+
+ // get the best one for a specified set of dimensions
+ if ( is_array($size) && !empty($imagedata['sizes']) ) {
+ foreach ( $imagedata['sizes'] as $_size => $data ) {
+ // already cropped to width or height; so use this size
+ if ( ( $data['width'] == $size[0] && $data['height'] <= $size[1] ) || ( $data['height'] == $size[1] && $data['width'] <= $size[0] ) ) {
+ $file = $data['file'];
+ list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
+ return compact( 'file', 'width', 'height' );
+ }
+ // add to lookup table: area => size
+ $areas[$data['width'] * $data['height']] = $_size;
+ }
+ if ( !$size || !empty($areas) ) {
+ // find for the smallest image not smaller than the desired size
+ ksort($areas);
+ foreach ( $areas as $_size ) {
+ $data = $imagedata['sizes'][$_size];
+ if ( $data['width'] >= $size[0] || $data['height'] >= $size[1] ) {
+ $file = $data['file'];
+ list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
+ return compact( 'file', 'width', 'height' );
+ }
+ }
+ }
+ }
+
+ if ( is_array($size) || empty($size) || empty($imagedata['sizes'][$size]) )
+ return false;
+
+ $data = $imagedata['sizes'][$size];
+ // include the full filesystem path of the intermediate file
+ if ( empty($data['path']) && !empty($data['file']) ) {
+ $file_url = wp_get_attachment_url($post_id);
+ $data['path'] = path_join( dirname($imagedata['file']), $data['file'] );
+ $data['url'] = path_join( dirname($file_url), $data['file'] );
+ }
+ return $data;
+}
+
+/**
+ * Retrieve an image to represent an attachment.
+ *
+ * A mime icon for files, thumbnail or intermediate size for images.
+ *
+ * @since 2.5.0
+ *
+ * @param int $attachment_id Image attachment ID.
+ * @param string $size Optional, default is 'thumbnail'.
+ * @param bool $icon Optional, default is false. Whether it is an icon.
+ * @return bool|array Returns an array (url, width, height), or false, if no image is available.
+ */
+function wp_get_attachment_image_src($attachment_id, $size='thumbnail', $icon = false) {
+
+ // get a thumbnail or intermediate image if there is one
+ if ( $image = image_downsize($attachment_id, $size) )
+ return $image;
+
+ if ( $icon && $src = wp_mime_type_icon($attachment_id) ) {
+ $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' );
+ $src_file = $icon_dir . '/' . basename($src);
+ @list($width, $height) = getimagesize($src_file);
+ }
+ if ( $src && $width && $height )
+ return array( $src, $width, $height );
+ return false;
+}
+
+/**
+ * Retrieve img HTML content for an image to represent an attachment.
+ *
+ * @see wp_get_attachment_image_src() Returns img HTML element based on array.
+ * @since 2.5.0
+ *
+ * @param int $attachment_id Image attachment ID.
+ * @param string $size Optional, default is 'thumbnail'.
+ * @param bool $icon Optional, default is false. Whether it is an icon.
+ * @return string HTML img element or empty string on failure.
+ */
+function wp_get_attachment_image($attachment_id, $size = 'thumbnail', $icon = false) {
+
+ $html = '';
+ $image = wp_get_attachment_image_src($attachment_id, $size, $icon);
+ if ( $image ) {
+ list($src, $width, $height) = $image;
+ $hwstring = image_hwstring($width, $height);
+ if ( is_array($size) )
+ $size = join('x', $size);
+ $html = ' ';
+ }
+
+ return $html;
+}
+
+add_shortcode('wp_caption', 'img_caption_shortcode');
+add_shortcode('caption', 'img_caption_shortcode');
+
+/**
+ * The Caption shortcode.
+ *
+ * Allows a plugin to replace the content that would otherwise be returned. The
+ * filter is 'img_caption_shortcode' and passes an empty string, the attr
+ * parameter and the content parameter values.
+ *
+ * The supported attributes for the shortcode are 'id', 'align', 'width', and
+ * 'caption'.
+ *
+ * @since 2.6.0
+ *
+ * @param array $attr Attributes attributed to the shortcode.
+ * @param string $content Optional. Shortcode content.
+ * @return string
+ */
+function img_caption_shortcode($attr, $content = null) {
+
+ // Allow plugins/themes to override the default caption template.
+ $output = apply_filters('img_caption_shortcode', '', $attr, $content);
+ if ( $output != '' )
+ return $output;
+
+ extract(shortcode_atts(array(
+ 'id' => '',
+ 'align' => 'alignnone',
+ 'width' => '',
+ 'caption' => ''
+ ), $attr));
+
+ if ( 1 > (int) $width || empty($caption) )
+ return $content;
+
+ if ( $id ) $id = 'id="' . $id . '" ';
+
+ return ''
+ . $content . '
' . $caption . '
';
+}
+
+add_shortcode('gallery', 'gallery_shortcode');
+
+/**
+ * The Gallery shortcode.
+ *
+ * This implements the functionality of the Gallery Shortcode for displaying
+ * WordPress images on a post.
+ *
+ * @since 2.5.0
+ *
+ * @param array $attr Attributes attributed to the shortcode.
+ * @return string HTML content to display gallery.
+ */
+function gallery_shortcode($attr) {
+ global $post;
+
+ // Allow plugins/themes to override the default gallery template.
+ $output = apply_filters('post_gallery', '', $attr);
+ if ( $output != '' )
+ return $output;
+
+ // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
+ if ( isset( $attr['orderby'] ) ) {
+ $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
+ if ( !$attr['orderby'] )
+ unset( $attr['orderby'] );
+ }
+
+ extract(shortcode_atts(array(
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order ID',
+ 'id' => $post->ID,
+ 'itemtag' => 'dl',
+ 'icontag' => 'dt',
+ 'captiontag' => 'dd',
+ 'columns' => 3,
+ 'size' => 'thumbnail'
+ ), $attr));
+
+ $id = intval($id);
+ $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
+
+ if ( empty($attachments) )
+ return '';
+
+ if ( is_feed() ) {
+ $output = "\n";
+ foreach ( $attachments as $id => $attachment )
+ $output .= wp_get_attachment_link($id, $size, true) . "\n";
+ return $output;
+ }
+
+ $itemtag = tag_escape($itemtag);
+ $captiontag = tag_escape($captiontag);
+ $columns = intval($columns);
+ $itemwidth = $columns > 0 ? floor(100/$columns) : 100;
+
+ $output = apply_filters('gallery_style', "
+
+
+ ");
+
+ $i = 0;
+ foreach ( $attachments as $id => $attachment ) {
+ $link = isset($attr['link']) && 'file' == $attr['link'] ? wp_get_attachment_link($id, $size, false, false) : wp_get_attachment_link($id, $size, true, false);
+
+ $output .= "<{$itemtag} class='gallery-item'>";
+ $output .= "
+ <{$icontag} class='gallery-icon'>
+ $link
+ ";
+ if ( $captiontag && trim($attachment->post_excerpt) ) {
+ $output .= "
+ <{$captiontag} class='gallery-caption'>
+ {$attachment->post_excerpt}
+ ";
+ }
+ $output .= "";
+ if ( $columns > 0 && ++$i % $columns == 0 )
+ $output .= ' ';
+ }
+
+ $output .= "
+
+
\n";
+
+ return $output;
+}
+
+/**
+ * Display previous image link that has the same post parent.
+ *
+ * @since 2.5.0
+ */
+function previous_image_link() {
+ adjacent_image_link(true);
+}
+
+/**
+ * Display next image link that has the same post parent.
+ *
+ * @since 2.5.0
+ */
+function next_image_link() {
+ adjacent_image_link(false);
+}
+
+/**
+ * Display next or previous image link that has the same post parent.
+ *
+ * Retrieves the current attachment object from the $post global.
+ *
+ * @since 2.5.0
+ *
+ * @param bool $prev Optional. Default is true to display previous link, true for next.
+ */
+function adjacent_image_link($prev = true) {
+ global $post;
+ $post = get_post($post);
+ $attachments = array_values(get_children( array('post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID') ));
+
+ foreach ( $attachments as $k => $attachment )
+ if ( $attachment->ID == $post->ID )
+ break;
+
+ $k = $prev ? $k - 1 : $k + 1;
+
+ if ( isset($attachments[$k]) )
+ echo wp_get_attachment_link($attachments[$k]->ID, 'thumbnail', true);
+}
+
+/**
+ * Retrieve taxonomies attached to the attachment.
+ *
+ * @since 2.5.0
+ *
+ * @param int|array|object $attachment Attachment ID, Attachment data array, or Attachment data object.
+ * @return array Empty array on failure. List of taxonomies on success.
+ */
+function get_attachment_taxonomies($attachment) {
+ if ( is_int( $attachment ) )
+ $attachment = get_post($attachment);
+ else if ( is_array($attachment) )
+ $attachment = (object) $attachment;
+
+ if ( ! is_object($attachment) )
+ return array();
+
+ $filename = basename($attachment->guid);
+
+ $objects = array('attachment');
+
+ if ( false !== strpos($filename, '.') )
+ $objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1);
+ if ( !empty($attachment->post_mime_type) ) {
+ $objects[] = 'attachment:' . $attachment->post_mime_type;
+ if ( false !== strpos($attachment->post_mime_type, '/') )
+ foreach ( explode('/', $attachment->post_mime_type) as $token )
+ if ( !empty($token) )
+ $objects[] = "attachment:$token";
+ }
+
+ $taxonomies = array();
+ foreach ( $objects as $object )
+ if ( $taxes = get_object_taxonomies($object) )
+ $taxonomies = array_merge($taxonomies, $taxes);
+
+ return array_unique($taxonomies);
+}
+
+?>
diff -uNr a/blog/wp-includes/pluggable.php b/blog/wp-includes/pluggable.php
--- a/blog/wp-includes/pluggable.php false
+++ b/blog/wp-includes/pluggable.php 3110eece15f60648ccf533c983427817795ba191289440bc291200e84cd4b75a3a23d4fcf2d485531da7ab4d265d1729af83e7cca7509702b4d6118dad1362c3
@@ -0,0 +1,1739 @@
+ID) )
+ return $current_user;
+
+ $current_user = new WP_User($id, $name);
+
+ setup_userdata($current_user->ID);
+
+ do_action('set_current_user');
+
+ return $current_user;
+}
+endif;
+
+if ( !function_exists('wp_get_current_user') ) :
+/**
+ * Retrieve the current user object.
+ *
+ * @since 2.0.4
+ *
+ * @return WP_User Current user WP_User object
+ */
+function wp_get_current_user() {
+ global $current_user;
+
+ get_currentuserinfo();
+
+ return $current_user;
+}
+endif;
+
+if ( !function_exists('get_currentuserinfo') ) :
+/**
+ * Populate global variables with information about the currently logged in user.
+ *
+ * Will set the current user, if the current user is not set. The current user
+ * will be set to the logged in person. If no user is logged in, then it will
+ * set the current user to 0, which is invalid and won't have any permissions.
+ *
+ * @since 0.71
+ * @uses $current_user Checks if the current user is set
+ * @uses wp_validate_auth_cookie() Retrieves current logged in user.
+ *
+ * @return bool|null False on XMLRPC Request and invalid auth cookie. Null when current user set
+ */
+function get_currentuserinfo() {
+ global $current_user;
+
+ if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST )
+ return false;
+
+ if ( ! empty($current_user) )
+ return;
+
+ if ( ! $user = wp_validate_auth_cookie() ) {
+ if ( empty($_COOKIE[LOGGED_IN_COOKIE]) || !$user = wp_validate_auth_cookie($_COOKIE[LOGGED_IN_COOKIE], 'logged_in') ) {
+ wp_set_current_user(0);
+ return false;
+ }
+ }
+
+ wp_set_current_user($user);
+}
+endif;
+
+if ( !function_exists('get_userdata') ) :
+/**
+ * Retrieve user info by user ID.
+ *
+ * @since 0.71
+ *
+ * @param int $user_id User ID
+ * @return bool|object False on failure, User DB row object
+ */
+function get_userdata( $user_id ) {
+ global $wpdb;
+
+ $user_id = absint($user_id);
+ if ( $user_id == 0 )
+ return false;
+
+ $user = wp_cache_get($user_id, 'users');
+
+ if ( $user )
+ return $user;
+
+ if ( !$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE ID = %d LIMIT 1", $user_id)) )
+ return false;
+
+ _fill_user($user);
+
+ return $user;
+}
+endif;
+
+if ( !function_exists('update_user_cache') ) :
+/**
+ * Updates a users cache when overridden by a plugin.
+ *
+ * Core function does nothing.
+ *
+ * @since 1.5
+ *
+ * @return bool Only returns true
+ */
+function update_user_cache() {
+ return true;
+}
+endif;
+
+if ( !function_exists('get_userdatabylogin') ) :
+/**
+ * Retrieve user info by login name.
+ *
+ * @since 0.71
+ *
+ * @param string $user_login User's username
+ * @return bool|object False on failure, User DB row object
+ */
+function get_userdatabylogin($user_login) {
+ global $wpdb;
+ $user_login = sanitize_user( $user_login );
+
+ if ( empty( $user_login ) )
+ return false;
+
+ $user_id = wp_cache_get($user_login, 'userlogins');
+
+ $user = false;
+ if ( false !== $user_id )
+ $user = wp_cache_get($user_id, 'users');
+
+ if ( false !== $user )
+ return $user;
+
+ if ( !$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_login = %s", $user_login)) )
+ return false;
+
+ _fill_user($user);
+
+ return $user;
+}
+endif;
+
+if ( !function_exists('get_user_by_email') ) :
+/**
+ * Retrieve user info by email.
+ *
+ * @since 2.5
+ *
+ * @param string $email User's email address
+ * @return bool|object False on failure, User DB row object
+ */
+function get_user_by_email($email) {
+ global $wpdb;
+
+ $user_id = wp_cache_get($email, 'useremail');
+
+ $user = false;
+ if ( false !== $user_id )
+ $user = wp_cache_get($user_id, 'users');
+
+ if ( false !== $user )
+ return $user;
+
+ if ( !$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_email = %s", $email)) )
+ return false;
+
+ _fill_user($user);
+
+ return $user;
+}
+endif;
+
+if ( !function_exists( 'wp_mail' ) ) :
+/**
+ * Send mail, similar to PHP's mail
+ *
+ * A true return value does not automatically mean that the user received the
+ * email successfully. It just only means that the method used was able to
+ * process the request without any errors.
+ *
+ * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
+ * creating a from address like 'Name ' when both are set. If
+ * just 'wp_mail_from' is set, then just the email address will be used with no
+ * name.
+ *
+ * The default content type is 'text/plain' which does not allow using HTML.
+ * However, you can set the content type of the email by using the
+ * 'wp_mail_content_type' filter.
+ *
+ * The default charset is based on the charset used on the blog. The charset can
+ * be set using the 'wp_mail_charset' filter.
+ *
+ * @since 1.2.1
+ * @uses apply_filters() Calls 'wp_mail' hook on an array of all of the parameters.
+ * @uses apply_filters() Calls 'wp_mail_from' hook to get the from email address.
+ * @uses apply_filters() Calls 'wp_mail_from_name' hook to get the from address name.
+ * @uses apply_filters() Calls 'wp_mail_content_type' hook to get the email content type.
+ * @uses apply_filters() Calls 'wp_mail_charset' hook to get the email charset
+ * @uses do_action_ref_array() Calls 'phpmailer_init' hook on the reference to
+ * phpmailer object.
+ * @uses PHPMailer
+ * @
+ *
+ * @param string $to Email address to send message
+ * @param string $subject Email subject
+ * @param string $message Message contents
+ * @param string|array $headers Optional. Additional headers.
+ * @param string|array $attachments Optional. Files to attach.
+ * @return bool Whether the email contents were sent successfully.
+ */
+function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
+ // Compact the input, apply the filters, and extract them back out
+ extract( apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ) );
+
+ if ( !is_array($attachments) )
+ $attachments = explode( "\n", $attachments );
+
+ global $phpmailer;
+
+ // (Re)create it, if it's gone missing
+ if ( !is_object( $phpmailer ) || !is_a( $phpmailer, 'PHPMailer' ) ) {
+ require_once ABSPATH . WPINC . '/class-phpmailer.php';
+ require_once ABSPATH . WPINC . '/class-smtp.php';
+ $phpmailer = new PHPMailer();
+ }
+
+ // Headers
+ if ( empty( $headers ) ) {
+ $headers = array();
+ } elseif ( !is_array( $headers ) ) {
+ // Explode the headers out, so this function can take both
+ // string headers and an array of headers.
+ $tempheaders = (array) explode( "\n", $headers );
+ $headers = array();
+
+ // If it's actually got contents
+ if ( !empty( $tempheaders ) ) {
+ // Iterate through the raw headers
+ foreach ( (array) $tempheaders as $header ) {
+ if ( strpos($header, ':') === false )
+ continue;
+ // Explode them out
+ list( $name, $content ) = explode( ':', trim( $header ), 2 );
+
+ // Cleanup crew
+ $name = trim( $name );
+ $content = trim( $content );
+
+ // Mainly for legacy -- process a From: header if it's there
+ if ( 'from' == strtolower($name) ) {
+ if ( strpos($content, '<' ) !== false ) {
+ // So... making my life hard again?
+ $from_name = substr( $content, 0, strpos( $content, '<' ) - 1 );
+ $from_name = str_replace( '"', '', $from_name );
+ $from_name = trim( $from_name );
+
+ $from_email = substr( $content, strpos( $content, '<' ) + 1 );
+ $from_email = str_replace( '>', '', $from_email );
+ $from_email = trim( $from_email );
+ } else {
+ $from_name = trim( $content );
+ }
+ } elseif ( 'content-type' == strtolower($name) ) {
+ if ( strpos( $content,';' ) !== false ) {
+ list( $type, $charset ) = explode( ';', $content );
+ $content_type = trim( $type );
+ $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset ) );
+ } else {
+ $content_type = trim( $content );
+ }
+ } elseif ( 'cc' == strtolower($name) ) {
+ $cc = explode(",", $content);
+ } elseif ( 'bcc' == strtolower($name) ) {
+ $bcc = explode(",", $content);
+ } else {
+ // Add it to our grand headers array
+ $headers[trim( $name )] = trim( $content );
+ }
+ }
+ }
+ }
+
+ // Empty out the values that may be set
+ $phpmailer->ClearAddresses();
+ $phpmailer->ClearAllRecipients();
+ $phpmailer->ClearAttachments();
+ $phpmailer->ClearBCCs();
+ $phpmailer->ClearCCs();
+ $phpmailer->ClearCustomHeaders();
+ $phpmailer->ClearReplyTos();
+
+ // From email and name
+ // If we don't have a name from the input headers
+ if ( !isset( $from_name ) ) {
+ $from_name = 'WordPress';
+ }
+
+ // If we don't have an email from the input headers
+ if ( !isset( $from_email ) ) {
+ // Get the site domain and get rid of www.
+ $sitename = strtolower( $_SERVER['SERVER_NAME'] );
+ if ( substr( $sitename, 0, 4 ) == 'www.' ) {
+ $sitename = substr( $sitename, 4 );
+ }
+
+ $from_email = 'wordpress@' . $sitename;
+ }
+
+ // Set the from name and email
+ $phpmailer->From = apply_filters( 'wp_mail_from', $from_email );
+ $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name );
+
+ // Set destination address
+ $phpmailer->AddAddress( $to );
+
+ // Set mail's subject and body
+ $phpmailer->Subject = $subject;
+ $phpmailer->Body = $message;
+
+ // Add any CC and BCC recipients
+ if ( !empty($cc) ) {
+ foreach ( (array) $cc as $recipient ) {
+ $phpmailer->AddCc( trim($recipient) );
+ }
+ }
+ if ( !empty($bcc) ) {
+ foreach ( (array) $bcc as $recipient) {
+ $phpmailer->AddBcc( trim($recipient) );
+ }
+ }
+
+ // Set to use PHP's mail()
+ $phpmailer->IsMail();
+
+ // Set Content-Type and charset
+ // If we don't have a content-type from the input headers
+ if ( !isset( $content_type ) ) {
+ $content_type = 'text/plain';
+ }
+
+ $content_type = apply_filters( 'wp_mail_content_type', $content_type );
+
+ // Set whether it's plaintext or not, depending on $content_type
+ if ( $content_type == 'text/html' ) {
+ $phpmailer->IsHTML( true );
+ } else {
+ $phpmailer->IsHTML( false );
+ }
+
+ // If we don't have a charset from the input headers
+ if ( !isset( $charset ) ) {
+ $charset = get_bloginfo( 'charset' );
+ }
+
+ // Set the content-type and charset
+ $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
+
+ // Set custom headers
+ if ( !empty( $headers ) ) {
+ foreach( (array) $headers as $name => $content ) {
+ $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
+ }
+ }
+
+ if ( !empty( $attachments ) ) {
+ foreach ( $attachments as $attachment ) {
+ $phpmailer->AddAttachment($attachment);
+ }
+ }
+
+ do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
+
+ // Send!
+ $result = @$phpmailer->Send();
+
+ return $result;
+}
+endif;
+
+if ( !function_exists('wp_authenticate') ) :
+/**
+ * Checks a user's login information and logs them in if it checks out.
+ *
+ * @since 2.5.0
+ *
+ * @param string $username User's username
+ * @param string $password User's password
+ * @return WP_Error|WP_User WP_User object if login successful, otherwise WP_Error object.
+ */
+function wp_authenticate($username, $password) {
+ $username = sanitize_user($username);
+
+ if ( '' == $username )
+ return new WP_Error('empty_username', __('ERROR : The username field is empty.'));
+
+ if ( '' == $password )
+ return new WP_Error('empty_password', __('ERROR : The password field is empty.'));
+
+ $user = get_userdatabylogin($username);
+
+ if ( !$user || ($user->user_login != $username) ) {
+ do_action( 'wp_login_failed', $username );
+ return new WP_Error('invalid_username', __('ERROR : Invalid username.'));
+ }
+
+ $user = apply_filters('wp_authenticate_user', $user, $password);
+ if ( is_wp_error($user) ) {
+ do_action( 'wp_login_failed', $username );
+ return $user;
+ }
+
+ if ( !wp_check_password($password, $user->user_pass, $user->ID) ) {
+ do_action( 'wp_login_failed', $username );
+ return new WP_Error('incorrect_password', __('ERROR : Incorrect password.'));
+ }
+
+ return new WP_User($user->ID);
+}
+endif;
+
+if ( !function_exists('wp_logout') ) :
+/**
+ * Log the current user out.
+ *
+ * @since 2.5.0
+ */
+function wp_logout() {
+ wp_clear_auth_cookie();
+ do_action('wp_logout');
+}
+endif;
+
+if ( !function_exists('wp_validate_auth_cookie') ) :
+/**
+ * Validates authentication cookie.
+ *
+ * The checks include making sure that the authentication cookie is set and
+ * pulling in the contents (if $cookie is not used).
+ *
+ * Makes sure the cookie is not expired. Verifies the hash in cookie is what is
+ * should be and compares the two.
+ *
+ * @since 2.5
+ *
+ * @param string $cookie Optional. If used, will validate contents instead of cookie's
+ * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
+ * @return bool|int False if invalid cookie, User ID if valid.
+ */
+function wp_validate_auth_cookie($cookie = '', $scheme = '') {
+ if ( ! $cookie_elements = wp_parse_auth_cookie($cookie, $scheme) ) {
+ do_action('auth_cookie_malformed', $cookie, $scheme);
+ return false;
+ }
+
+ extract($cookie_elements, EXTR_OVERWRITE);
+
+ $expired = $expiration;
+
+ // Allow a grace period for POST and AJAX requests
+ if ( defined('DOING_AJAX') || 'POST' == $_SERVER['REQUEST_METHOD'] )
+ $expired += 3600;
+
+ // Quick check to see if an honest cookie has expired
+ if ( $expired < time() ) {
+ do_action('auth_cookie_expired', $cookie_elements);
+ return false;
+ }
+
+ $key = wp_hash($username . '|' . $expiration, $scheme);
+ $hash = hash_hmac('md5', $username . '|' . $expiration, $key);
+
+ if ( $hmac != $hash ) {
+ do_action('auth_cookie_bad_hash', $cookie_elements);
+ return false;
+ }
+
+ $user = get_userdatabylogin($username);
+ if ( ! $user ) {
+ do_action('auth_cookie_bad_username', $cookie_elements);
+ return false;
+ }
+
+ do_action('auth_cookie_valid', $cookie_elements, $user);
+
+ return $user->ID;
+}
+endif;
+
+if ( !function_exists('wp_generate_auth_cookie') ) :
+/**
+ * Generate authentication cookie contents.
+ *
+ * @since 2.5
+ * @uses apply_filters() Calls 'auth_cookie' hook on $cookie contents, User ID
+ * and expiration of cookie.
+ *
+ * @param int $user_id User ID
+ * @param int $expiration Cookie expiration in seconds
+ * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
+ * @return string Authentication cookie contents
+ */
+function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth') {
+ $user = get_userdata($user_id);
+
+ $key = wp_hash($user->user_login . '|' . $expiration, $scheme);
+ $hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
+
+ $cookie = $user->user_login . '|' . $expiration . '|' . $hash;
+
+ return apply_filters('auth_cookie', $cookie, $user_id, $expiration, $scheme);
+}
+endif;
+
+if ( !function_exists('wp_parse_auth_cookie') ) :
+/**
+ * Parse a cookie into its components
+ *
+ * @since 2.7
+ *
+ * @param string $cookie
+ * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
+ * @return array Authentication cookie components
+ */
+function wp_parse_auth_cookie($cookie = '', $scheme = '') {
+ if ( empty($cookie) ) {
+ switch ($scheme){
+ case 'auth':
+ $cookie_name = AUTH_COOKIE;
+ break;
+ case 'secure_auth':
+ $cookie_name = SECURE_AUTH_COOKIE;
+ break;
+ case "logged_in":
+ $cookie_name = LOGGED_IN_COOKIE;
+ break;
+ default:
+ if ( is_ssl() ) {
+ $cookie_name = SECURE_AUTH_COOKIE;
+ $scheme = 'secure_auth';
+ } else {
+ $cookie_name = AUTH_COOKIE;
+ $scheme = 'auth';
+ }
+ }
+
+ if ( empty($_COOKIE[$cookie_name]) )
+ return false;
+ $cookie = $_COOKIE[$cookie_name];
+ }
+
+ $cookie_elements = explode('|', $cookie);
+ if ( count($cookie_elements) != 3 )
+ return false;
+
+ list($username, $expiration, $hmac) = $cookie_elements;
+
+ return compact('username', 'expiration', 'hmac', 'scheme');
+}
+endif;
+
+if ( !function_exists('wp_set_auth_cookie') ) :
+/**
+ * Sets the authentication cookies based User ID.
+ *
+ * The $remember parameter increases the time that the cookie will be kept. The
+ * default the cookie is kept without remembering is two days. When $remember is
+ * set, the cookies will be kept for 14 days or two weeks.
+ *
+ * @since 2.5
+ *
+ * @param int $user_id User ID
+ * @param bool $remember Whether to remember the user or not
+ */
+function wp_set_auth_cookie($user_id, $remember = false, $secure = '') {
+ if ( $remember ) {
+ $expiration = $expire = time() + 1209600;
+ } else {
+ $expiration = time() + 172800;
+ $expire = 0;
+ }
+
+ if ( '' === $secure )
+ $secure = is_ssl() ? true : false;
+
+ if ( $secure ) {
+ $auth_cookie_name = SECURE_AUTH_COOKIE;
+ $scheme = 'secure_auth';
+ } else {
+ $auth_cookie_name = AUTH_COOKIE;
+ $scheme = 'auth';
+ }
+
+ $auth_cookie = wp_generate_auth_cookie($user_id, $expiration, $scheme);
+ $logged_in_cookie = wp_generate_auth_cookie($user_id, $expiration, 'logged_in');
+
+ do_action('set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme);
+ do_action('set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in');
+
+ // Set httponly if the php version is >= 5.2.0
+ if ( version_compare(phpversion(), '5.2.0', 'ge') ) {
+ setcookie($auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
+ setcookie($auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
+ setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, false, true);
+ if ( COOKIEPATH != SITECOOKIEPATH )
+ setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, false, true);
+ } else {
+ $cookie_domain = COOKIE_DOMAIN;
+ if ( !empty($cookie_domain) )
+ $cookie_domain .= '; HttpOnly';
+ setcookie($auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, $cookie_domain, $secure);
+ setcookie($auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, $cookie_domain, $secure);
+ setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, $cookie_domain);
+ if ( COOKIEPATH != SITECOOKIEPATH )
+ setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, SITECOOKIEPATH, $cookie_domain);
+ }
+}
+endif;
+
+if ( !function_exists('wp_clear_auth_cookie') ) :
+/**
+ * Removes all of the cookies associated with authentication.
+ *
+ * @since 2.5
+ */
+function wp_clear_auth_cookie() {
+ do_action('clear_auth_cookie');
+
+ setcookie(AUTH_COOKIE, ' ', time() - 31536000, ADMIN_COOKIE_PATH, COOKIE_DOMAIN);
+ setcookie(SECURE_AUTH_COOKIE, ' ', time() - 31536000, ADMIN_COOKIE_PATH, COOKIE_DOMAIN);
+ setcookie(AUTH_COOKIE, ' ', time() - 31536000, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN);
+ setcookie(SECURE_AUTH_COOKIE, ' ', time() - 31536000, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN);
+ setcookie(LOGGED_IN_COOKIE, ' ', time() - 31536000, COOKIEPATH, COOKIE_DOMAIN);
+ setcookie(LOGGED_IN_COOKIE, ' ', time() - 31536000, SITECOOKIEPATH, COOKIE_DOMAIN);
+
+ // Old cookies
+ setcookie(AUTH_COOKIE, ' ', time() - 31536000, COOKIEPATH, COOKIE_DOMAIN);
+ setcookie(AUTH_COOKIE, ' ', time() - 31536000, SITECOOKIEPATH, COOKIE_DOMAIN);
+ setcookie(SECURE_AUTH_COOKIE, ' ', time() - 31536000, COOKIEPATH, COOKIE_DOMAIN);
+ setcookie(SECURE_AUTH_COOKIE, ' ', time() - 31536000, SITECOOKIEPATH, COOKIE_DOMAIN);
+
+ // Even older cookies
+ setcookie(USER_COOKIE, ' ', time() - 31536000, COOKIEPATH, COOKIE_DOMAIN);
+ setcookie(PASS_COOKIE, ' ', time() - 31536000, COOKIEPATH, COOKIE_DOMAIN);
+ setcookie(USER_COOKIE, ' ', time() - 31536000, SITECOOKIEPATH, COOKIE_DOMAIN);
+ setcookie(PASS_COOKIE, ' ', time() - 31536000, SITECOOKIEPATH, COOKIE_DOMAIN);
+}
+endif;
+
+if ( !function_exists('is_user_logged_in') ) :
+/**
+ * Checks if the current visitor is a logged in user.
+ *
+ * @since 2.0.0
+ *
+ * @return bool True if user is logged in, false if not logged in.
+ */
+function is_user_logged_in() {
+ $user = wp_get_current_user();
+
+ if ( $user->id == 0 )
+ return false;
+
+ return true;
+}
+endif;
+
+if ( !function_exists('auth_redirect') ) :
+/**
+ * Checks if a user is logged in, if not it redirects them to the login page.
+ *
+ * @since 1.5
+ */
+function auth_redirect() {
+ // Checks if a user is logged in, if not redirects them to the login page
+
+ if ( is_ssl() || force_ssl_admin() )
+ $secure = true;
+ else
+ $secure = false;
+
+ // If https is required and request is http, redirect
+ if ( $secure && !is_ssl() && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
+ if ( 0 === strpos($_SERVER['REQUEST_URI'], 'http') ) {
+ wp_redirect(preg_replace('|^http://|', 'https://', $_SERVER['REQUEST_URI']));
+ exit();
+ } else {
+ wp_redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
+ exit();
+ }
+ }
+
+ if ( $user_id = wp_validate_auth_cookie() ) {
+ // If the user wants ssl but the session is not ssl, redirect.
+ if ( !$secure && get_user_option('use_ssl', $user_id) && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
+ if ( 0 === strpos($_SERVER['REQUEST_URI'], 'http') ) {
+ wp_redirect(preg_replace('|^http://|', 'https://', $_SERVER['REQUEST_URI']));
+ exit();
+ } else {
+ wp_redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
+ exit();
+ }
+ }
+
+ return; // The cookie is good so we're done
+ }
+
+ // The cookie is no good so force login
+ nocache_headers();
+
+ if ( is_ssl() )
+ $proto = 'https://';
+ else
+ $proto = 'http://';
+
+ $redirect = ( strpos($_SERVER['REQUEST_URI'], '/options.php') && wp_get_referer() ) ? wp_get_referer() : $proto . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+
+ $login_url = site_url( 'wp-login.php?redirect_to=' . urlencode( $redirect ), 'login' );
+
+ wp_redirect($login_url);
+ exit();
+}
+endif;
+
+if ( !function_exists('check_admin_referer') ) :
+/**
+ * Makes sure that a user was referred from another admin page.
+ *
+ * To avoid security exploits.
+ *
+ * @since 1.2.0
+ * @uses do_action() Calls 'check_admin_referer' on $action.
+ *
+ * @param string $action Action nonce
+ * @param string $query_arg where to look for nonce in $_REQUEST (since 2.5)
+ */
+function check_admin_referer($action = -1, $query_arg = '_wpnonce') {
+ $adminurl = strtolower(admin_url());
+ $referer = strtolower(wp_get_referer());
+ $result = isset($_REQUEST[$query_arg]) ? wp_verify_nonce($_REQUEST[$query_arg], $action) : false;
+ if ( !$result && !(-1 == $action && strpos($referer, $adminurl) !== false) ) {
+ wp_nonce_ays($action);
+ die();
+ }
+ do_action('check_admin_referer', $action, $result);
+ return $result;
+}endif;
+
+if ( !function_exists('check_ajax_referer') ) :
+/**
+ * Verifies the AJAX request to prevent processing requests external of the blog.
+ *
+ * @since 2.0.4
+ *
+ * @param string $action Action nonce
+ * @param string $query_arg where to look for nonce in $_REQUEST (since 2.5)
+ */
+function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
+ if ( $query_arg )
+ $nonce = $_REQUEST[$query_arg];
+ else
+ $nonce = $_REQUEST['_ajax_nonce'] ? $_REQUEST['_ajax_nonce'] : $_REQUEST['_wpnonce'];
+
+ $result = wp_verify_nonce( $nonce, $action );
+
+ if ( $die && false == $result )
+ die('-1');
+
+ do_action('check_ajax_referer', $action, $result);
+
+ return $result;
+}
+endif;
+
+if ( !function_exists('wp_redirect') ) :
+/**
+ * Redirects to another page, with a workaround for the IIS Set-Cookie bug.
+ *
+ * @link http://support.microsoft.com/kb/q176113/
+ * @since 1.5.1
+ * @uses apply_filters() Calls 'wp_redirect' hook on $location and $status.
+ *
+ * @param string $location The path to redirect to
+ * @param int $status Status code to use
+ * @return bool False if $location is not set
+ */
+function wp_redirect($location, $status = 301) {
+ global $is_IIS;
+
+ $location = apply_filters('wp_redirect', $location, $status);
+ $status = apply_filters('wp_redirect_status', $status, $location);
+
+ if ( !$location ) // allows the wp_redirect filter to cancel a redirect
+ return false;
+
+ $location = wp_sanitize_redirect($location);
+
+ if ( $is_IIS ) {
+ header("Refresh: 0;url=$location");
+ } else {
+ if ( php_sapi_name() != 'cgi-fcgi' )
+ status_header($status); // This causes problems on IIS and some FastCGI setups
+ header("Location: $location");
+ }
+}
+endif;
+
+if ( !function_exists('wp_sanitize_redirect') ) :
+/**
+ * Sanitizes a URL for use in a redirect.
+ *
+ * @since 2.3
+ *
+ * @return string redirect-sanitized URL
+ **/
+function wp_sanitize_redirect($location) {
+ $location = preg_replace('|[^a-z0-9-~+_.?#=&;,/:%]|i', '', $location);
+ $location = wp_kses_no_null($location);
+
+ // remove %0d and %0a from location
+ $strip = array('%0d', '%0a');
+ $found = true;
+ while($found) {
+ $found = false;
+ foreach( (array) $strip as $val ) {
+ while(strpos($location, $val) !== false) {
+ $found = true;
+ $location = str_replace($val, '', $location);
+ }
+ }
+ }
+ return $location;
+}
+endif;
+
+if ( !function_exists('wp_safe_redirect') ) :
+/**
+ * Performs a safe (local) redirect, using wp_redirect().
+ *
+ * Checks whether the $location is using an allowed host, if it has an absolute
+ * path. A plugin can therefore set or remove allowed host(s) to or from the
+ * list.
+ *
+ * If the host is not allowed, then the redirect is to wp-admin on the siteurl
+ * instead. This prevents malicious redirects which redirect to another host,
+ * but only used in a few places.
+ *
+ * @since 2.3
+ * @uses apply_filters() Calls 'allowed_redirect_hosts' on an array containing
+ * WordPress host string and $location host string.
+ *
+ * @return void Does not return anything
+ **/
+function wp_safe_redirect($location, $status = 301) {
+
+ // Need to look at the URL the way it will end up in wp_redirect()
+ $location = wp_sanitize_redirect($location);
+
+ // browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'
+ if ( substr($location, 0, 2) == '//' )
+ $location = 'http:' . $location;
+
+ // In php 5 parse_url may fail if the URL query part contains http://, bug #38143
+ $test = ( $cut = strpos($location, '?') ) ? substr( $location, 0, $cut ) : $location;
+
+ $lp = parse_url($test);
+ $wpp = parse_url(get_option('home'));
+
+ $allowed_hosts = (array) apply_filters('allowed_redirect_hosts', array($wpp['host']), isset($lp['host']) ? $lp['host'] : '');
+
+ if ( isset($lp['host']) && ( !in_array($lp['host'], $allowed_hosts) && $lp['host'] != strtolower($wpp['host'])) )
+ $location = admin_url();
+
+ wp_redirect($location, $status);
+}
+endif;
+
+if ( ! function_exists('wp_notify_postauthor') ) :
+/**
+ * Notify an author of a comment/trackback/pingback to one of their posts.
+ *
+ * @since 1.0.0
+ *
+ * @param int $comment_id Comment ID
+ * @param string $comment_type Optional. The comment type either 'comment' (default), 'trackback', or 'pingback'
+ * @return bool False if user email does not exist. True on completion.
+ */
+function wp_notify_postauthor($comment_id, $comment_type='') {
+ $comment = get_comment($comment_id);
+ $post = get_post($comment->comment_post_ID);
+ $user = get_userdata( $post->post_author );
+
+ if ('' == $user->user_email) return false; // If there's no email to send the comment to
+
+ $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
+
+ $blogname = get_option('blogname');
+
+ if ( empty( $comment_type ) ) $comment_type = 'comment';
+
+ if ('comment' == $comment_type) {
+ $notify_message = sprintf( __('New comment on your post #%1$s "%2$s"'), $comment->comment_post_ID, $post->post_title ) . "\r\n";
+ $notify_message .= sprintf( __('Author : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('E-mail : %s'), $comment->comment_author_email ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= sprintf( __('Whois : http://ws.arin.net/cgi-bin/whois.pl?queryinput=%s'), $comment->comment_author_IP ) . "\r\n";
+ $notify_message .= __('Comment: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ $notify_message .= __('You can see all comments on this post here: ') . "\r\n";
+ $subject = sprintf( __('[%1$s] Comment: "%2$s"'), $blogname, $post->post_title );
+ } elseif ('trackback' == $comment_type) {
+ $notify_message = sprintf( __('New trackback on your post #%1$s "%2$s"'), $comment->comment_post_ID, $post->post_title ) . "\r\n";
+ $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ $notify_message .= __('You can see all trackbacks on this post here: ') . "\r\n";
+ $subject = sprintf( __('[%1$s] Trackback: "%2$s"'), $blogname, $post->post_title );
+ } elseif ('pingback' == $comment_type) {
+ $notify_message = sprintf( __('New pingback on your post #%1$s "%2$s"'), $comment->comment_post_ID, $post->post_title ) . "\r\n";
+ $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Excerpt: ') . "\r\n" . sprintf('[...] %s [...]', $comment->comment_content ) . "\r\n\r\n";
+ $notify_message .= __('You can see all pingbacks on this post here: ') . "\r\n";
+ $subject = sprintf( __('[%1$s] Pingback: "%2$s"'), $blogname, $post->post_title );
+ }
+ $notify_message .= get_permalink($comment->comment_post_ID) . "#comments\r\n\r\n";
+ $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=cdc&c=$comment_id") ) . "\r\n";
+ $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=cdc&dt=spam&c=$comment_id") ) . "\r\n";
+
+ $wp_email = 'wordpress@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
+
+ if ( '' == $comment->comment_author ) {
+ $from = "From: \"$blogname\" <$wp_email>";
+ if ( '' != $comment->comment_author_email )
+ $reply_to = "Reply-To: $comment->comment_author_email";
+ } else {
+ $from = "From: \"$comment->comment_author\" <$wp_email>";
+ if ( '' != $comment->comment_author_email )
+ $reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
+ }
+
+ $message_headers = "$from\n"
+ . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
+
+ if ( isset($reply_to) )
+ $message_headers .= $reply_to . "\n";
+
+ $notify_message = apply_filters('comment_notification_text', $notify_message, $comment_id);
+ $subject = apply_filters('comment_notification_subject', $subject, $comment_id);
+ $message_headers = apply_filters('comment_notification_headers', $message_headers, $comment_id);
+
+ @wp_mail($user->user_email, $subject, $notify_message, $message_headers);
+
+ return true;
+}
+endif;
+
+if ( !function_exists('wp_notify_moderator') ) :
+/**
+ * Notifies the moderator of the blog about a new comment that is awaiting approval.
+ *
+ * @since 1.0
+ * @uses $wpdb
+ *
+ * @param int $comment_id Comment ID
+ * @return bool Always returns true
+ */
+function wp_notify_moderator($comment_id) {
+ global $wpdb;
+
+ if( get_option( "moderation_notify" ) == 0 )
+ return true;
+
+ $comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_ID=%d LIMIT 1", $comment_id));
+ $post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID=%d LIMIT 1", $comment->comment_post_ID));
+
+ $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
+ $comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
+
+ switch ($comment->comment_type)
+ {
+ case 'trackback':
+ $notify_message = sprintf( __('A new trackback on the post #%1$s "%2$s" is waiting for your approval'), $post->ID, $post->post_title ) . "\r\n";
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
+ $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Trackback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ break;
+ case 'pingback':
+ $notify_message = sprintf( __('A new pingback on the post #%1$s "%2$s" is waiting for your approval'), $post->ID, $post->post_title ) . "\r\n";
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
+ $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Pingback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ break;
+ default: //Comments
+ $notify_message = sprintf( __('A new comment on the post #%1$s "%2$s" is waiting for your approval'), $post->ID, $post->post_title ) . "\r\n";
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
+ $notify_message .= sprintf( __('Author : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('E-mail : %s'), $comment->comment_author_email ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= sprintf( __('Whois : http://ws.arin.net/cgi-bin/whois.pl?queryinput=%s'), $comment->comment_author_IP ) . "\r\n";
+ $notify_message .= __('Comment: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ break;
+ }
+
+ $notify_message .= sprintf( __('Approve it: %s'), admin_url("comment.php?action=mac&c=$comment_id") ) . "\r\n";
+ $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=cdc&c=$comment_id") ) . "\r\n";
+ $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=cdc&dt=spam&c=$comment_id") ) . "\r\n";
+
+ $notify_message .= sprintf( __ngettext('Currently %s comment is waiting for approval. Please visit the moderation panel:',
+ 'Currently %s comments are waiting for approval. Please visit the moderation panel:', $comments_waiting), number_format_i18n($comments_waiting) ) . "\r\n";
+ $notify_message .= admin_url("edit-comments.php?comment_status=moderated") . "\r\n";
+
+ $subject = sprintf( __('[%1$s] Please moderate: "%2$s"'), get_option('blogname'), $post->post_title );
+ $admin_email = get_option('admin_email');
+
+ $notify_message = apply_filters('comment_moderation_text', $notify_message, $comment_id);
+ $subject = apply_filters('comment_moderation_subject', $subject, $comment_id);
+
+ @wp_mail($admin_email, $subject, $notify_message);
+
+ return true;
+}
+endif;
+
+if ( !function_exists('wp_password_change_notification') ) :
+/**
+ * Notify the blog admin of a user changing password, normally via email.
+ *
+ * @since 2.7
+ *
+ * @param object $user User Object
+ */
+function wp_password_change_notification(&$user) {
+ // send a copy of password change notification to the admin
+ // but check to see if it's the admin whose password we're changing, and skip this
+ if ( $user->user_email != get_option('admin_email') ) {
+ $message = sprintf(__('Password Lost and Changed for user: %s'), $user->user_login) . "\r\n";
+ wp_mail(get_option('admin_email'), sprintf(__('[%s] Password Lost/Changed'), get_option('blogname')), $message);
+ }
+}
+endif;
+
+if ( !function_exists('wp_new_user_notification') ) :
+/**
+ * Notify the blog admin of a new user, normally via email.
+ *
+ * @since 2.0
+ *
+ * @param int $user_id User ID
+ * @param string $plaintext_pass Optional. The user's plaintext password
+ */
+function wp_new_user_notification($user_id, $plaintext_pass = '') {
+ $user = new WP_User($user_id);
+
+ $user_login = stripslashes($user->user_login);
+ $user_email = stripslashes($user->user_email);
+
+ $message = sprintf(__('New user registration on your blog %s:'), get_option('blogname')) . "\r\n\r\n";
+ $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
+ $message .= sprintf(__('E-mail: %s'), $user_email) . "\r\n";
+
+ @wp_mail(get_option('admin_email'), sprintf(__('[%s] New User Registration'), get_option('blogname')), $message);
+
+ if ( empty($plaintext_pass) )
+ return;
+
+ $message = sprintf(__('Username: %s'), $user_login) . "\r\n";
+ $message .= sprintf(__('Password: %s'), $plaintext_pass) . "\r\n";
+ $message .= site_url("wp-login.php", 'login') . "\r\n";
+
+ wp_mail($user_email, sprintf(__('[%s] Your username and password'), get_option('blogname')), $message);
+
+}
+endif;
+
+if ( !function_exists('wp_nonce_tick') ) :
+/**
+ * Get the time-dependent variable for nonce creation.
+ *
+ * A nonce has a lifespan of two ticks. Nonces in their second tick may be
+ * updated, e.g. by autosave.
+ *
+ * @since 2.5
+ *
+ * @return int
+ */
+function wp_nonce_tick() {
+ $nonce_life = apply_filters('nonce_life', 86400);
+
+ return ceil(time() / ( $nonce_life / 2 ));
+}
+endif;
+
+if ( !function_exists('wp_verify_nonce') ) :
+/**
+ * Verify that correct nonce was used with time limit.
+ *
+ * The user is given an amount of time to use the token, so therefore, since the
+ * UID and $action remain the same, the independent variable is the time.
+ *
+ * @since 2.0.4
+ *
+ * @param string $nonce Nonce that was used in the form to verify
+ * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
+ * @return bool Whether the nonce check passed or failed.
+ */
+function wp_verify_nonce($nonce, $action = -1) {
+ $user = wp_get_current_user();
+ $uid = (int) $user->id;
+
+ $i = wp_nonce_tick();
+
+ // Nonce generated 0-12 hours ago
+ if ( substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10) == $nonce )
+ return 1;
+ // Nonce generated 12-24 hours ago
+ if ( substr(wp_hash(($i - 1) . $action . $uid, 'nonce'), -12, 10) == $nonce )
+ return 2;
+ // Invalid nonce
+ return false;
+}
+endif;
+
+if ( !function_exists('wp_create_nonce') ) :
+/**
+ * Creates a random, one time use token.
+ *
+ * @since 2.0.4
+ *
+ * @param string|int $action Scalar value to add context to the nonce.
+ * @return string The one use form token
+ */
+function wp_create_nonce($action = -1) {
+ $user = wp_get_current_user();
+ $uid = (int) $user->id;
+
+ $i = wp_nonce_tick();
+
+ return substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10);
+}
+endif;
+
+if ( !function_exists('wp_salt') ) :
+/**
+ * Get salt to add to hashes to help prevent attacks.
+ *
+ * The secret key is located in two places: the database in case the secret key
+ * isn't defined in the second place, which is in the wp-config.php file. If you
+ * are going to set the secret key, then you must do so in the wp-config.php
+ * file.
+ *
+ * The secret key in the database is randomly generated and will be appended to
+ * the secret key that is in wp-config.php file in some instances. It is
+ * important to have the secret key defined or changed in wp-config.php.
+ *
+ * If you have installed WordPress 2.5 or later, then you will have the
+ * SECRET_KEY defined in the wp-config.php already. You will want to change the
+ * value in it because hackers will know what it is. If you have upgraded to
+ * WordPress 2.5 or later version from a version before WordPress 2.5, then you
+ * should add the constant to your wp-config.php file.
+ *
+ * Below is an example of how the SECRET_KEY constant is defined with a value.
+ * You must not copy the below example and paste into your wp-config.php. If you
+ * need an example, then you can have a
+ * {@link http://api.wordpress.org/secret-key/1.0/ secret key created} for you.
+ *
+ *
+ * define('SECRET_KEY', 'mAry1HadA15|\/|b17w55w1t3asSn09w');
+ *
+ *
+ * Salting passwords helps against tools which has stored hashed values of
+ * common dictionary strings. The added values makes it harder to crack if given
+ * salt string is not weak.
+ *
+ * @since 2.5
+ * @link http://api.wordpress.org/secret-key/1.0/ Create a Secret Key for wp-config.php
+ *
+ * @return string Salt value from either 'SECRET_KEY' or 'secret' option
+ */
+function wp_salt($scheme = 'auth') {
+ global $wp_default_secret_key;
+ $secret_key = '';
+ if ( defined('SECRET_KEY') && ('' != SECRET_KEY) && ( $wp_default_secret_key != SECRET_KEY) )
+ $secret_key = SECRET_KEY;
+
+ if ( 'auth' == $scheme ) {
+ if ( defined('AUTH_KEY') && ('' != AUTH_KEY) && ( $wp_default_secret_key != AUTH_KEY) )
+ $secret_key = AUTH_KEY;
+
+ if ( defined('AUTH_SALT') ) {
+ $salt = AUTH_SALT;
+ } elseif ( defined('SECRET_SALT') ) {
+ $salt = SECRET_SALT;
+ } else {
+ $salt = get_option('auth_salt');
+ if ( empty($salt) ) {
+ $salt = wp_generate_password();
+ update_option('auth_salt', $salt);
+ }
+ }
+ } elseif ( 'secure_auth' == $scheme ) {
+ if ( defined('SECURE_AUTH_KEY') && ('' != SECURE_AUTH_KEY) && ( $wp_default_secret_key != SECURE_AUTH_KEY) )
+ $secret_key = SECURE_AUTH_KEY;
+
+ if ( defined('SECURE_AUTH_SALT') ) {
+ $salt = SECRET_AUTH_SALT;
+ } else {
+ $salt = get_option('secure_auth_salt');
+ if ( empty($salt) ) {
+ $salt = wp_generate_password();
+ update_option('secure_auth_salt', $salt);
+ }
+ }
+ } elseif ( 'logged_in' == $scheme ) {
+ if ( defined('LOGGED_IN_KEY') && ('' != LOGGED_IN_KEY) && ( $wp_default_secret_key != LOGGED_IN_KEY) )
+ $secret_key = LOGGED_IN_KEY;
+
+ if ( defined('LOGGED_IN_SALT') ) {
+ $salt = LOGGED_IN_SALT;
+ } else {
+ $salt = get_option('logged_in_salt');
+ if ( empty($salt) ) {
+ $salt = wp_generate_password();
+ update_option('logged_in_salt', $salt);
+ }
+ }
+ } elseif ( 'nonce' == $scheme ) {
+ if ( defined('NONCE_KEY') && ('' != NONCE_KEY) && ( $wp_default_secret_key != NONCE_KEY) )
+ $secret_key = NONCE_KEY;
+
+ if ( defined('NONCE_SALT') ) {
+ $salt = NONCE_SALT;
+ } else {
+ $salt = get_option('nonce_salt');
+ if ( empty($salt) ) {
+ $salt = wp_generate_password();
+ update_option('nonce_salt', $salt);
+ }
+ }
+ } else {
+ // ensure each auth scheme has its own unique salt
+ $salt = hash_hmac('md5', $scheme, $secret_key);
+ }
+
+ return apply_filters('salt', $secret_key . $salt, $scheme);
+}
+endif;
+
+if ( !function_exists('wp_hash') ) :
+/**
+ * Get hash of given string.
+ *
+ * @since 2.0.4
+ * @uses wp_salt() Get WordPress salt
+ *
+ * @param string $data Plain text to hash
+ * @return string Hash of $data
+ */
+function wp_hash($data, $scheme = 'auth') {
+ $salt = wp_salt($scheme);
+
+ return hash_hmac('md5', $data, $salt);
+}
+endif;
+
+if ( !function_exists('wp_hash_password') ) :
+/**
+ * Create a hash (encrypt) of a plain text password.
+ *
+ * For integration with other applications, this function can be overwritten to
+ * instead use the other package password checking algorithm.
+ *
+ * @since 2.5
+ * @global object $wp_hasher PHPass object
+ * @uses PasswordHash::HashPassword
+ *
+ * @param string $password Plain text user password to hash
+ * @return string The hash string of the password
+ */
+function wp_hash_password($password) {
+ global $wp_hasher;
+
+ if ( empty($wp_hasher) ) {
+ require_once( ABSPATH . 'wp-includes/class-phpass.php');
+ // By default, use the portable hash from phpass
+ $wp_hasher = new PasswordHash(8, TRUE);
+ }
+
+ return $wp_hasher->HashPassword($password);
+}
+endif;
+
+if ( !function_exists('wp_check_password') ) :
+/**
+ * Checks the plaintext password against the encrypted Password.
+ *
+ * Maintains compatibility between old version and the new cookie authentication
+ * protocol using PHPass library. The $hash parameter is the encrypted password
+ * and the function compares the plain text password when encypted similarly
+ * against the already encrypted password to see if they match.
+ *
+ * For integration with other applications, this function can be overwritten to
+ * instead use the other package password checking algorithm.
+ *
+ * @since 2.5
+ * @global object $wp_hasher PHPass object used for checking the password
+ * against the $hash + $password
+ * @uses PasswordHash::CheckPassword
+ *
+ * @param string $password Plaintext user's password
+ * @param string $hash Hash of the user's password to check against.
+ * @return bool False, if the $password does not match the hashed password
+ */
+function wp_check_password($password, $hash, $user_id = '') {
+ global $wp_hasher;
+
+ // If the hash is still md5...
+ if ( strlen($hash) <= 32 ) {
+ $check = ( $hash == md5($password) );
+ if ( $check && $user_id ) {
+ // Rehash using new hash.
+ wp_set_password($password, $user_id);
+ $hash = wp_hash_password($password);
+ }
+
+ return apply_filters('check_password', $check, $password, $hash, $user_id);
+ }
+
+ // If the stored hash is longer than an MD5, presume the
+ // new style phpass portable hash.
+ if ( empty($wp_hasher) ) {
+ require_once( ABSPATH . 'wp-includes/class-phpass.php');
+ // By default, use the portable hash from phpass
+ $wp_hasher = new PasswordHash(8, TRUE);
+ }
+
+ $check = $wp_hasher->CheckPassword($password, $hash);
+
+ return apply_filters('check_password', $check, $password, $hash, $user_id);
+}
+endif;
+
+if ( !function_exists('wp_generate_password') ) :
+/**
+ * Generates a random password drawn from the defined set of characters.
+ *
+ * @since 2.5
+ *
+ * @return string The random password
+ **/
+function wp_generate_password($length = 12, $special_chars = true) {
+ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ if ( $special_chars )
+ $chars .= '!@#$%^&*()';
+
+ $password = '';
+ for ( $i = 0; $i < $length; $i++ )
+ $password .= substr($chars, wp_rand(0, strlen($chars) - 1), 1);
+ return $password;
+}
+endif;
+
+if ( !function_exists('wp_rand') ) :
+ /**
+ * Generates a random number
+ *
+ * @since 2.6.2
+ *
+ * @param int $min Lower limit for the generated number (optional, default is 0)
+ * @param int $max Upper limit for the generated number (optional, default is 4294967295)
+ * @return int A random number between min and max
+ */
+function wp_rand( $min = 0, $max = 0 ) {
+ global $rnd_value;
+
+ $seed = get_option('random_seed');
+
+ // Reset $rnd_value after 14 uses
+ // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
+ if ( strlen($rnd_value) < 8 ) {
+ $rnd_value = md5( uniqid(microtime() . mt_rand(), true ) . $seed );
+ $rnd_value .= sha1($rnd_value);
+ $rnd_value .= sha1($rnd_value . $seed);
+ $seed = md5($seed . $rnd_value);
+ update_option('random_seed', $seed);
+ }
+
+ // Take the first 8 digits for our value
+ $value = substr($rnd_value, 0, 8);
+
+ // Strip the first eight, leaving the remainder for the next call to wp_rand().
+ $rnd_value = substr($rnd_value, 8);
+
+ $value = abs(hexdec($value));
+
+ // Reduce the value to be within the min - max range
+ // 4294967295 = 0xffffffff = max random number
+ if ( $max != 0 )
+ $value = $min + (($max - $min + 1) * ($value / (4294967295 + 1)));
+
+ return abs(intval($value));
+}
+endif;
+
+if ( !function_exists('wp_set_password') ) :
+/**
+ * Updates the user's password with a new encrypted one.
+ *
+ * For integration with other applications, this function can be overwritten to
+ * instead use the other package password checking algorithm.
+ *
+ * @since 2.5
+ * @uses $wpdb WordPress database object for queries
+ * @uses wp_hash_password() Used to encrypt the user's password before passing to the database
+ *
+ * @param string $password The plaintext new user password
+ * @param int $user_id User ID
+ */
+function wp_set_password( $password, $user_id ) {
+ global $wpdb;
+
+ $hash = wp_hash_password($password);
+ $query = $wpdb->prepare("UPDATE $wpdb->users SET user_pass = %s, user_activation_key = '' WHERE ID = %d", $hash, $user_id);
+ $wpdb->query($query);
+ wp_cache_delete($user_id, 'users');
+}
+endif;
+
+if ( !function_exists( 'get_avatar' ) ) :
+/**
+ * Retrieve the avatar for a user who provided a user ID or email address.
+ *
+ * @since 2.5
+ * @param int|string|object $id_or_email A user ID, email address, or comment object
+ * @param int $size Size of the avatar image
+ * @param string $default URL to a default image to use if no avatar is available
+ * @param string $alt Alternate text to use in image tag. Defaults to blank
+ * @return string tag for the user's avatar
+*/
+function get_avatar( $id_or_email, $size = '96', $default = '', $alt = false ) {
+ if ( ! get_option('show_avatars') )
+ return false;
+
+ if ( false === $alt)
+ $safe_alt = '';
+ else
+ $safe_alt = attribute_escape( $alt );
+
+ if ( !is_numeric($size) )
+ $size = '96';
+
+ $email = '';
+ $url = '';
+ if ( is_numeric($id_or_email) ) {
+ $id = (int) $id_or_email;
+ $user = get_userdata($id);
+ if ( $user ) {
+ $email = $user->user_email;
+ $url = $user->user_url;
+ }
+ } elseif ( is_object($id_or_email) ) {
+ if ( isset($id_or_email->comment_type) && '' != $id_or_email->comment_type && 'comment' != $id_or_email->comment_type )
+ return false; // No avatar for pingbacks or trackbacks
+
+ if ( !empty($id_or_email->user_id) ) {
+ $id = (int) $id_or_email->user_id;
+ $user = get_userdata($id);
+ if ( $user) {
+ $email = $user->user_email;
+ $url = $user->user_url;
+ }
+ } else {
+ if (!empty($id_or_email->comment_author_email)) {
+ $email = $id_or_email->comment_author_email;
+ }
+ if (!empty($id_or_email->comment_author_url)) {
+ $url = $id_or_email->comment_author_url;
+ }
+ }
+ } else {
+ $email = $id_or_email;
+ }
+
+ if ( empty($default) ) {
+ $avatar_default = get_option('avatar_default');
+ if ( empty($avatar_default) )
+ $default = 'mystery';
+ else
+ $default = $avatar_default;
+ }
+
+ if ( 'mystery' == $default )
+ $default = "http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s={$size}"; // ad516503a11cd5ca435acc9bb6523536 == md5('unknown@gravatar.com')
+ elseif ( 'blank' == $default )
+ $default = includes_url('images/blank.gif');
+ elseif ( !empty($email) && 'gravatar_default' == $default )
+ $default = '';
+ elseif ( 'gravatar_default' == $default )
+ $default = "http://www.gravatar.com/avatar/s={$size}";
+ elseif ('fromurl' == $default)
+ $default = get_bloginfo('wpurl') . '/default_avatar.png';
+ elseif ( empty($email) )
+ $default = "http://www.gravatar.com/avatar/?d=$default&s={$size}";
+ elseif ( strpos($default, 'http://') === 0 )
+ $default = add_query_arg( 's', $size, $default );
+
+ if ( !empty($email) && empty($url)) {
+ $out = 'http://www.gravatar.com/avatar/';
+ $out .= md5( strtolower( $email ) );
+ $out .= '?s='.$size;
+ $out .= '&d=' . urlencode( $default );
+
+ $rating = get_option('avatar_rating');
+ if ( !empty( $rating ) )
+ $out .= "&r={$rating}";
+
+ $avatar = " ";
+ } elseif (!empty($url)) {
+ $url_parsed = parse_url($url);
+ if ($url_parsed["host"] . $url_parsed["path"] > "") {
+ $out = "http://" . $url_parsed["host"] . $url_parsed["path"] . "/avatar.png";
+ } else {
+ $out = $default;
+ }
+ $avatar = " ";
+ } else {
+ $avatar = " ";
+ }
+
+ return apply_filters('get_avatar', $avatar, $id_or_email, $size, $default, $alt);
+}
+endif;
+
+if ( !function_exists('wp_setcookie') ) :
+/**
+ * Sets a cookie for a user who just logged in.
+ *
+ * @since 1.5
+ * @deprecated Use wp_set_auth_cookie()
+ * @see wp_set_auth_cookie()
+ *
+ * @param string $username The user's username
+ * @param string $password Optional. The user's password
+ * @param bool $already_md5 Optional. Whether the password has already been through MD5
+ * @param string $home Optional. Will be used instead of COOKIEPATH if set
+ * @param string $siteurl Optional. Will be used instead of SITECOOKIEPATH if set
+ * @param bool $remember Optional. Remember that the user is logged in
+ */
+function wp_setcookie($username, $password = '', $already_md5 = false, $home = '', $siteurl = '', $remember = false) {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_set_auth_cookie()' );
+ $user = get_userdatabylogin($username);
+ wp_set_auth_cookie($user->ID, $remember);
+}
+endif;
+
+if ( !function_exists('wp_clearcookie') ) :
+/**
+ * Clears the authentication cookie, logging the user out.
+ *
+ * @since 1.5
+ * @deprecated Use wp_clear_auth_cookie()
+ * @see wp_clear_auth_cookie()
+ */
+function wp_clearcookie() {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_clear_auth_cookie()' );
+ wp_clear_auth_cookie();
+}
+endif;
+
+if ( !function_exists('wp_get_cookie_login') ):
+/**
+ * Gets the user cookie login.
+ *
+ * This function is deprecated and should no longer be extended as it won't be
+ * used anywhere in WordPress. Also, plugins shouldn't use it either.
+ *
+ * @since 2.0.4
+ * @deprecated No alternative
+ *
+ * @return bool Always returns false
+ */
+function wp_get_cookie_login() {
+ _deprecated_function( __FUNCTION__, '2.5', '' );
+ return false;
+}
+endif;
+
+if ( !function_exists('wp_login') ) :
+/**
+ * Checks a users login information and logs them in if it checks out.
+ *
+ * Use the global $error to get the reason why the login failed. If the username
+ * is blank, no error will be set, so assume blank username on that case.
+ *
+ * Plugins extending this function should also provide the global $error and set
+ * what the error is, so that those checking the global for why there was a
+ * failure can utilize it later.
+ *
+ * @since 1.2.2
+ * @deprecated Use wp_signon()
+ * @global string $error Error when false is returned
+ *
+ * @param string $username User's username
+ * @param string $password User's password
+ * @param bool $deprecated Not used
+ * @return bool False on login failure, true on successful check
+ */
+function wp_login($username, $password, $deprecated = '') {
+ global $error;
+
+ $user = wp_authenticate($username, $password);
+
+ if ( ! is_wp_error($user) )
+ return true;
+
+ $error = $user->get_error_message();
+ return false;
+}
+endif;
+
+if ( !function_exists( 'wp_text_diff' ) ) :
+/**
+ * Displays a human readable HTML representation of the difference between two strings.
+ *
+ * The Diff is available for getting the changes between versions. The output is
+ * HTML, so the primary use is for displaying the changes. If the two strings
+ * are equivalent, then an empty string will be returned.
+ *
+ * The arguments supported and can be changed are listed below.
+ *
+ * 'title' : Default is an empty string. Titles the diff in a manner compatible
+ * with the output.
+ * 'title_left' : Default is an empty string. Change the HTML to the left of the
+ * title.
+ * 'title_right' : Default is an empty string. Change the HTML to the right of
+ * the title.
+ *
+ * @since 2.6
+ * @see wp_parse_args() Used to change defaults to user defined settings.
+ * @uses Text_Diff
+ * @uses WP_Text_Diff_Renderer_Table
+ *
+ * @param string $left_string "old" (left) version of string
+ * @param string $right_string "new" (right) version of string
+ * @param string|array $args Optional. Change 'title', 'title_left', and 'title_right' defaults.
+ * @return string Empty string if strings are equivalent or HTML with differences.
+ */
+function wp_text_diff( $left_string, $right_string, $args = null ) {
+ $defaults = array( 'title' => '', 'title_left' => '', 'title_right' => '' );
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( !class_exists( 'WP_Text_Diff_Renderer_Table' ) )
+ require( ABSPATH . WPINC . '/wp-diff.php' );
+
+ $left_string = normalize_whitespace($left_string);
+ $right_string = normalize_whitespace($right_string);
+
+ $left_lines = split("\n", $left_string);
+ $right_lines = split("\n", $right_string);
+
+ $text_diff = new Text_Diff($left_lines, $right_lines);
+ $renderer = new WP_Text_Diff_Renderer_Table();
+ $diff = $renderer->render($text_diff);
+
+ if ( !$diff )
+ return '';
+
+ $r = "\n";
+ $r .= "";
+
+ if ( $args['title'] || $args['title_left'] || $args['title_right'] )
+ $r .= "";
+ if ( $args['title'] )
+ $r .= "\n";
+ if ( $args['title_left'] || $args['title_right'] ) {
+ $r .= "\n";
+ $r .= "\t\n";
+ $r .= "\t\n";
+ $r .= "\n";
+ }
+ if ( $args['title'] || $args['title_left'] || $args['title_right'] )
+ $r .= "\n";
+
+ $r .= "\n$diff\n\n";
+ $r .= "$args[title] $args[title_left] $args[title_right]
";
+
+ return $r;
+}
+endif;
+
+?>
diff -uNr a/blog/wp-includes/plugin.php b/blog/wp-includes/plugin.php
--- a/blog/wp-includes/plugin.php false
+++ b/blog/wp-includes/plugin.php 1672261bfa090c73d934a42cdca93abf54b32bc8562c52d3b0227e3e4dfb19c536e08b6c8b60e003d1b596e7579ef0d097e443629f135e7b5c9847906c5269bb
@@ -0,0 +1,674 @@
+
+ * function example_hook($example) { echo $example; }
+ * add_filter('example_filter', 'example_hook');
+ *
+ *
+ * In WordPress 1.5.1+, hooked functions can take extra arguments that are set
+ * when the matching do_action() or apply_filters() call is run. The
+ * $accepted_args allow for calling functions only when the number of args
+ * match. Hooked functions can take extra arguments that are set when the
+ * matching do_action() or apply_filters() call is run. For example, the action
+ * comment_id_not_found will pass any functions that hook onto it the ID of the
+ * requested comment.
+ *
+ * Note: the function will return true no matter if the
+ * function was hooked fails or not. There are no checks for whether the
+ * function exists beforehand and no checks to whether the $function_to_add
+ * is even a string. It is up to you to take care and this is done for
+ * optimization purposes, so everything is as quick as possible.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 0.71
+ * @global array $wp_filter Stores all of the filters added in the form of
+ * wp_filter['tag']['array of priorities']['array of functions serialized']['array of ['array (functions, accepted_args)]']
+ * @global array $merged_filters Tracks the tags that need to be merged for later. If the hook is added, it doesn't need to run through that process.
+ *
+ * @param string $tag The name of the filter to hook the $function_to_add to.
+ * @param callback $function_to_add The name of the function to be called when the filter is applied.
+ * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
+ * @param int $accepted_args optional. The number of arguments the function accept (default 1).
+ * @return boolean true
+ */
+function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
+ global $wp_filter, $merged_filters;
+
+ $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
+ $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
+ unset( $merged_filters[ $tag ] );
+ return true;
+}
+
+/**
+ * Check if any filter has been registered for a hook.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ * @global array $wp_filter Stores all of the filters
+ *
+ * @param string $tag The name of the filter hook.
+ * @param callback $function_to_check optional. If specified, return the priority of that function on this hook or false if not attached.
+ * @return int|boolean Optionally returns the priority on that hook for the specified function.
+ */
+function has_filter($tag, $function_to_check = false) {
+ global $wp_filter;
+
+ $has = !empty($wp_filter[$tag]);
+ if ( false === $function_to_check || false == $has )
+ return $has;
+
+ if ( !$idx = _wp_filter_build_unique_id($tag, $function_to_check, false) )
+ return false;
+
+ foreach ( (array) array_keys($wp_filter[$tag]) as $priority ) {
+ if ( isset($wp_filter[$tag][$priority][$idx]) )
+ return $priority;
+ }
+
+ return false;
+}
+
+/**
+ * Call the functions added to a filter hook.
+ *
+ * The callback functions attached to filter hook $tag are invoked by calling
+ * this function. This function can be used to create a new filter hook by
+ * simply calling this function with the name of the new hook specified using
+ * the $tag parameter.
+ *
+ * The function allows for additional arguments to be added and passed to hooks.
+ *
+ * function example_hook($string, $arg1, $arg2)
+ * {
+ * //Do stuff
+ * return $string;
+ * }
+ * $value = apply_filters('example_filter', 'filter me', 'arg1', 'arg2');
+ *
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 0.71
+ * @global array $wp_filter Stores all of the filters
+ * @global array $merged_filters Merges the filter hooks using this function.
+ * @global array $wp_current_filter stores the list of current filters with the current one last
+ *
+ * @param string $tag The name of the filter hook.
+ * @param mixed $value The value on which the filters hooked to $tag are applied on.
+ * @param mixed $var,... Additional variables passed to the functions hooked to $tag .
+ * @return mixed The filtered value after all hooked functions are applied to it.
+ */
+function apply_filters($tag, $value) {
+ global $wp_filter, $merged_filters, $wp_current_filter;
+
+ $args = array();
+ $wp_current_filter[] = $tag;
+
+ // Do 'all' actions first
+ if ( isset($wp_filter['all']) ) {
+ $args = func_get_args();
+ _wp_call_all_hook($args);
+ }
+
+ if ( !isset($wp_filter[$tag]) ) {
+ array_pop($wp_current_filter);
+ return $value;
+ }
+
+ // Sort
+ if ( !isset( $merged_filters[ $tag ] ) ) {
+ ksort($wp_filter[$tag]);
+ $merged_filters[ $tag ] = true;
+ }
+
+ reset( $wp_filter[ $tag ] );
+
+ if ( empty($args) )
+ $args = func_get_args();
+
+ do {
+ foreach( (array) current($wp_filter[$tag]) as $the_ )
+ if ( !is_null($the_['function']) ){
+ $args[1] = $value;
+ $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
+ }
+
+ } while ( next($wp_filter[$tag]) !== false );
+
+ array_pop( $wp_current_filter );
+
+ return $value;
+}
+
+/**
+ * Removes a function from a specified filter hook.
+ *
+ * This function removes a function attached to a specified filter hook. This
+ * method can be used to remove default functions attached to a specific filter
+ * hook and possibly replace them with a substitute.
+ *
+ * To remove a hook, the $function_to_remove and $priority arguments must match
+ * when the hook was added. This goes for both filters and actions. No warning
+ * will be given on removal failure.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ *
+ * @param string $tag The filter hook to which the function to be removed is hooked.
+ * @param callback $function_to_remove The name of the function which should be removed.
+ * @param int $priority optional. The priority of the function (default: 10).
+ * @param int $accepted_args optional. The number of arguments the function accpets (default: 1).
+ * @return boolean Whether the function existed before it was removed.
+ */
+function remove_filter($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
+ $function_to_remove = _wp_filter_build_unique_id($tag, $function_to_remove, $priority);
+
+ $r = isset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
+
+ if ( true === $r) {
+ unset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
+ if ( empty($GLOBALS['wp_filter'][$tag][$priority]) )
+ unset($GLOBALS['wp_filter'][$tag][$priority]);
+ unset($GLOBALS['merged_filters'][$tag]);
+ }
+
+ return $r;
+}
+
+/**
+ * Remove all of the hooks from a filter.
+ *
+ * @since 2.7
+ *
+ * @param string $tag The filter to remove hooks from.
+ * @param int $priority The priority number to remove.
+ * @return bool True when finished.
+ */
+function remove_all_filters($tag, $priority = false) {
+ global $wp_filter, $merged_filters;
+
+ if( isset($wp_filter[$tag]) ) {
+ if( false !== $priority && isset($$wp_filter[$tag][$priority]) )
+ unset($wp_filter[$tag][$priority]);
+ else
+ unset($wp_filter[$tag]);
+ }
+
+ if( isset($merged_filters[$tag]) )
+ unset($merged_filters[$tag]);
+
+ return true;
+}
+
+/**
+ * Retrieve the name of the current filter or action.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ *
+ * @return string Hook name of the current filter or action.
+ */
+function current_filter() {
+ global $wp_current_filter;
+ return end( $wp_current_filter );
+}
+
+
+/**
+ * Hooks a function on to a specific action.
+ *
+ * Actions are the hooks that the WordPress core launches at specific points
+ * during execution, or when specific events occur. Plugins can specify that
+ * one or more of its PHP functions are executed at these points, using the
+ * Action API.
+ *
+ * @uses add_filter() Adds an action. Parameter list and functionality are the same.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ *
+ * @param string $tag The name of the action to which the $function_to_add is hooked.
+ * @param callback $function_to_add The name of the function you wish to be called.
+ * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
+ * @param int $accepted_args optional. The number of arguments the function accept (default 1).
+ */
+function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
+ return add_filter($tag, $function_to_add, $priority, $accepted_args);
+}
+
+
+/**
+ * Execute functions hooked on a specific action hook.
+ *
+ * This function invokes all functions attached to action hook $tag. It is
+ * possible to create new action hooks by simply calling this function,
+ * specifying the name of the new hook using the $tag parameter.
+ *
+ * You can pass extra arguments to the hooks, much like you can with
+ * apply_filters().
+ *
+ * @see apply_filters() This function works similar with the exception that
+ * nothing is returned and only the functions or methods are called.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ * @global array $wp_filter Stores all of the filters
+ * @global array $wp_actions Increments the amount of times action was triggered.
+ *
+ * @param string $tag The name of the action to be executed.
+ * @param mixed $arg,... Optional additional arguments which are passed on to the functions hooked to the action.
+ * @return null Will return null if $tag does not exist in $wp_filter array
+ */
+function do_action($tag, $arg = '') {
+ global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
+
+ if ( is_array($wp_actions) )
+ $wp_actions[] = $tag;
+ else
+ $wp_actions = array($tag);
+
+ $wp_current_filter[] = $tag;
+
+ // Do 'all' actions first
+ if ( isset($wp_filter['all']) ) {
+ $all_args = func_get_args();
+ _wp_call_all_hook($all_args);
+ }
+
+ if ( !isset($wp_filter[$tag]) ) {
+ array_pop($wp_current_filter);
+ return;
+ }
+
+ $args = array();
+ if ( is_array($arg) && 1 == count($arg) && is_object($arg[0]) ) // array(&$this)
+ $args[] =& $arg[0];
+ else
+ $args[] = $arg;
+ for ( $a = 2; $a < func_num_args(); $a++ )
+ $args[] = func_get_arg($a);
+
+ // Sort
+ if ( !isset( $merged_filters[ $tag ] ) ) {
+ ksort($wp_filter[$tag]);
+ $merged_filters[ $tag ] = true;
+ }
+
+ reset( $wp_filter[ $tag ] );
+
+ do {
+ foreach ( (array) current($wp_filter[$tag]) as $the_ )
+ if ( !is_null($the_['function']) )
+ call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
+
+ } while ( next($wp_filter[$tag]) !== false );
+
+ array_pop($wp_current_filter);
+}
+
+/**
+ * Retrieve the number times an action is fired.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.1
+ * @global array $wp_actions Increments the amount of times action was triggered.
+ *
+ * @param string $tag The name of the action hook.
+ * @return int The number of times action hook $tag is fired
+ */
+function did_action($tag) {
+ global $wp_actions;
+
+ if ( empty($wp_actions) )
+ return 0;
+
+ return count(array_keys($wp_actions, $tag));
+}
+
+/**
+ * Execute functions hooked on a specific action hook, specifying arguments in an array.
+ *
+ * @see do_action() This function is identical, but the arguments passed to the
+ * functions hooked to $tag are supplied using an array.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.1
+ * @global array $wp_filter Stores all of the filters
+ * @global array $wp_actions Increments the amount of times action was triggered.
+ *
+ * @param string $tag The name of the action to be executed.
+ * @param array $args The arguments supplied to the functions hooked to $tag
+ * @return null Will return null if $tag does not exist in $wp_filter array
+ */
+function do_action_ref_array($tag, $args) {
+ global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
+
+ if ( !is_array($wp_actions) )
+ $wp_actions = array($tag);
+ else
+ $wp_actions[] = $tag;
+
+ $wp_current_filter[] = $tag;
+
+ // Do 'all' actions first
+ if ( isset($wp_filter['all']) ) {
+ $all_args = func_get_args();
+ _wp_call_all_hook($all_args);
+ }
+
+ if ( !isset($wp_filter[$tag]) ) {
+ array_pop($wp_current_filter);
+ return;
+ }
+
+ // Sort
+ if ( !isset( $merged_filters[ $tag ] ) ) {
+ ksort($wp_filter[$tag]);
+ $merged_filters[ $tag ] = true;
+ }
+
+ reset( $wp_filter[ $tag ] );
+
+ do {
+ foreach( (array) current($wp_filter[$tag]) as $the_ )
+ if ( !is_null($the_['function']) )
+ call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
+
+ } while ( next($wp_filter[$tag]) !== false );
+
+ array_pop($wp_current_filter);
+}
+
+/**
+ * Check if any action has been registered for a hook.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ * @see has_filter() has_action() is an alias of has_filter().
+ *
+ * @param string $tag The name of the action hook.
+ * @param callback $function_to_check optional. If specified, return the priority of that function on this hook or false if not attached.
+ * @return int|boolean Optionally returns the priority on that hook for the specified function.
+ */
+function has_action($tag, $function_to_check = false) {
+ return has_filter($tag, $function_to_check);
+}
+
+/**
+ * Removes a function from a specified action hook.
+ *
+ * This function removes a function attached to a specified action hook. This
+ * method can be used to remove default functions attached to a specific filter
+ * hook and possibly replace them with a substitute.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ *
+ * @param string $tag The action hook to which the function to be removed is hooked.
+ * @param callback $function_to_remove The name of the function which should be removed.
+ * @param int $priority optional The priority of the function (default: 10).
+ * @param int $accepted_args optional. The number of arguments the function accpets (default: 1).
+ * @return boolean Whether the function is removed.
+ */
+function remove_action($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
+ return remove_filter($tag, $function_to_remove, $priority, $accepted_args);
+}
+
+/**
+ * Remove all of the hooks from an action.
+ *
+ * @since 2.7
+ *
+ * @param string $tag The action to remove hooks from.
+ * @param int $priority The priority number to remove them from.
+ * @return bool True when finished.
+ */
+function remove_all_actions($tag, $priority = false) {
+ return remove_all_filters($tag, $priority);
+}
+
+//
+// Functions for handling plugins.
+//
+
+/**
+ * Gets the basename of a plugin.
+ *
+ * This method extracts the name of a plugin from its filename.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.5
+ *
+ * @access private
+ *
+ * @param string $file The filename of plugin.
+ * @return string The name of a plugin.
+ * @uses WP_PLUGIN_DIR
+ */
+function plugin_basename($file) {
+ $file = str_replace('\\','/',$file); // sanitize for Win32 installs
+ $file = preg_replace('|/+|','/', $file); // remove any duplicate slash
+ $plugin_dir = str_replace('\\','/',WP_PLUGIN_DIR); // sanitize for Win32 installs
+ $plugin_dir = preg_replace('|/+|','/', $plugin_dir); // remove any duplicate slash
+ $file = preg_replace('|^' . preg_quote($plugin_dir, '|') . '/|','',$file); // get relative path from plugins dir
+ return $file;
+}
+
+/**
+ * Set the activation hook for a plugin.
+ *
+ * When a plugin is activated, the action 'activate_PLUGINNAME' hook is
+ * activated. In the name of this hook, PLUGINNAME is replaced with the name of
+ * the plugin, including the optional subdirectory. For example, when the plugin
+ * is located in wp-content/plugin/sampleplugin/sample.php, then the name of
+ * this hook will become 'activate_sampleplugin/sample.php'. When the plugin
+ * consists of only one file and is (as by default) located at
+ * wp-content/plugin/sample.php the name of this hook will be
+ * 'activate_sample.php'.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.0
+ *
+ * @access private
+ *
+ * @param string $file The filename of the plugin including the path.
+ * @param callback $function the function hooked to the 'activate_PLUGIN' action.
+ */
+function register_activation_hook($file, $function) {
+ $file = plugin_basename($file);
+ add_action('activate_' . $file, $function);
+}
+
+/**
+ * Set the deactivation hook for a plugin.
+ *
+ * When a plugin is deactivated, the action 'deactivate_PLUGINNAME' hook is
+ * deactivated. In the name of this hook, PLUGINNAME is replaced with the name
+ * of the plugin, including the optional subdirectory. For example, when the
+ * plugin is located in wp-content/plugin/sampleplugin/sample.php, then
+ * the name of this hook will become 'activate_sampleplugin/sample.php'.
+ *
+ * When the plugin consists of only one file and is (as by default) located at
+ * wp-content/plugin/sample.php the name of this hook will be
+ * 'activate_sample.php'.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.0
+ *
+ * @access private
+ *
+ * @param string $file The filename of the plugin including the path.
+ * @param callback $function the function hooked to the 'activate_PLUGIN' action.
+ */
+function register_deactivation_hook($file, $function) {
+ $file = plugin_basename($file);
+ add_action('deactivate_' . $file, $function);
+}
+
+/**
+ * Set the uninstallation hook for a plugin.
+ *
+ * Registers the uninstall hook that will be called when the user clicks on the
+ * uninstall link that calls for the plugin to uninstall itself. The link won't
+ * be active unless the plugin hooks into the action.
+ *
+ * The plugin should not run arbitrary code outside of functions, when
+ * registering the uninstall hook. In order to run using the hook, the plugin
+ * will have to be included, which means that any code laying outside of a
+ * function will be run during the uninstall process. The plugin should not
+ * hinder the uninstall process.
+ *
+ * If the plugin can not be written without running code within the plugin, then
+ * the plugin should create a file named 'uninstall.php' in the base plugin
+ * folder. This file will be called, if it exists, during the uninstall process
+ * bypassing the uninstall hook. The plugin, when using the 'uninstall.php'
+ * should always check for the 'WP_UNINSTALL_PLUGIN' constant, before
+ * executing.
+ *
+ * @since 2.7
+ *
+ * @param string $file
+ * @param callback $callback The callback to run when the hook is called.
+ */
+function register_uninstall_hook($file, $callback) {
+ // The option should not be autoloaded, because it is not needed in most
+ // cases. Emphasis should be put on using the 'uninstall.php' way of
+ // uninstalling the plugin.
+ $uninstallable_plugins = (array) get_option('uninstall_plugins');
+ $uninstallable_plugins[plugin_basename($file)] = $callback;
+ update_option('uninstall_plugins', $uninstallable_plugins);
+}
+
+/**
+ * Calls the 'all' hook, which will process the functions hooked into it.
+ *
+ * The 'all' hook passes all of the arguments or parameters that were used for
+ * the hook, which this function was called for.
+ *
+ * This function is used internally for apply_filters(), do_action(), and
+ * do_action_ref_array() and is not meant to be used from outside those
+ * functions. This function does not check for the existence of the all hook, so
+ * it will fail unless the all hook exists prior to this function call.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ * @access private
+ *
+ * @uses $wp_filter Used to process all of the functions in the 'all' hook
+ *
+ * @param array $args The collected parameters from the hook that was called.
+ * @param string $hook Optional. The hook name that was used to call the 'all' hook.
+ */
+function _wp_call_all_hook($args) {
+ global $wp_filter;
+
+ reset( $wp_filter['all'] );
+ do {
+ foreach( (array) current($wp_filter['all']) as $the_ )
+ if ( !is_null($the_['function']) )
+ call_user_func_array($the_['function'], $args);
+
+ } while ( next($wp_filter['all']) !== false );
+}
+
+/**
+ * Build Unique ID for storage and retrieval.
+ *
+ * The old way to serialize the callback caused issues and this function is the
+ * solution. It works by checking for objects and creating an a new property in
+ * the class to keep track of the object and new objects of the same class that
+ * need to be added.
+ *
+ * It also allows for the removal of actions and filters for objects after they
+ * change class properties. It is possible to include the property $wp_filter_id
+ * in your class and set it to "null" or a number to bypass the workaround.
+ * However this will prevent you from adding new classes and any new classes
+ * will overwrite the previous hook by the same class.
+ *
+ * Functions and static method callbacks are just returned as strings and
+ * shouldn't have any speed penalty.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @access private
+ * @since 2.2.3
+ * @link http://trac.wordpress.org/ticket/3875
+ *
+ * @global array $wp_filter Storage for all of the filters and actions
+ * @param string $tag Used in counting how many hooks were applied
+ * @param string|array $function Used for creating unique id
+ * @param int|bool $priority Used in counting how many hooks were applied. If === false and $function is an object reference, we return the unique id only if it already has one, false otherwise.
+ * @param string $type filter or action
+ * @return string Unique ID for usage as array key
+ */
+function _wp_filter_build_unique_id($tag, $function, $priority) {
+ global $wp_filter;
+
+ // If function then just skip all of the tests and not overwrite the following.
+ if ( is_string($function) )
+ return $function;
+ // Object Class Calling
+ else if (is_object($function[0]) ) {
+ $obj_idx = get_class($function[0]).$function[1];
+ if ( !isset($function[0]->wp_filter_id) ) {
+ if ( false === $priority )
+ return false;
+ $count = isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : 0;
+ $function[0]->wp_filter_id = $count;
+ $obj_idx .= $count;
+ unset($count);
+ } else
+ $obj_idx .= $function[0]->wp_filter_id;
+ return $obj_idx;
+ }
+ // Static Calling
+ else if ( is_string($function[0]) )
+ return $function[0].$function[1];
+}
+
+?>
diff -uNr a/blog/wp-includes/post.php b/blog/wp-includes/post.php
--- a/blog/wp-includes/post.php false
+++ b/blog/wp-includes/post.php afd861ec351f6e291fb62bda03f9a1d12e15127ef92c2b3b4d02fdc78dba70b6b46f39da686eec4e162c5087f79d7d7adc2660c1397c3e43e08e9bb1f4ddd765
@@ -0,0 +1,3623 @@
+ (int) $GLOBALS['post']->post_parent );
+ } else {
+ return false;
+ }
+ } elseif ( is_object( $args ) ) {
+ $args = array('post_parent' => (int) $args->post_parent );
+ } elseif ( is_numeric( $args ) ) {
+ $args = array('post_parent' => (int) $args);
+ }
+
+ $defaults = array(
+ 'numberposts' => -1, 'post_type' => 'any',
+ 'post_status' => 'any', 'post_parent' => 0,
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ $children = get_posts( $r );
+ if ( !$children ) {
+ $kids = false;
+ return $kids;
+ }
+
+ update_post_cache($children);
+
+ foreach ( $children as $key => $child )
+ $kids[$child->ID] =& $children[$key];
+
+ if ( $output == OBJECT ) {
+ return $kids;
+ } elseif ( $output == ARRAY_A ) {
+ foreach ( (array) $kids as $kid )
+ $weeuns[$kid->ID] = get_object_vars($kids[$kid->ID]);
+ return $weeuns;
+ } elseif ( $output == ARRAY_N ) {
+ foreach ( (array) $kids as $kid )
+ $babes[$kid->ID] = array_values(get_object_vars($kids[$kid->ID]));
+ return $babes;
+ } else {
+ return $kids;
+ }
+}
+
+/**
+ * Get extended entry info ().
+ *
+ * There should not be any space after the second dash and before the word
+ * 'more'. There can be text or space(s) after the word 'more', but won't be
+ * referenced.
+ *
+ * The returned array has 'main' and 'extended' keys. Main has the text before
+ * the
. The 'extended' key has the content after the
+ *
comment.
+ *
+ * @since 1.0.0
+ *
+ * @param string $post Post content.
+ * @return array Post before ('main') and after ('extended').
+ */
+function get_extended($post) {
+ //Match the new style more links
+ if ( preg_match('//', $post, $matches) ) {
+ list($main, $extended) = explode($matches[0], $post, 2);
+ } else {
+ $main = $post;
+ $extended = '';
+ }
+
+ // Strip leading and trailing whitespace
+ $main = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $main);
+ $extended = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $extended);
+
+ return array('main' => $main, 'extended' => $extended);
+}
+
+/**
+ * Retrieves post data given a post ID or post object.
+ *
+ * See {@link sanitize_post()} for optional $filter values. Also, the parameter
+ * $post, must be given as a variable, since it is passed by reference.
+ *
+ * @since 1.5.1
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/get_post
+ *
+ * @param int|object $post Post ID or post object.
+ * @param string $output Optional, default is Object. Either OBJECT, ARRAY_A, or ARRAY_N.
+ * @param string $filter Optional, default is raw.
+ * @return mixed Post data
+ */
+function &get_post(&$post, $output = OBJECT, $filter = 'raw') {
+ global $wpdb;
+ $null = null;
+
+ if ( empty($post) ) {
+ if ( isset($GLOBALS['post']) )
+ $_post = & $GLOBALS['post'];
+ else
+ return $null;
+ } elseif ( is_object($post) ) {
+ _get_post_ancestors($post);
+ wp_cache_add($post->ID, $post, 'posts');
+ $_post = &$post;
+ } else {
+ $post = (int) $post;
+ if ( ! $_post = wp_cache_get($post, 'posts') ) {
+ $_post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d LIMIT 1", $post));
+ if ( ! $_post )
+ return $null;
+ _get_post_ancestors($_post);
+ wp_cache_add($_post->ID, $_post, 'posts');
+ }
+ }
+
+ $_post = sanitize_post($_post, $filter);
+
+ if ( $output == OBJECT ) {
+ return $_post;
+ } elseif ( $output == ARRAY_A ) {
+ $__post = get_object_vars($_post);
+ return $__post;
+ } elseif ( $output == ARRAY_N ) {
+ $__post = array_values(get_object_vars($_post));
+ return $__post;
+ } else {
+ return $_post;
+ }
+}
+
+/**
+ * Retrieve ancestors of a post.
+ *
+ * @since 2.5.0
+ *
+ * @param int|object $post Post ID or post object
+ * @return array Ancestor IDs or empty array if none are found.
+ */
+function get_post_ancestors($post) {
+ $post = get_post($post);
+
+ if ( !empty($post->ancestors) )
+ return $post->ancestors;
+
+ return array();
+}
+
+/**
+ * Retrieve data from a post field based on Post ID.
+ *
+ * Examples of the post field will be, 'post_type', 'post_status', 'content',
+ * etc and based off of the post object property or key names.
+ *
+ * The context values are based off of the taxonomy filter functions and
+ * supported values are found within those functions.
+ *
+ * @since 2.3.0
+ * @uses sanitize_post_field() See for possible $context values.
+ *
+ * @param string $field Post field name
+ * @param id $post Post ID
+ * @param string $context Optional. How to filter the field. Default is display.
+ * @return WP_Error|string Value in post field or WP_Error on failure
+ */
+function get_post_field( $field, $post, $context = 'display' ) {
+ $post = (int) $post;
+ $post = get_post( $post );
+
+ if ( is_wp_error($post) )
+ return $post;
+
+ if ( !is_object($post) )
+ return '';
+
+ if ( !isset($post->$field) )
+ return '';
+
+ return sanitize_post_field($field, $post->$field, $post->ID, $context);
+}
+
+/**
+ * Retrieve the mime type of an attachment based on the ID.
+ *
+ * This function can be used with any post type, but it makes more sense with
+ * attachments.
+ *
+ * @since 2.0.0
+ *
+ * @param int $ID Optional. Post ID.
+ * @return bool|string False on failure or returns the mime type
+ */
+function get_post_mime_type($ID = '') {
+ $post = & get_post($ID);
+
+ if ( is_object($post) )
+ return $post->post_mime_type;
+
+ return false;
+}
+
+/**
+ * Retrieve the post status based on the Post ID.
+ *
+ * If the post ID is of an attachment, then the parent post status will be given
+ * instead.
+ *
+ * @since 2.0.0
+ *
+ * @param int $ID Post ID
+ * @return string|bool Post status or false on failure.
+ */
+function get_post_status($ID = '') {
+ $post = get_post($ID);
+
+ if ( is_object($post) ) {
+ if ( ('attachment' == $post->post_type) && $post->post_parent && ($post->ID != $post->post_parent) )
+ return get_post_status($post->post_parent);
+ else
+ return $post->post_status;
+ }
+
+ return false;
+}
+
+/**
+ * Retrieve all of the WordPress supported post statuses.
+ *
+ * Posts have a limited set of valid status values, this provides the
+ * post_status values and descriptions.
+ *
+ * @since 2.5.0
+ *
+ * @return array List of post statuses.
+ */
+function get_post_statuses( ) {
+ $status = array(
+ 'draft' => __('Draft'),
+ 'pending' => __('Pending Review'),
+ 'private' => __('Private'),
+ 'publish' => __('Published')
+ );
+
+ return $status;
+}
+
+/**
+ * Retrieve all of the WordPress support page statuses.
+ *
+ * Pages have a limited set of valid status values, this provides the
+ * post_status values and descriptions.
+ *
+ * @since 2.5.0
+ *
+ * @return array List of page statuses.
+ */
+function get_page_statuses( ) {
+ $status = array(
+ 'draft' => __('Draft'),
+ 'private' => __('Private'),
+ 'publish' => __('Published')
+ );
+
+ return $status;
+}
+
+/**
+ * Retrieve the post type of the current post or of a given post.
+ *
+ * @since 2.1.0
+ *
+ * @uses $wpdb
+ * @uses $posts The Loop post global
+ *
+ * @param mixed $post Optional. Post object or post ID.
+ * @return bool|string post type or false on failure.
+ */
+function get_post_type($post = false) {
+ global $posts;
+
+ if ( false === $post )
+ $post = $posts[0];
+ elseif ( (int) $post )
+ $post = get_post($post, OBJECT);
+
+ if ( is_object($post) )
+ return $post->post_type;
+
+ return false;
+}
+
+/**
+ * Updates the post type for the post ID.
+ *
+ * The page or post cache will be cleaned for the post ID.
+ *
+ * @since 2.5.0
+ *
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID to change post type. Not actually optional.
+ * @param string $post_type Optional, default is post. Supported values are 'post' or 'page' to name a few.
+ * @return int Amount of rows changed. Should be 1 for success and 0 for failure.
+ */
+function set_post_type( $post_id = 0, $post_type = 'post' ) {
+ global $wpdb;
+
+ $post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
+ $return = $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_type = %s WHERE ID = %d", $post_type, $post_id) );
+
+ if ( 'page' == $post_type )
+ clean_page_cache($post_id);
+ else
+ clean_post_cache($post_id);
+
+ return $return;
+}
+
+/**
+ * Retrieve list of latest posts or posts matching criteria.
+ *
+ * The defaults are as follows:
+ * 'numberposts' - Default is 5. Total number of posts to retrieve.
+ * 'offset' - Default is 0. See {@link WP_Query::query()} for more.
+ * 'category' - What category to pull the posts from.
+ * 'orderby' - Default is 'post_date'. How to order the posts.
+ * 'order' - Default is 'DESC'. The order to retrieve the posts.
+ * 'include' - See {@link WP_Query::query()} for more.
+ * 'exclude' - See {@link WP_Query::query()} for more.
+ * 'meta_key' - See {@link WP_Query::query()} for more.
+ * 'meta_value' - See {@link WP_Query::query()} for more.
+ * 'post_type' - Default is 'post'. Can be 'page', or 'attachment' to name a few.
+ * 'post_parent' - The parent of the post or post type.
+ * 'post_status' - Default is 'published'. Post status to retrieve.
+ *
+ * @since 1.2.0
+ * @uses $wpdb
+ * @uses WP_Query::query() See for more default arguments and information.
+ * @link http://codex.wordpress.org/Template_Tags/get_posts
+ *
+ * @param array $args Optional. Override defaults.
+ * @return array List of posts.
+ */
+function get_posts($args = null) {
+ $defaults = array(
+ 'numberposts' => 5, 'offset' => 0,
+ 'category' => 0, 'orderby' => 'post_date',
+ 'order' => 'DESC', 'include' => '',
+ 'exclude' => '', 'meta_key' => '',
+ 'meta_value' =>'', 'post_type' => 'post',
+ 'suppress_filters' => true
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ if ( empty( $r['post_status'] ) )
+ $r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
+ if ( ! empty($r['numberposts']) )
+ $r['posts_per_page'] = $r['numberposts'];
+ if ( ! empty($r['category']) )
+ $r['cat'] = $r['category'];
+ if ( ! empty($r['include']) ) {
+ $incposts = preg_split('/[\s,]+/',$r['include']);
+ $r['posts_per_page'] = count($incposts); // only the number of posts included
+ $r['post__in'] = $incposts;
+ } elseif ( ! empty($r['exclude']) )
+ $r['post__not_in'] = preg_split('/[\s,]+/',$r['exclude']);
+
+ $r['caller_get_posts'] = true;
+
+ $get_posts = new WP_Query;
+ return $get_posts->query($r);
+
+}
+
+//
+// Post meta functions
+//
+
+/**
+ * Add meta data field to a post.
+ *
+ * Post meta data is called "Custom Fields" on the Administration Panels.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/add_post_meta
+ *
+ * @param int $post_id Post ID.
+ * @param string $key Metadata name.
+ * @param mixed $value Metadata value.
+ * @param bool $unique Optional, default is false. Whether the same key should not be added.
+ * @return bool False for failure. True for success.
+ */
+function add_post_meta($post_id, $meta_key, $meta_value, $unique = false) {
+ global $wpdb;
+
+ // make sure meta is added to the post, not a revision
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ // expected_slashed ($meta_key)
+ $meta_key = stripslashes($meta_key);
+
+ if ( $unique && $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d", $meta_key, $post_id ) ) )
+ return false;
+
+ $meta_value = maybe_serialize( stripslashes_deep($meta_value) );
+
+ $wpdb->insert( $wpdb->postmeta, compact( 'post_id', 'meta_key', 'meta_value' ) );
+
+ wp_cache_delete($post_id, 'post_meta');
+
+ return true;
+}
+
+/**
+ * Remove metadata matching criteria from a post.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/delete_post_meta
+ *
+ * @param int $post_id post ID
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata value.
+ * @return bool False for failure. True for success.
+ */
+function delete_post_meta($post_id, $meta_key, $meta_value = '') {
+ global $wpdb;
+
+ // make sure meta is added to the post, not a revision
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ // expected_slashed ($meta_key, $meta_value)
+ $meta_key = stripslashes( $meta_key );
+ $meta_value = maybe_serialize( stripslashes_deep($meta_value) );
+
+ if ( empty( $meta_value ) )
+ $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key ) );
+ else
+ $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $meta_key, $meta_value ) );
+
+ if ( !$meta_id )
+ return false;
+
+ if ( empty( $meta_value ) )
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key ) );
+ else
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $meta_key, $meta_value ) );
+
+ wp_cache_delete($post_id, 'post_meta');
+
+ return true;
+}
+
+/**
+ * Retrieve post meta field for a post.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/get_post_meta
+ *
+ * @param int $post_id Post ID.
+ * @param string $key The meta key to retrieve.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
+ */
+function get_post_meta($post_id, $key, $single = false) {
+ $post_id = (int) $post_id;
+
+ $meta_cache = wp_cache_get($post_id, 'post_meta');
+
+ if ( !$meta_cache ) {
+ update_postmeta_cache($post_id);
+ $meta_cache = wp_cache_get($post_id, 'post_meta');
+ }
+
+ if ( isset($meta_cache[$key]) ) {
+ if ( $single ) {
+ return maybe_unserialize( $meta_cache[$key][0] );
+ } else {
+ return array_map('maybe_unserialize', $meta_cache[$key]);
+ }
+ }
+
+ return '';
+}
+
+/**
+ * Update post meta field based on post ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and post ID.
+ *
+ * If the meta field for the post does not exist, it will be added.
+ *
+ * @since 1.5
+ * @uses $wpdb
+ * @link http://codex.wordpress.org/Function_Reference/update_post_meta
+ *
+ * @param int $post_id Post ID.
+ * @param string $key Metadata key.
+ * @param mixed $value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return bool False on failure, true if success.
+ */
+function update_post_meta($post_id, $meta_key, $meta_value, $prev_value = '') {
+ global $wpdb;
+
+ // make sure meta is added to the post, not a revision
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ // expected_slashed ($meta_key)
+ $meta_key = stripslashes($meta_key);
+
+ if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d", $meta_key, $post_id ) ) ) {
+ return add_post_meta($post_id, $meta_key, $meta_value);
+ }
+
+ $meta_value = maybe_serialize( stripslashes_deep($meta_value) );
+
+ $data = compact( 'meta_value' );
+ $where = compact( 'meta_key', 'post_id' );
+
+ if ( !empty( $prev_value ) ) {
+ $prev_value = maybe_serialize($prev_value);
+ $where['meta_value'] = $prev_value;
+ }
+
+ $wpdb->update( $wpdb->postmeta, $data, $where );
+ wp_cache_delete($post_id, 'post_meta');
+ return true;
+}
+
+/**
+ * Delete everything from post meta matching meta key.
+ *
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param string $post_meta_key Key to search for when deleting.
+ * @return bool Whether the post meta key was deleted from the database
+ */
+function delete_post_meta_by_key($post_meta_key) {
+ global $wpdb;
+ if ( $wpdb->query($wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_key = %s", $post_meta_key)) ) {
+ /** @todo Get post_ids and delete cache */
+ // wp_cache_delete($post_id, 'post_meta');
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Retrieve post meta fields, based on post ID.
+ *
+ * The post meta fields are retrieved from the cache, so the function is
+ * optimized to be called more than once. It also applies to the functions, that
+ * use this function.
+ *
+ * @since 1.2.0
+ * @link http://codex.wordpress.org/Function_Reference/get_post_custom
+ *
+ * @uses $id Current Loop Post ID
+ *
+ * @param int $post_id post ID
+ * @return array
+ */
+function get_post_custom($post_id = 0) {
+ global $id;
+
+ if ( !$post_id )
+ $post_id = (int) $id;
+
+ $post_id = (int) $post_id;
+
+ if ( ! wp_cache_get($post_id, 'post_meta') )
+ update_postmeta_cache($post_id);
+
+ return wp_cache_get($post_id, 'post_meta');
+}
+
+/**
+ * Retrieve meta field names for a post.
+ *
+ * If there are no meta fields, then nothing (null) will be returned.
+ *
+ * @since 1.2.0
+ * @link http://codex.wordpress.org/Function_Reference/get_post_custom_keys
+ *
+ * @param int $post_id post ID
+ * @return array|null Either array of the keys, or null if keys could not be retrieved.
+ */
+function get_post_custom_keys( $post_id = 0 ) {
+ $custom = get_post_custom( $post_id );
+
+ if ( !is_array($custom) )
+ return;
+
+ if ( $keys = array_keys($custom) )
+ return $keys;
+}
+
+/**
+ * Retrieve values for a custom post field.
+ *
+ * The parameters must not be considered optional. All of the post meta fields
+ * will be retrieved and only the meta field key values returned.
+ *
+ * @since 1.2.0
+ * @link http://codex.wordpress.org/Function_Reference/get_post_custom_values
+ *
+ * @param string $key Meta field key.
+ * @param int $post_id Post ID
+ * @return array Meta field values.
+ */
+function get_post_custom_values( $key = '', $post_id = 0 ) {
+ $custom = get_post_custom($post_id);
+
+ return $custom[$key];
+}
+
+/**
+ * Check if post is sticky.
+ *
+ * Sticky posts should remain at the top of The Loop. If the post ID is not
+ * given, then The Loop ID for the current post will be used.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @return bool Whether post is sticky (true) or not sticky (false).
+ */
+function is_sticky($post_id = null) {
+ global $id;
+
+ $post_id = absint($post_id);
+
+ if ( !$post_id )
+ $post_id = absint($id);
+
+ $stickies = get_option('sticky_posts');
+
+ if ( !is_array($stickies) )
+ return false;
+
+ if ( in_array($post_id, $stickies) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Sanitize every post field.
+ *
+ * If the context is 'raw', then the post object or array will just be returned.
+ *
+ * @since 2.3.0
+ * @uses sanitize_post_field() Used to sanitize the fields.
+ *
+ * @param object|array $post The Post Object or Array
+ * @param string $context Optional, default is 'display'. How to sanitize post fields.
+ * @return object|array The now sanitized Post Object or Array (will be the same type as $post)
+ */
+function sanitize_post($post, $context = 'display') {
+ if ( 'raw' == $context )
+ return $post;
+ if ( is_object($post) ) {
+ if ( !isset($post->ID) )
+ $post->ID = 0;
+ foreach ( array_keys(get_object_vars($post)) as $field )
+ $post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
+ } else {
+ if ( !isset($post['ID']) )
+ $post['ID'] = 0;
+ foreach ( array_keys($post) as $field )
+ $post[$field] = sanitize_post_field($field, $post[$field], $post['ID'], $context);
+ }
+ return $post;
+}
+
+/**
+ * Sanitize post field based on context.
+ *
+ * Possible context values are: raw, edit, db, attribute, js, and display. The
+ * display context is used by default.
+ *
+ * @since 2.3.0
+ *
+ * @param string $field The Post Object field name.
+ * @param mixed $value The Post Object value.
+ * @param int $post_id Post ID.
+ * @param string $context How to sanitize post fields.
+ * @return mixed Sanitized value.
+ */
+function sanitize_post_field($field, $value, $post_id, $context) {
+ $int_fields = array('ID', 'post_parent', 'menu_order');
+ if ( in_array($field, $int_fields) )
+ $value = (int) $value;
+
+ if ( 'raw' == $context )
+ return $value;
+
+ $prefixed = false;
+ if ( false !== strpos($field, 'post_') ) {
+ $prefixed = true;
+ $field_no_prefix = str_replace('post_', '', $field);
+ }
+
+ if ( 'edit' == $context ) {
+ $format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
+
+ if ( $prefixed ) {
+ $value = apply_filters("edit_$field", $value, $post_id);
+ // Old school
+ $value = apply_filters("${field_no_prefix}_edit_pre", $value, $post_id);
+ } else {
+ $value = apply_filters("edit_post_$field", $value, $post_id);
+ }
+
+ if ( in_array($field, $format_to_edit) ) {
+ if ( 'post_content' == $field )
+ $value = format_to_edit($value, user_can_richedit());
+ else
+ $value = format_to_edit($value);
+ } else {
+ $value = attribute_escape($value);
+ }
+ } else if ( 'db' == $context ) {
+ if ( $prefixed ) {
+ $value = apply_filters("pre_$field", $value);
+ $value = apply_filters("${field_no_prefix}_save_pre", $value);
+ } else {
+ $value = apply_filters("pre_post_$field", $value);
+ $value = apply_filters("${field}_pre", $value);
+ }
+ } else {
+ // Use display filters by default.
+ if ( $prefixed )
+ $value = apply_filters($field, $value, $post_id, $context);
+ else
+ $value = apply_filters("post_$field", $value, $post_id, $context);
+ }
+
+ if ( 'attribute' == $context )
+ $value = attribute_escape($value);
+ else if ( 'js' == $context )
+ $value = js_escape($value);
+
+ return $value;
+}
+
+/**
+ * Make a post sticky.
+ *
+ * Sticky posts should be displayed at the top of the front page.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Post ID.
+ */
+function stick_post($post_id) {
+ $stickies = get_option('sticky_posts');
+
+ if ( !is_array($stickies) )
+ $stickies = array($post_id);
+
+ if ( ! in_array($post_id, $stickies) )
+ $stickies[] = $post_id;
+
+ update_option('sticky_posts', $stickies);
+}
+
+/**
+ * Unstick a post.
+ *
+ * Sticky posts should be displayed at the top of the front page.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Post ID.
+ */
+function unstick_post($post_id) {
+ $stickies = get_option('sticky_posts');
+
+ if ( !is_array($stickies) )
+ return;
+
+ if ( ! in_array($post_id, $stickies) )
+ return;
+
+ $offset = array_search($post_id, $stickies);
+ if ( false === $offset )
+ return;
+
+ array_splice($stickies, $offset, 1);
+
+ update_option('sticky_posts', $stickies);
+}
+
+/**
+ * Count number of posts of a post type and is user has permissions to view.
+ *
+ * This function provides an efficient method of finding the amount of post's
+ * type a blog has. Another method is to count the amount of items in
+ * get_posts(), but that method has a lot of overhead with doing so. Therefore,
+ * when developing for 2.5+, use this function instead.
+ *
+ * The $perm parameter checks for 'readable' value and if the user can read
+ * private posts, it will display that for the user that is signed in.
+ *
+ * @since 2.5.0
+ * @link http://codex.wordpress.org/Template_Tags/wp_count_posts
+ *
+ * @param string $type Optional. Post type to retrieve count
+ * @param string $perm Optional. 'readable' or empty.
+ * @return object Number of posts for each status
+ */
+function wp_count_posts( $type = 'post', $perm = '' ) {
+ global $wpdb;
+
+ $user = wp_get_current_user();
+
+ $cache_key = $type;
+
+ $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
+ if ( 'readable' == $perm && is_user_logged_in() ) {
+ if ( !current_user_can("read_private_{$type}s") ) {
+ $cache_key .= '_' . $perm . '_' . $user->ID;
+ $query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
+ }
+ }
+ $query .= ' GROUP BY post_status';
+
+ $count = wp_cache_get($cache_key, 'counts');
+ if ( false !== $count )
+ return $count;
+
+ $count = $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
+
+ $stats = array( );
+ foreach( (array) $count as $row_num => $row ) {
+ $stats[$row['post_status']] = $row['num_posts'];
+ }
+
+ $stats = (object) $stats;
+ wp_cache_set($cache_key, $stats, 'counts');
+
+ return $stats;
+}
+
+
+/**
+ * Count number of attachments for the mime type(s).
+ *
+ * If you set the optional mime_type parameter, then an array will still be
+ * returned, but will only have the item you are looking for. It does not give
+ * you the number of attachments that are children of a post. You can get that
+ * by counting the number of children that post has.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $mime_type Optional. Array or comma-separated list of MIME patterns.
+ * @return array Number of posts for each mime type.
+ */
+function wp_count_attachments( $mime_type = '' ) {
+ global $wpdb;
+
+ $and = wp_post_mime_type_where( $mime_type );
+ $count = $wpdb->get_results( "SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = 'attachment' $and GROUP BY post_mime_type", ARRAY_A );
+
+ $stats = array( );
+ foreach( (array) $count as $row ) {
+ $stats[$row['post_mime_type']] = $row['num_posts'];
+ }
+
+ return (object) $stats;
+}
+
+/**
+ * Check a MIME-Type against a list.
+ *
+ * If the wildcard_mime_types parameter is a string, it must be comma separated
+ * list. If the real_mime_types is a string, it is also comma separated to
+ * create the list.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $wildcard_mime_types e.g. audio/mpeg or image (same as image/*) or flash (same as *flash*)
+ * @param string|array $real_mime_types post_mime_type values
+ * @return array array(wildcard=>array(real types))
+ */
+function wp_match_mime_types($wildcard_mime_types, $real_mime_types) {
+ $matches = array();
+ if ( is_string($wildcard_mime_types) )
+ $wildcard_mime_types = array_map('trim', explode(',', $wildcard_mime_types));
+ if ( is_string($real_mime_types) )
+ $real_mime_types = array_map('trim', explode(',', $real_mime_types));
+ $wild = '[-._a-z0-9]*';
+ foreach ( (array) $wildcard_mime_types as $type ) {
+ $type = str_replace('*', $wild, $type);
+ $patternses[1][$type] = "^$type$";
+ if ( false === strpos($type, '/') ) {
+ $patternses[2][$type] = "^$type/";
+ $patternses[3][$type] = $type;
+ }
+ }
+ asort($patternses);
+ foreach ( $patternses as $patterns )
+ foreach ( $patterns as $type => $pattern )
+ foreach ( (array) $real_mime_types as $real )
+ if ( preg_match("#$pattern#", $real) && ( empty($matches[$type]) || false === array_search($real, $matches[$type]) ) )
+ $matches[$type][] = $real;
+ return $matches;
+}
+
+/**
+ * Convert MIME types into SQL.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $mime_types List of mime types or comma separated string of mime types.
+ * @return string The SQL AND clause for mime searching.
+ */
+function wp_post_mime_type_where($post_mime_types) {
+ $where = '';
+ $wildcards = array('', '%', '%/%');
+ if ( is_string($post_mime_types) )
+ $post_mime_types = array_map('trim', explode(',', $post_mime_types));
+ foreach ( (array) $post_mime_types as $mime_type ) {
+ $mime_type = preg_replace('/\s/', '', $mime_type);
+ $slashpos = strpos($mime_type, '/');
+ if ( false !== $slashpos ) {
+ $mime_group = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, 0, $slashpos));
+ $mime_subgroup = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, $slashpos + 1));
+ if ( empty($mime_subgroup) )
+ $mime_subgroup = '*';
+ else
+ $mime_subgroup = str_replace('/', '', $mime_subgroup);
+ $mime_pattern = "$mime_group/$mime_subgroup";
+ } else {
+ $mime_pattern = preg_replace('/[^-*.a-zA-Z0-9]/', '', $mime_type);
+ if ( false === strpos($mime_pattern, '*') )
+ $mime_pattern .= '/*';
+ }
+
+ $mime_pattern = preg_replace('/\*+/', '%', $mime_pattern);
+
+ if ( in_array( $mime_type, $wildcards ) )
+ return '';
+
+ if ( false !== strpos($mime_pattern, '%') )
+ $wheres[] = "post_mime_type LIKE '$mime_pattern'";
+ else
+ $wheres[] = "post_mime_type = '$mime_pattern'";
+ }
+ if ( !empty($wheres) )
+ $where = ' AND (' . join(' OR ', $wheres) . ') ';
+ return $where;
+}
+
+/**
+ * Removes a post, attachment, or page.
+ *
+ * When the post and page goes, everything that is tied to it is deleted also.
+ * This includes comments, post meta fields, and terms associated with the post.
+ *
+ * @since 1.0.0
+ * @uses do_action() Calls 'deleted_post' hook on post ID.
+ *
+ * @param int $postid Post ID.
+ * @return mixed
+ */
+function wp_delete_post($postid = 0) {
+ global $wpdb, $wp_rewrite;
+
+ if ( !$post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
+ return $post;
+
+ if ( 'attachment' == $post->post_type )
+ return wp_delete_attachment($postid);
+
+ do_action('delete_post', $postid);
+
+ /** @todo delete for pluggable post taxonomies too */
+ wp_delete_object_term_relationships($postid, array('category', 'post_tag'));
+
+ $parent_data = array( 'post_parent' => $post->post_parent );
+ $parent_where = array( 'post_parent' => $postid );
+
+ if ( 'page' == $post->post_type) {
+ // if the page is defined in option page_on_front or post_for_posts,
+ // adjust the corresponding options
+ if ( get_option('page_on_front') == $postid ) {
+ update_option('show_on_front', 'posts');
+ delete_option('page_on_front');
+ }
+ if ( get_option('page_for_posts') == $postid ) {
+ delete_option('page_for_posts');
+ }
+
+ // Point children of this page to its parent, also clean the cache of affected children
+ $children_query = $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type='page'", $postid);
+ $children = $wpdb->get_results($children_query);
+
+ $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'page' ) );
+ }
+
+ // Do raw query. wp_get_post_revisions() is filtered
+ $revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $postid ) );
+ // Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
+ foreach ( $revision_ids as $revision_id )
+ wp_delete_post_revision( $revision_id );
+
+ // Point all attachments to this post up one level
+ $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
+
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->posts WHERE ID = %d", $postid ));
+
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
+
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d", $postid ));
+
+ if ( 'page' == $post->post_type ) {
+ clean_page_cache($postid);
+
+ foreach ( (array) $children as $child )
+ clean_page_cache($child->ID);
+
+ $wp_rewrite->flush_rules();
+ } else {
+ clean_post_cache($postid);
+ }
+
+ do_action('deleted_post', $postid);
+
+ return $post;
+}
+
+/**
+ * Retrieve the list of categories for a post.
+ *
+ * Compatibility layer for themes and plugins. Also an easy layer of abstraction
+ * away from the complexity of the taxonomy layer.
+ *
+ * @since 2.1.0
+ *
+ * @uses wp_get_object_terms() Retrieves the categories. Args details can be found here.
+ *
+ * @param int $post_id Optional. The Post ID.
+ * @param array $args Optional. Overwrite the defaults.
+ * @return array
+ */
+function wp_get_post_categories( $post_id = 0, $args = array() ) {
+ $post_id = (int) $post_id;
+
+ $defaults = array('fields' => 'ids');
+ $args = wp_parse_args( $args, $defaults );
+
+ $cats = wp_get_object_terms($post_id, 'category', $args);
+ return $cats;
+}
+
+/**
+ * Retrieve the tags for a post.
+ *
+ * There is only one default for this function, called 'fields' and by default
+ * is set to 'all'. There are other defaults that can be override in
+ * {@link wp_get_object_terms()}.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.3.0
+ *
+ * @uses wp_get_object_terms() Gets the tags for returning. Args can be found here
+ *
+ * @param int $post_id Optional. The Post ID
+ * @param array $args Optional. Overwrite the defaults
+ * @return array List of post tags.
+ */
+function wp_get_post_tags( $post_id = 0, $args = array() ) {
+ $post_id = (int) $post_id;
+
+ $defaults = array('fields' => 'all');
+ $args = wp_parse_args( $args, $defaults );
+
+ $tags = wp_get_object_terms($post_id, 'post_tag', $args);
+
+ return $tags;
+}
+
+/**
+ * Retrieve number of recent posts.
+ *
+ * @since 1.0.0
+ * @uses $wpdb
+ *
+ * @param int $num Optional, default is 10. Number of posts to get.
+ * @return array List of posts.
+ */
+function wp_get_recent_posts($num = 10) {
+ global $wpdb;
+
+ // Set the limit clause, if we got a limit
+ $num = (int) $num;
+ if ($num) {
+ $limit = "LIMIT $num";
+ }
+
+ $sql = "SELECT * FROM $wpdb->posts WHERE post_type = 'post' ORDER BY post_date DESC $limit";
+ $result = $wpdb->get_results($sql,ARRAY_A);
+
+ return $result ? $result : array();
+}
+
+/**
+ * Retrieve a single post, based on post ID.
+ *
+ * Has categories in 'post_category' property or key. Has tags in 'tags_input'
+ * property or key.
+ *
+ * @since 1.0.0
+ *
+ * @param int $postid Post ID.
+ * @param string $mode How to return result, either OBJECT, ARRAY_N, or ARRAY_A.
+ * @return object|array Post object or array holding post contents and information
+ */
+function wp_get_single_post($postid = 0, $mode = OBJECT) {
+ $postid = (int) $postid;
+
+ $post = get_post($postid, $mode);
+
+ // Set categories and tags
+ if($mode == OBJECT) {
+ $post->post_category = wp_get_post_categories($postid);
+ $post->tags_input = wp_get_post_tags($postid, array('fields' => 'names'));
+ }
+ else {
+ $post['post_category'] = wp_get_post_categories($postid);
+ $post['tags_input'] = wp_get_post_tags($postid, array('fields' => 'names'));
+ }
+
+ return $post;
+}
+
+/**
+ * Insert a post.
+ *
+ * If the $postarr parameter has 'ID' set to a value, then post will be updated.
+ *
+ * You can set the post date manually, but setting the values for 'post_date'
+ * and 'post_date_gmt' keys. You can close the comments or open the comments by
+ * setting the value for 'comment_status' key.
+ *
+ * The defaults for the parameter $postarr are:
+ * 'post_status' - Default is 'draft'.
+ * 'post_type' - Default is 'post'.
+ * 'post_author' - Default is current user ID. The ID of the user, who added
+ * the post.
+ * 'ping_status' - Default is the value in default ping status option.
+ * Whether the attachment can accept pings.
+ * 'post_parent' - Default is 0. Set this for the post it belongs to, if
+ * any.
+ * 'menu_order' - Default is 0. The order it is displayed.
+ * 'to_ping' - Whether to ping.
+ * 'pinged' - Default is empty string.
+ * 'post_password' - Default is empty string. The password to access the
+ * attachment.
+ * 'guid' - Global Unique ID for referencing the attachment.
+ * 'post_content_filtered' - Post content filtered.
+ * 'post_excerpt' - Post excerpt.
+ *
+ * @since 1.0.0
+ * @uses $wpdb
+ * @uses $wp_rewrite
+ * @uses $user_ID
+ *
+ * @param array $postarr Optional. Override defaults.
+ * @param bool $wp_error Optional. Allow return of WP_Error on failure.
+ * @return int|WP_Error The value 0 or WP_Error on failure. The post ID on success.
+ */
+function wp_insert_post($postarr = array(), $wp_error = false) {
+ global $wpdb, $wp_rewrite, $user_ID;
+
+ $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
+ 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
+ 'menu_order' => 0, 'to_ping' => '', 'pinged' => '', 'post_password' => '',
+ 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '', 'import_id' => 0);
+
+ $postarr = wp_parse_args($postarr, $defaults);
+ $postarr = sanitize_post($postarr, 'db');
+
+ // export array as variables
+ extract($postarr, EXTR_SKIP);
+
+ // Are we updating or creating?
+ $update = false;
+ if ( !empty($ID) ) {
+ $update = true;
+ $previous_status = get_post_field('post_status', $ID);
+ } else {
+ $previous_status = 'new';
+ }
+
+ if ( ('' == $post_content) && ('' == $post_title) && ('' == $post_excerpt) ) {
+ if ( $wp_error )
+ return new WP_Error('empty_content', __('Content, title, and excerpt are empty.'));
+ else
+ return 0;
+ }
+
+ // Make sure we set a valid category
+ if ( empty($post_category) || 0 == count($post_category) || !is_array($post_category) ) {
+ $post_category = array(get_option('default_category'));
+ }
+
+ //Set the default tag list
+ if ( !isset($tags_input) )
+ $tags_input = array();
+
+ if ( empty($post_author) )
+ $post_author = $user_ID;
+
+ if ( empty($post_status) )
+ $post_status = 'draft';
+
+ if ( empty($post_type) )
+ $post_type = 'post';
+
+ $post_ID = 0;
+
+ // Get the post ID and GUID
+ if ( $update ) {
+ $post_ID = (int) $ID;
+ $guid = get_post_field( 'guid', $post_ID );
+ }
+
+ // Don't allow contributors to set to set the post slug for pending review posts
+ if ( 'pending' == $post_status && !current_user_can( 'publish_posts' ) )
+ $post_name = '';
+
+ // Create a valid post name. Drafts and pending posts are allowed to have an empty
+ // post name.
+ if ( empty($post_name) ) {
+ if ( !in_array( $post_status, array( 'draft', 'pending' ) ) )
+ $post_name = sanitize_title($post_title);
+ } else {
+ $post_name = sanitize_title($post_name);
+ }
+
+ // If the post date is empty (due to having been new or a draft) and status is not 'draft' or 'pending', set date to now
+ if ( empty($post_date) || '0000-00-00 00:00:00' == $post_date )
+ $post_date = current_time('mysql');
+
+ if ( empty($post_date_gmt) || '0000-00-00 00:00:00' == $post_date_gmt ) {
+ if ( !in_array( $post_status, array( 'draft', 'pending' ) ) )
+ $post_date_gmt = get_gmt_from_date($post_date);
+ else
+ $post_date_gmt = '0000-00-00 00:00:00';
+ }
+
+ if ( $update || '0000-00-00 00:00:00' == $post_date ) {
+ $post_modified = current_time( 'mysql' );
+ $post_modified_gmt = current_time( 'mysql', 1 );
+ } else {
+ $post_modified = $post_date;
+ $post_modified_gmt = $post_date_gmt;
+ }
+
+ if ( 'publish' == $post_status ) {
+ $now = gmdate('Y-m-d H:i:59');
+ if ( mysql2date('U', $post_date_gmt) > mysql2date('U', $now) )
+ $post_status = 'future';
+ }
+
+ if ( empty($comment_status) ) {
+ if ( $update )
+ $comment_status = 'closed';
+ else
+ $comment_status = get_option('default_comment_status');
+ }
+ if ( empty($ping_status) )
+ $ping_status = get_option('default_ping_status');
+
+ if ( isset($to_ping) )
+ $to_ping = preg_replace('|\s+|', "\n", $to_ping);
+ else
+ $to_ping = '';
+
+ if ( ! isset($pinged) )
+ $pinged = '';
+
+ if ( isset($post_parent) )
+ $post_parent = (int) $post_parent;
+ else
+ $post_parent = 0;
+
+ if ( !empty($post_ID) ) {
+ if ( $post_parent == $post_ID ) {
+ // Post can't be its own parent
+ $post_parent = 0;
+ } elseif ( !empty($post_parent) ) {
+ $parent_post = get_post($post_parent);
+ // Check for circular dependency
+ if ( $parent_post->post_parent == $post_ID )
+ $post_parent = 0;
+ }
+ }
+
+ if ( isset($menu_order) )
+ $menu_order = (int) $menu_order;
+ else
+ $menu_order = 0;
+
+ if ( !isset($post_password) || 'private' == $post_status )
+ $post_password = '';
+
+ if ( !in_array( $post_status, array( 'draft', 'pending' ) ) ) {
+ $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d AND post_parent = %d LIMIT 1", $post_name, $post_type, $post_ID, $post_parent));
+
+ if ($post_name_check || in_array($post_name, $wp_rewrite->feeds) ) {
+ $suffix = 2;
+ do {
+ $alt_post_name = substr($post_name, 0, 200-(strlen($suffix)+1)). "-$suffix";
+ $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d AND post_parent = %d LIMIT 1", $alt_post_name, $post_type, $post_ID, $post_parent));
+ $suffix++;
+ } while ($post_name_check);
+ $post_name = $alt_post_name;
+ }
+ }
+
+ // expected_slashed (everything!)
+ $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'guid' ) );
+ $data = apply_filters('wp_insert_post_data', $data, $postarr);
+ $data = stripslashes_deep( $data );
+ $where = array( 'ID' => $post_ID );
+
+ if ($update) {
+ do_action( 'pre_post_update', $post_ID );
+ if ( false === $wpdb->update( $wpdb->posts, $data, $where ) ) {
+ if ( $wp_error )
+ return new WP_Error('db_update_error', __('Could not update post in the database'), $wpdb->last_error);
+ else
+ return 0;
+ }
+ } else {
+ if ( isset($post_mime_type) )
+ $data['post_mime_type'] = stripslashes( $post_mime_type ); // This isn't in the update
+ // If there is a suggested ID, use it if not already present
+ if ( !empty($import_id) ) {
+ $import_id = (int) $import_id;
+ if ( ! $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE ID = %d", $import_id) ) ) {
+ $data['ID'] = $import_id;
+ }
+ }
+ if ( false === $wpdb->insert( $wpdb->posts, $data ) ) {
+ if ( $wp_error )
+ return new WP_Error('db_insert_error', __('Could not insert post into the database'), $wpdb->last_error);
+ else
+ return 0;
+ }
+ $post_ID = (int) $wpdb->insert_id;
+
+ // use the newly generated $post_ID
+ $where = array( 'ID' => $post_ID );
+ }
+
+ if ( empty($post_name) && !in_array( $post_status, array( 'draft', 'pending' ) ) ) {
+ $post_name = sanitize_title($post_title, $post_ID);
+ $wpdb->update( $wpdb->posts, compact( 'post_name' ), $where );
+ }
+
+ wp_set_post_categories( $post_ID, $post_category );
+ wp_set_post_tags( $post_ID, $tags_input );
+
+ $current_guid = get_post_field( 'guid', $post_ID );
+
+ if ( 'page' == $post_type )
+ clean_page_cache($post_ID);
+ else
+ clean_post_cache($post_ID);
+
+ // Set GUID
+ if ( !$update && '' == $current_guid )
+ $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
+
+ $post = get_post($post_ID);
+
+ if ( !empty($page_template) && 'page' == $post_type ) {
+ $post->page_template = $page_template;
+ $page_templates = get_page_templates();
+ if ( 'default' != $page_template && !in_array($page_template, $page_templates) ) {
+ if ( $wp_error )
+ return new WP_Error('invalid_page_template', __('The page template is invalid.'));
+ else
+ return 0;
+ }
+ update_post_meta($post_ID, '_wp_page_template', $page_template);
+ }
+
+ wp_transition_post_status($post_status, $previous_status, $post);
+
+ if ( $update)
+ do_action('edit_post', $post_ID, $post);
+
+ do_action('save_post', $post_ID, $post);
+ do_action('wp_insert_post', $post_ID, $post);
+
+ return $post_ID;
+}
+
+/**
+ * Update a post with new post data.
+ *
+ * The date does not have to be set for drafts. You can set the date and it will
+ * not be overridden.
+ *
+ * @since 1.0.0
+ *
+ * @param array|object $postarr Post data.
+ * @return int 0 on failure, Post ID on success.
+ */
+function wp_update_post($postarr = array()) {
+ if ( is_object($postarr) )
+ $postarr = get_object_vars($postarr);
+
+ // First, get all of the original fields
+ $post = wp_get_single_post($postarr['ID'], ARRAY_A);
+
+ // Escape data pulled from DB.
+ $post = add_magic_quotes($post);
+
+ // Passed post category list overwrites existing category list if not empty.
+ if ( isset($postarr['post_category']) && is_array($postarr['post_category'])
+ && 0 != count($postarr['post_category']) )
+ $post_cats = $postarr['post_category'];
+ else
+ $post_cats = $post['post_category'];
+
+ // Drafts shouldn't be assigned a date unless explicitly done so by the user
+ if ( in_array($post['post_status'], array('draft', 'pending')) && empty($postarr['edit_date']) &&
+ ('0000-00-00 00:00:00' == $post['post_date_gmt']) )
+ $clear_date = true;
+ else
+ $clear_date = false;
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $postarr = array_merge($post, $postarr);
+ $postarr['post_category'] = $post_cats;
+ if ( $clear_date ) {
+ $postarr['post_date'] = current_time('mysql');
+ $postarr['post_date_gmt'] = '';
+ }
+
+ if ($postarr['post_type'] == 'attachment')
+ return wp_insert_attachment($postarr);
+
+ return wp_insert_post($postarr);
+}
+
+/**
+ * Publish a post by transitioning the post status.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ * @uses do_action() Calls 'edit_post', 'save_post', and 'wp_insert_post' on post_id and post data.
+ *
+ * @param int $post_id Post ID.
+ * @return null
+ */
+function wp_publish_post($post_id) {
+ global $wpdb;
+
+ $post = get_post($post_id);
+
+ if ( empty($post) )
+ return;
+
+ if ( 'publish' == $post->post_status )
+ return;
+
+ $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post_id ) );
+
+ $old_status = $post->post_status;
+ $post->post_status = 'publish';
+ wp_transition_post_status('publish', $old_status, $post);
+
+ // Update counts for the post's terms.
+ foreach ( (array) get_object_taxonomies('post') as $taxonomy ) {
+ $tt_ids = wp_get_object_terms($post_id, $taxonomy, 'fields=tt_ids');
+ wp_update_term_count($tt_ids, $taxonomy);
+ }
+
+ do_action('edit_post', $post_id, $post);
+ do_action('save_post', $post_id, $post);
+ do_action('wp_insert_post', $post_id, $post);
+}
+
+/**
+ * Publish future post and make sure post ID has future post status.
+ *
+ * Invoked by cron 'publish_future_post' event. This safeguard prevents cron
+ * from publishing drafts, etc.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Post ID.
+ * @return null Nothing is returned. Which can mean that no action is required or post was published.
+ */
+function check_and_publish_future_post($post_id) {
+
+ $post = get_post($post_id);
+
+ if ( empty($post) )
+ return;
+
+ if ( 'future' != $post->post_status )
+ return;
+
+ $time = strtotime( $post->post_date_gmt . ' GMT' );
+
+ if ( $time > time() ) { // Uh oh, someone jumped the gun!
+ wp_clear_scheduled_hook( 'publish_future_post', $post_id ); // clear anything else in the system
+ wp_schedule_single_event( $time, 'publish_future_post', array( $post_id ) );
+ return;
+ }
+
+ return wp_publish_post($post_id);
+}
+
+/**
+ * Adds tags to a post.
+ *
+ * @uses wp_set_post_tags() Same first two parameters, but the last parameter is always set to true.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.3.0
+ *
+ * @param int $post_id Post ID
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @return bool|null Will return false if $post_id is not an integer or is 0. Will return null otherwise
+ */
+function wp_add_post_tags($post_id = 0, $tags = '') {
+ return wp_set_post_tags($post_id, $tags, true);
+}
+
+
+/**
+ * Set the tags for a post.
+ *
+ * @since 2.3.0
+ * @uses wp_set_object_terms() Sets the tags for the post.
+ *
+ * @param int $post_id Post ID.
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @param bool $append If true, don't delete existing tags, just add on. If false, replace the tags with the new tags.
+ * @return bool|null Will return false if $post_id is not an integer or is 0. Will return null otherwise
+ */
+function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
+
+ $post_id = (int) $post_id;
+
+ if ( !$post_id )
+ return false;
+
+ if ( empty($tags) )
+ $tags = array();
+ $tags = (is_array($tags)) ? $tags : explode( ',', trim($tags, " \n\t\r\0\x0B,") );
+ wp_set_object_terms($post_id, $tags, 'post_tag', $append);
+}
+
+/**
+ * Set categories for a post.
+ *
+ * If the post categories parameter is not set, then the default category is
+ * going used.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_ID Post ID.
+ * @param array $post_categories Optional. List of categories.
+ * @return bool|mixed
+ */
+function wp_set_post_categories($post_ID = 0, $post_categories = array()) {
+ $post_ID = (int) $post_ID;
+ // If $post_categories isn't already an array, make it one:
+ if (!is_array($post_categories) || 0 == count($post_categories) || empty($post_categories))
+ $post_categories = array(get_option('default_category'));
+ else if ( 1 == count($post_categories) && '' == $post_categories[0] )
+ return true;
+
+ $post_categories = array_map('intval', $post_categories);
+ $post_categories = array_unique($post_categories);
+
+ return wp_set_object_terms($post_ID, $post_categories, 'category');
+}
+
+/**
+ * Transition the post status of a post.
+ *
+ * Calls hooks to transition post status. If the new post status is not the same
+ * as the previous post status, then two hooks will be ran, the first is
+ * 'transition_post_status' with new status, old status, and post data. The
+ * next action called is 'OLDSTATUS_to_NEWSTATUS' the NEWSTATUS is the
+ * $new_status parameter and the OLDSTATUS is $old_status parameter; it has the
+ * post data.
+ *
+ * The final action will run whether or not the post statuses are the same. The
+ * action is named 'NEWSTATUS_POSTTYPE', NEWSTATUS is from the $new_status
+ * parameter and POSTTYPE is post_type post data.
+ *
+ * @since 2.3.0
+ *
+ * @param string $new_status Transition to this post status.
+ * @param string $old_status Previous post status.
+ * @param object $post Post data.
+ */
+function wp_transition_post_status($new_status, $old_status, $post) {
+ if ( $new_status != $old_status ) {
+ do_action('transition_post_status', $new_status, $old_status, $post);
+ do_action("${old_status}_to_$new_status", $post);
+ }
+ do_action("${new_status}_$post->post_type", $post->ID, $post);
+}
+
+//
+// Trackback and ping functions
+//
+
+/**
+ * Add a URL to those already pung.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @param string $uri Ping URI.
+ * @return int How many rows were updated.
+ */
+function add_ping($post_id, $uri) {
+ global $wpdb;
+ $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $pung = trim($pung);
+ $pung = preg_split('/\s/', $pung);
+ $pung[] = $uri;
+ $new = implode("\n", $pung);
+ $new = apply_filters('add_ping', $new);
+ // expected_slashed ($new)
+ $new = stripslashes($new);
+ return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
+}
+
+/**
+ * Retrieve enclosures already enclosed for a post.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @return array List of enclosures
+ */
+function get_enclosed($post_id) {
+ $custom_fields = get_post_custom( $post_id );
+ $pung = array();
+ if ( !is_array( $custom_fields ) )
+ return $pung;
+
+ foreach ( $custom_fields as $key => $val ) {
+ if ( 'enclosure' != $key || !is_array( $val ) )
+ continue;
+ foreach( $val as $enc ) {
+ $enclosure = split( "\n", $enc );
+ $pung[] = trim( $enclosure[ 0 ] );
+ }
+ }
+ $pung = apply_filters('get_enclosed', $pung);
+ return $pung;
+}
+
+/**
+ * Retrieve URLs already pinged for a post.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @return array
+ */
+function get_pung($post_id) {
+ global $wpdb;
+ $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $pung = trim($pung);
+ $pung = preg_split('/\s/', $pung);
+ $pung = apply_filters('get_pung', $pung);
+ return $pung;
+}
+
+/**
+ * Retrieve URLs that need to be pinged.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID
+ * @return array
+ */
+function get_to_ping($post_id) {
+ global $wpdb;
+ $to_ping = $wpdb->get_var( $wpdb->prepare( "SELECT to_ping FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $to_ping = trim($to_ping);
+ $to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
+ $to_ping = apply_filters('get_to_ping', $to_ping);
+ return $to_ping;
+}
+
+/**
+ * Do trackbacks for a list of URLs.
+ *
+ * @since 1.0.0
+ *
+ * @param string $tb_list Comma separated list of URLs
+ * @param int $post_id Post ID
+ */
+function trackback_url_list($tb_list, $post_id) {
+ if ( ! empty( $tb_list ) ) {
+ // get post data
+ $postdata = wp_get_single_post($post_id, ARRAY_A);
+
+ // import postdata as variables
+ extract($postdata, EXTR_SKIP);
+
+ // form an excerpt
+ $excerpt = strip_tags($post_excerpt ? $post_excerpt : $post_content);
+
+ if (strlen($excerpt) > 255) {
+ $excerpt = substr($excerpt,0,252) . '...';
+ }
+
+ $trackback_urls = explode(',', $tb_list);
+ foreach( (array) $trackback_urls as $tb_url) {
+ $tb_url = trim($tb_url);
+ trackback($tb_url, stripslashes($post_title), $excerpt, $post_id);
+ }
+ }
+}
+
+//
+// Page functions
+//
+
+/**
+ * Get a list of page IDs.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @return array List of page IDs.
+ */
+function get_all_page_ids() {
+ global $wpdb;
+
+ if ( ! $page_ids = wp_cache_get('all_page_ids', 'posts') ) {
+ $page_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE post_type = 'page'");
+ wp_cache_add('all_page_ids', $page_ids, 'posts');
+ }
+
+ return $page_ids;
+}
+
+/**
+ * Retrieves page data given a page ID or page object.
+ *
+ * @since 1.5.1
+ *
+ * @param mixed $page Page object or page ID. Passed by reference.
+ * @param string $output What to output. OBJECT, ARRAY_A, or ARRAY_N.
+ * @param string $filter How the return value should be filtered.
+ * @return mixed Page data.
+ */
+function &get_page(&$page, $output = OBJECT, $filter = 'raw') {
+ if ( empty($page) ) {
+ if ( isset( $GLOBALS['page'] ) && isset( $GLOBALS['page']->ID ) ) {
+ return get_post($GLOBALS['page'], $output, $filter);
+ } else {
+ $page = null;
+ return $page;
+ }
+ }
+
+ $the_page = get_post($page, $output, $filter);
+ return $the_page;
+}
+
+/**
+ * Retrieves a page given its path.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $page_path Page path
+ * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A.
+ * @return mixed Null when complete.
+ */
+function get_page_by_path($page_path, $output = OBJECT) {
+ global $wpdb;
+ $page_path = rawurlencode(urldecode($page_path));
+ $page_path = str_replace('%2F', '/', $page_path);
+ $page_path = str_replace('%20', ' ', $page_path);
+ $page_paths = '/' . trim($page_path, '/');
+ $leaf_path = sanitize_title(basename($page_paths));
+ $page_paths = explode('/', $page_paths);
+ $full_path = '';
+ foreach( (array) $page_paths as $pathdir)
+ $full_path .= ($pathdir!=''?'/':'') . sanitize_title($pathdir);
+
+ $pages = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_name = %s AND (post_type = 'page' OR post_type = 'attachment')", $leaf_path ));
+
+ if ( empty($pages) )
+ return null;
+
+ foreach ($pages as $page) {
+ $path = '/' . $leaf_path;
+ $curpage = $page;
+ while ($curpage->post_parent != 0) {
+ $curpage = $wpdb->get_row( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE ID = %d and post_type='page'", $curpage->post_parent ));
+ $path = '/' . $curpage->post_name . $path;
+ }
+
+ if ( $path == $full_path )
+ return get_page($page->ID, $output);
+ }
+
+ return null;
+}
+
+/**
+ * Retrieve a page given its title.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $page_title Page title
+ * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A.
+ * @return mixed
+ */
+function get_page_by_title($page_title, $output = OBJECT) {
+ global $wpdb;
+ $page = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type='page'", $page_title ));
+ if ( $page )
+ return get_page($page, $output);
+
+ return null;
+}
+
+/**
+ * Retrieve child pages from list of pages matching page ID.
+ *
+ * Matches against the pages parameter against the page ID. Also matches all
+ * children for the same to retrieve all children of a page. Does not make any
+ * SQL queries to get the children.
+ *
+ * @since 1.5.1
+ *
+ * @param int $page_id Page ID.
+ * @param array $pages List of pages' objects.
+ * @return array
+ */
+function &get_page_children($page_id, $pages) {
+ $page_list = array();
+ foreach ( (array) $pages as $page ) {
+ if ( $page->post_parent == $page_id ) {
+ $page_list[] = $page;
+ if ( $children = get_page_children($page->ID, $pages) )
+ $page_list = array_merge($page_list, $children);
+ }
+ }
+ return $page_list;
+}
+
+/**
+ * Order the pages with children under parents in a flat list.
+ *
+ * Fetches the pages returned as a FLAT list, but arranged in order of their
+ * hierarchy, i.e., child parents immediately follow their parents.
+ *
+ * @since 2.0.0
+ *
+ * @param array $posts Posts array.
+ * @param int $parent Parent page ID.
+ * @return array
+ */
+function get_page_hierarchy($posts, $parent = 0) {
+ $result = array ( );
+ if ($posts) { foreach ( (array) $posts as $post) {
+ if ($post->post_parent == $parent) {
+ $result[$post->ID] = $post->post_name;
+ $children = get_page_hierarchy($posts, $post->ID);
+ $result += $children; //append $children to $result
+ }
+ } }
+ return $result;
+}
+
+/**
+ * Builds URI for a page.
+ *
+ * Sub pages will be in the "directory" under the parent page post name.
+ *
+ * @since 1.5.0
+ *
+ * @param int $page_id Page ID.
+ * @return string Page URI.
+ */
+function get_page_uri($page_id) {
+ $page = get_page($page_id);
+ $uri = $page->post_name;
+
+ // A page cannot be it's own parent.
+ if ( $page->post_parent == $page->ID )
+ return $uri;
+
+ while ($page->post_parent != 0) {
+ $page = get_page($page->post_parent);
+ $uri = $page->post_name . "/" . $uri;
+ }
+
+ return $uri;
+}
+
+/**
+ * Retrieve a list of pages.
+ *
+ * The defaults that can be overridden are the following: 'child_of',
+ * 'sort_order', 'sort_column', 'post_title', 'hierarchical', 'exclude',
+ * 'include', 'meta_key', 'meta_value', and 'authors'.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param mixed $args Optional. Array or string of options that overrides defaults.
+ * @return array List of pages matching defaults or $args
+ */
+function &get_pages($args = '') {
+ global $wpdb;
+
+ $defaults = array(
+ 'child_of' => 0, 'sort_order' => 'ASC',
+ 'sort_column' => 'post_title', 'hierarchical' => 1,
+ 'exclude' => '', 'include' => '',
+ 'meta_key' => '', 'meta_value' => '',
+ 'authors' => '', 'parent' => -1, 'exclude_tree' => ''
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $key = md5( serialize( compact(array_keys($defaults)) ) );
+ if ( $cache = wp_cache_get( 'get_pages', 'posts' ) ) {
+ if ( isset( $cache[ $key ] ) ) {
+ $pages = apply_filters('get_pages', $cache[ $key ], $r );
+ return $pages;
+ }
+ }
+
+ $inclusions = '';
+ if ( !empty($include) ) {
+ $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include
+ $parent = -1;
+ $exclude = '';
+ $meta_key = '';
+ $meta_value = '';
+ $hierarchical = false;
+ $incpages = preg_split('/[\s,]+/',$include);
+ if ( count($incpages) ) {
+ foreach ( $incpages as $incpage ) {
+ if (empty($inclusions))
+ $inclusions = $wpdb->prepare(' AND ( ID = %d ', $incpage);
+ else
+ $inclusions .= $wpdb->prepare(' OR ID = %d ', $incpage);
+ }
+ }
+ }
+ if (!empty($inclusions))
+ $inclusions .= ')';
+
+ $exclusions = '';
+ if ( !empty($exclude) ) {
+ $expages = preg_split('/[\s,]+/',$exclude);
+ if ( count($expages) ) {
+ foreach ( $expages as $expage ) {
+ if (empty($exclusions))
+ $exclusions = $wpdb->prepare(' AND ( ID <> %d ', $expage);
+ else
+ $exclusions .= $wpdb->prepare(' AND ID <> %d ', $expage);
+ }
+ }
+ }
+ if (!empty($exclusions))
+ $exclusions .= ')';
+
+ $author_query = '';
+ if (!empty($authors)) {
+ $post_authors = preg_split('/[\s,]+/',$authors);
+
+ if ( count($post_authors) ) {
+ foreach ( $post_authors as $post_author ) {
+ //Do we have an author id or an author login?
+ if ( 0 == intval($post_author) ) {
+ $post_author = get_userdatabylogin($post_author);
+ if ( empty($post_author) )
+ continue;
+ if ( empty($post_author->ID) )
+ continue;
+ $post_author = $post_author->ID;
+ }
+
+ if ( '' == $author_query )
+ $author_query = $wpdb->prepare(' post_author = %d ', $post_author);
+ else
+ $author_query .= $wpdb->prepare(' OR post_author = %d ', $post_author);
+ }
+ if ( '' != $author_query )
+ $author_query = " AND ($author_query)";
+ }
+ }
+
+ $join = '';
+ $where = "$exclusions $inclusions ";
+ if ( ! empty( $meta_key ) || ! empty( $meta_value ) ) {
+ $join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )";
+
+ // meta_key and meta_value might be slashed
+ $meta_key = stripslashes($meta_key);
+ $meta_value = stripslashes($meta_value);
+ if ( ! empty( $meta_key ) )
+ $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $meta_key);
+ if ( ! empty( $meta_value ) )
+ $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $meta_value);
+
+ }
+
+ if ( $parent >= 0 )
+ $where .= $wpdb->prepare(' AND post_parent = %d ', $parent);
+
+ $query = "SELECT * FROM $wpdb->posts $join WHERE (post_type = 'page' AND post_status = 'publish') $where ";
+ $query .= $author_query;
+ $query .= " ORDER BY " . $sort_column . " " . $sort_order ;
+
+ $pages = $wpdb->get_results($query);
+
+ if ( empty($pages) ) {
+ $pages = apply_filters('get_pages', array(), $r);
+ return $pages;
+ }
+
+ // Update cache.
+ update_page_cache($pages);
+
+ if ( $child_of || $hierarchical )
+ $pages = & get_page_children($child_of, $pages);
+
+ if ( !empty($exclude_tree) ) {
+ $exclude = array();
+
+ $exclude = (int) $exclude_tree;
+ $children = get_page_children($exclude, $pages);
+ $excludes = array();
+ foreach ( $children as $child )
+ $excludes[] = $child->ID;
+ $excludes[] = $exclude;
+ $total = count($pages);
+ for ( $i = 0; $i < $total; $i++ ) {
+ if ( in_array($pages[$i]->ID, $excludes) )
+ unset($pages[$i]);
+ }
+ }
+
+ $cache[ $key ] = $pages;
+ wp_cache_set( 'get_pages', $cache, 'posts' );
+
+ $pages = apply_filters('get_pages', $pages, $r);
+
+ return $pages;
+}
+
+//
+// Attachment functions
+//
+
+/**
+ * Check if the attachment URI is local one and is really an attachment.
+ *
+ * @since 2.0.0
+ *
+ * @param string $url URL to check
+ * @return bool True on success, false on failure.
+ */
+function is_local_attachment($url) {
+ if (strpos($url, get_bloginfo('url')) === false)
+ return false;
+ if (strpos($url, get_bloginfo('url') . '/?attachment_id=') !== false)
+ return true;
+ if ( $id = url_to_postid($url) ) {
+ $post = & get_post($id);
+ if ( 'attachment' == $post->post_type )
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Insert an attachment.
+ *
+ * If you set the 'ID' in the $object parameter, it will mean that you are
+ * updating and attempt to update the attachment. You can also set the
+ * attachment name or title by setting the key 'post_name' or 'post_title'.
+ *
+ * You can set the dates for the attachment manually by setting the 'post_date'
+ * and 'post_date_gmt' keys' values.
+ *
+ * By default, the comments will use the default settings for whether the
+ * comments are allowed. You can close them manually or keep them open by
+ * setting the value for the 'comment_status' key.
+ *
+ * The $object parameter can have the following:
+ * 'post_status' - Default is 'draft'. Can not be override, set the same as
+ * parent post.
+ * 'post_type' - Default is 'post', will be set to attachment. Can not
+ * override.
+ * 'post_author' - Default is current user ID. The ID of the user, who added
+ * the attachment.
+ * 'ping_status' - Default is the value in default ping status option.
+ * Whether the attachment can accept pings.
+ * 'post_parent' - Default is 0. Can use $parent parameter or set this for
+ * the post it belongs to, if any.
+ * 'menu_order' - Default is 0. The order it is displayed.
+ * 'to_ping' - Whether to ping.
+ * 'pinged' - Default is empty string.
+ * 'post_password' - Default is empty string. The password to access the
+ * attachment.
+ * 'guid' - Global Unique ID for referencing the attachment.
+ * 'post_content_filtered' - Attachment post content filtered.
+ * 'post_excerpt' - Attachment excerpt.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses $user_ID
+ *
+ * @param string|array $object Arguments to override defaults.
+ * @param string $file Optional filename.
+ * @param int $post_parent Parent post ID.
+ * @return int Attachment ID.
+ */
+function wp_insert_attachment($object, $file = false, $parent = 0) {
+ global $wpdb, $user_ID;
+
+ $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
+ 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
+ 'menu_order' => 0, 'to_ping' => '', 'pinged' => '', 'post_password' => '',
+ 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '', 'import_id' => 0);
+
+ $object = wp_parse_args($object, $defaults);
+ if ( !empty($parent) )
+ $object['post_parent'] = $parent;
+
+ $object = sanitize_post($object, 'db');
+
+ // export array as variables
+ extract($object, EXTR_SKIP);
+
+ // Make sure we set a valid category
+ if ( !isset($post_category) || 0 == count($post_category) || !is_array($post_category)) {
+ $post_category = array(get_option('default_category'));
+ }
+
+ if ( empty($post_author) )
+ $post_author = $user_ID;
+
+ $post_type = 'attachment';
+ $post_status = 'inherit';
+
+ // Are we updating or creating?
+ if ( !empty($ID) ) {
+ $update = true;
+ $post_ID = (int) $ID;
+ } else {
+ $update = false;
+ $post_ID = 0;
+ }
+
+ // Create a valid post name.
+ if ( empty($post_name) )
+ $post_name = sanitize_title($post_title);
+ else
+ $post_name = sanitize_title($post_name);
+
+ // expected_slashed ($post_name)
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_status = 'inherit' AND ID != %d LIMIT 1", $post_name, $post_ID));
+
+ if ($post_name_check) {
+ $suffix = 2;
+ while ($post_name_check) {
+ $alt_post_name = $post_name . "-$suffix";
+ // expected_slashed ($alt_post_name, $post_name)
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_status = 'inherit' AND ID != %d AND post_parent = %d LIMIT 1", $alt_post_name, $post_ID, $post_parent));
+ $suffix++;
+ }
+ $post_name = $alt_post_name;
+ }
+
+ if ( empty($post_date) )
+ $post_date = current_time('mysql');
+ if ( empty($post_date_gmt) )
+ $post_date_gmt = current_time('mysql', 1);
+
+ if ( empty($post_modified) )
+ $post_modified = $post_date;
+ if ( empty($post_modified_gmt) )
+ $post_modified_gmt = $post_date_gmt;
+
+ if ( empty($comment_status) ) {
+ if ( $update )
+ $comment_status = 'closed';
+ else
+ $comment_status = get_option('default_comment_status');
+ }
+ if ( empty($ping_status) )
+ $ping_status = get_option('default_ping_status');
+
+ if ( isset($to_ping) )
+ $to_ping = preg_replace('|\s+|', "\n", $to_ping);
+ else
+ $to_ping = '';
+
+ if ( isset($post_parent) )
+ $post_parent = (int) $post_parent;
+ else
+ $post_parent = 0;
+
+ if ( isset($menu_order) )
+ $menu_order = (int) $menu_order;
+ else
+ $menu_order = 0;
+
+ if ( !isset($post_password) )
+ $post_password = '';
+
+ if ( ! isset($pinged) )
+ $pinged = '';
+
+ // expected_slashed (everything!)
+ $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' ) );
+ $data = stripslashes_deep( $data );
+
+ if ( $update ) {
+ $wpdb->update( $wpdb->posts, $data, array( 'ID' => $post_ID ) );
+ } else {
+ // If there is a suggested ID, use it if not already present
+ if ( !empty($import_id) ) {
+ $import_id = (int) $import_id;
+ if ( ! $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE ID = %d", $import_id) ) ) {
+ $data['ID'] = $import_id;
+ }
+ }
+
+ $wpdb->insert( $wpdb->posts, $data );
+ $post_ID = (int) $wpdb->insert_id;
+ }
+
+ if ( empty($post_name) ) {
+ $post_name = sanitize_title($post_title, $post_ID);
+ $wpdb->update( $wpdb->posts, compact("post_name"), array( 'ID' => $post_ID ) );
+ }
+
+ wp_set_post_categories($post_ID, $post_category);
+
+ if ( $file )
+ update_attached_file( $post_ID, $file );
+
+ clean_post_cache($post_ID);
+
+ if ( $update) {
+ do_action('edit_attachment', $post_ID);
+ } else {
+ do_action('add_attachment', $post_ID);
+ }
+
+ return $post_ID;
+}
+
+/**
+ * Delete an attachment.
+ *
+ * Will remove the file also, when the attachment is removed. Removes all post
+ * meta fields, taxonomy, comments, etc associated with the attachment (except
+ * the main post).
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses do_action() Calls 'delete_attachment' hook on Attachment ID.
+ *
+ * @param int $postid Attachment ID.
+ * @return mixed False on failure. Post data on success.
+ */
+function wp_delete_attachment($postid) {
+ global $wpdb;
+
+ if ( !$post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
+ return $post;
+
+ if ( 'attachment' != $post->post_type )
+ return false;
+
+ $meta = wp_get_attachment_metadata( $postid );
+ $file = get_attached_file( $postid );
+
+ /** @todo Delete for pluggable post taxonomies too */
+ wp_delete_object_term_relationships($postid, array('category', 'post_tag'));
+
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->posts WHERE ID = %d", $postid ));
+
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
+
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
+
+ $uploadPath = wp_upload_dir();
+
+ if ( ! empty($meta['thumb']) ) {
+ // Don't delete the thumb if another attachment uses it
+ if (! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%'.$meta['thumb'].'%', $postid)) ) {
+ $thumbfile = str_replace(basename($file), $meta['thumb'], $file);
+ $thumbfile = apply_filters('wp_delete_file', $thumbfile);
+ @ unlink( path_join($uploadPath['basedir'], $thumbfile) );
+ }
+ }
+
+ // remove intermediate images if there are any
+ $sizes = apply_filters('intermediate_image_sizes', array('thumbnail', 'medium', 'large'));
+ foreach ( $sizes as $size ) {
+ if ( $intermediate = image_get_intermediate_size($postid, $size) ) {
+ $intermediate_file = apply_filters('wp_delete_file', $intermediate['path']);
+ @ unlink( path_join($uploadPath['basedir'], $intermediate_file) );
+ }
+ }
+
+ $file = apply_filters('wp_delete_file', $file);
+
+ if ( ! empty($file) )
+ @ unlink($file);
+
+ clean_post_cache($postid);
+
+ do_action('delete_attachment', $postid);
+
+ return $post;
+}
+
+/**
+ * Retrieve attachment meta field for attachment ID.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID
+ * @param bool $unfiltered Optional, default is false. If true, filters are not run.
+ * @return string|bool Attachment meta field. False on failure.
+ */
+function wp_get_attachment_metadata( $post_id, $unfiltered = false ) {
+ $post_id = (int) $post_id;
+ if ( !$post =& get_post( $post_id ) )
+ return false;
+
+ $data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
+ if ( $unfiltered )
+ return $data;
+ return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
+}
+
+/**
+ * Update metadata for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID.
+ * @param array $data Attachment data.
+ * @return int
+ */
+function wp_update_attachment_metadata( $post_id, $data ) {
+ $post_id = (int) $post_id;
+ if ( !$post =& get_post( $post_id ) )
+ return false;
+
+ $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID );
+
+ return update_post_meta( $post->ID, '_wp_attachment_metadata', $data);
+}
+
+/**
+ * Retrieve the URL for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID.
+ * @return string
+ */
+function wp_get_attachment_url( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post =& get_post( $post_id ) )
+ return false;
+
+ $url = '';
+ if ( $file = get_post_meta( $post->ID, '_wp_attached_file', true) ) { //Get attached file
+ if ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) { //Get upload directory
+ if ( 0 === strpos($file, $uploads['basedir']) ) //Check that the upload base exists in the file location
+ $url = str_replace($uploads['basedir'], $uploads['baseurl'], $file); //replace file location with url location
+ }
+ }
+
+ if ( empty($url) ) //If any of the above options failed, Fallback on the GUID as used pre-2.7, not recomended to rely upon this.
+ $url = get_the_guid( $post->ID );
+
+ if ( 'attachment' != $post->post_type || empty($url) )
+ return false;
+
+ return apply_filters( 'wp_get_attachment_url', $url, $post->ID );
+}
+
+/**
+ * Retrieve thumbnail for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID.
+ * @return mixed False on failure. Thumbnail file path on success.
+ */
+function wp_get_attachment_thumb_file( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post =& get_post( $post_id ) )
+ return false;
+ if ( !is_array( $imagedata = wp_get_attachment_metadata( $post->ID ) ) )
+ return false;
+
+ $file = get_attached_file( $post->ID );
+
+ if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) )
+ return apply_filters( 'wp_get_attachment_thumb_file', $thumbfile, $post->ID );
+ return false;
+}
+
+/**
+ * Retrieve URL for an attachment thumbnail.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID
+ * @return string|bool False on failure. Thumbnail URL on success.
+ */
+function wp_get_attachment_thumb_url( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post =& get_post( $post_id ) )
+ return false;
+ if ( !$url = wp_get_attachment_url( $post->ID ) )
+ return false;
+
+ $sized = image_downsize( $post_id, 'thumbnail' );
+ if ( $sized )
+ return $sized[0];
+
+ if ( !$thumb = wp_get_attachment_thumb_file( $post->ID ) )
+ return false;
+
+ $url = str_replace(basename($url), basename($thumb), $url);
+
+ return apply_filters( 'wp_get_attachment_thumb_url', $url, $post->ID );
+}
+
+/**
+ * Check if the attachment is an image.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID
+ * @return bool
+ */
+function wp_attachment_is_image( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post =& get_post( $post_id ) )
+ return false;
+
+ if ( !$file = get_attached_file( $post->ID ) )
+ return false;
+
+ $ext = preg_match('/\.([^.]+)$/', $file, $matches) ? strtolower($matches[1]) : false;
+
+ $image_exts = array('jpg', 'jpeg', 'gif', 'png');
+
+ if ( 'image/' == substr($post->post_mime_type, 0, 6) || $ext && 'import' == $post->post_mime_type && in_array($ext, $image_exts) )
+ return true;
+ return false;
+}
+
+/**
+ * Retrieve the icon for a MIME type.
+ *
+ * @since 2.1.0
+ *
+ * @param string $mime MIME type
+ * @return string|bool
+ */
+function wp_mime_type_icon( $mime = 0 ) {
+ if ( !is_numeric($mime) )
+ $icon = wp_cache_get("mime_type_icon_$mime");
+ if ( empty($icon) ) {
+ $post_id = 0;
+ $post_mimes = array();
+ if ( is_numeric($mime) ) {
+ $mime = (int) $mime;
+ if ( $post =& get_post( $mime ) ) {
+ $post_id = (int) $post->ID;
+ $ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $post->guid);
+ if ( !empty($ext) ) {
+ $post_mimes[] = $ext;
+ if ( $ext_type = wp_ext2type( $ext ) )
+ $post_mimes[] = $ext_type;
+ }
+ $mime = $post->post_mime_type;
+ } else {
+ $mime = 0;
+ }
+ } else {
+ $post_mimes[] = $mime;
+ }
+
+ $icon_files = wp_cache_get('icon_files');
+
+ if ( !is_array($icon_files) ) {
+ $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' );
+ $icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url('images/crystal') );
+ $dirs = apply_filters( 'icon_dirs', array($icon_dir => $icon_dir_uri) );
+ $icon_files = array();
+ while ( $dirs ) {
+ $dir = array_shift($keys = array_keys($dirs));
+ $uri = array_shift($dirs);
+ if ( $dh = opendir($dir) ) {
+ while ( false !== $file = readdir($dh) ) {
+ $file = basename($file);
+ if ( substr($file, 0, 1) == '.' )
+ continue;
+ if ( !in_array(strtolower(substr($file, -4)), array('.png', '.gif', '.jpg') ) ) {
+ if ( is_dir("$dir/$file") )
+ $dirs["$dir/$file"] = "$uri/$file";
+ continue;
+ }
+ $icon_files["$dir/$file"] = "$uri/$file";
+ }
+ closedir($dh);
+ }
+ }
+ wp_cache_set('icon_files', $icon_files, 600);
+ }
+
+ // Icon basename - extension = MIME wildcard
+ foreach ( $icon_files as $file => $uri )
+ $types[ preg_replace('/^([^.]*).*$/', '$1', basename($file)) ] =& $icon_files[$file];
+
+ if ( ! empty($mime) ) {
+ $post_mimes[] = substr($mime, 0, strpos($mime, '/'));
+ $post_mimes[] = substr($mime, strpos($mime, '/') + 1);
+ $post_mimes[] = str_replace('/', '_', $mime);
+ }
+
+ $matches = wp_match_mime_types(array_keys($types), $post_mimes);
+ $matches['default'] = array('default');
+
+ foreach ( $matches as $match => $wilds ) {
+ if ( isset($types[$wilds[0]])) {
+ $icon = $types[$wilds[0]];
+ if ( !is_numeric($mime) )
+ wp_cache_set("mime_type_icon_$mime", $icon);
+ break;
+ }
+ }
+ }
+
+ return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id ); // Last arg is 0 if function pass mime type.
+}
+
+/**
+ * Checked for changed slugs for published posts and save old slug.
+ *
+ * The function is used along with form POST data. It checks for the wp-old-slug
+ * POST field. Will only be concerned with published posts and the slug actually
+ * changing.
+ *
+ * If the slug was changed and not already part of the old slugs then it will be
+ * added to the post meta field ('_wp_old_slug') for storing old slugs for that
+ * post.
+ *
+ * The most logically usage of this function is redirecting changed posts, so
+ * that those that linked to an changed post will be redirected to the new post.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Post ID.
+ * @return int Same as $post_id
+ */
+function wp_check_for_changed_slugs($post_id) {
+ if ( !isset($_POST['wp-old-slug']) || !strlen($_POST['wp-old-slug']) )
+ return $post_id;
+
+ $post = &get_post($post_id);
+
+ // we're only concerned with published posts
+ if ( $post->post_status != 'publish' || $post->post_type != 'post' )
+ return $post_id;
+
+ // only bother if the slug has changed
+ if ( $post->post_name == $_POST['wp-old-slug'] )
+ return $post_id;
+
+ $old_slugs = (array) get_post_meta($post_id, '_wp_old_slug');
+
+ // if we haven't added this old slug before, add it now
+ if ( !count($old_slugs) || !in_array($_POST['wp-old-slug'], $old_slugs) )
+ add_post_meta($post_id, '_wp_old_slug', $_POST['wp-old-slug']);
+
+ // if the new slug was used previously, delete it from the list
+ if ( in_array($post->post_name, $old_slugs) )
+ delete_post_meta($post_id, '_wp_old_slug', $post->post_name);
+
+ return $post_id;
+}
+
+/**
+ * Retrieve the private post SQL based on capability.
+ *
+ * This function provides a standardized way to appropriately select on the
+ * post_status of posts/pages. The function will return a piece of SQL code that
+ * can be added to a WHERE clause; this SQL is constructed to allow all
+ * published posts, and all private posts to which the user has access.
+ *
+ * It also allows plugins that define their own post type to control the cap by
+ * using the hook 'pub_priv_sql_capability'. The plugin is expected to return
+ * the capability the user must have to read the private post type.
+ *
+ * @since 2.2.0
+ *
+ * @uses $user_ID
+ * @uses apply_filters() Call 'pub_priv_sql_capability' filter for plugins with different post types.
+ *
+ * @param string $post_type currently only supports 'post' or 'page'.
+ * @return string SQL code that can be added to a where clause.
+ */
+function get_private_posts_cap_sql($post_type) {
+ global $user_ID;
+ $cap = '';
+
+ // Private posts
+ if ($post_type == 'post') {
+ $cap = 'read_private_posts';
+ // Private pages
+ } elseif ($post_type == 'page') {
+ $cap = 'read_private_pages';
+ // Dunno what it is, maybe plugins have their own post type?
+ } else {
+ $cap = apply_filters('pub_priv_sql_capability', $cap);
+
+ if (empty($cap)) {
+ // We don't know what it is, filters don't change anything,
+ // so set the SQL up to return nothing.
+ return '1 = 0';
+ }
+ }
+
+ $sql = '(post_status = \'publish\'';
+
+ if (current_user_can($cap)) {
+ // Does the user have the capability to view private posts? Guess so.
+ $sql .= ' OR post_status = \'private\'';
+ } elseif (is_user_logged_in()) {
+ // Users can view their own private posts.
+ $sql .= ' OR post_status = \'private\' AND post_author = \'' . $user_ID . '\'';
+ }
+
+ $sql .= ')';
+
+ return $sql;
+}
+
+/**
+ * Retrieve the date the the last post was published.
+ *
+ * The server timezone is the default and is the difference between GMT and
+ * server time. The 'blog' value is the date when the last post was posted. The
+ * 'gmt' is when the last post was posted in GMT formatted date.
+ *
+ * @since 0.71
+ *
+ * @uses $wpdb
+ * @uses $blog_id
+ * @uses apply_filters() Calls 'get_lastpostdate' filter
+ *
+ * @global mixed $cache_lastpostdate Stores the last post date
+ * @global mixed $pagenow The current page being viewed
+ *
+ * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
+ * @return string The date of the last post.
+ */
+function get_lastpostdate($timezone = 'server') {
+ global $cache_lastpostdate, $wpdb, $blog_id;
+ $add_seconds_server = date('Z');
+ if ( !isset($cache_lastpostdate[$blog_id][$timezone]) ) {
+ switch(strtolower($timezone)) {
+ case 'gmt':
+ $lastpostdate = $wpdb->get_var("SELECT post_date_gmt FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
+ break;
+ case 'blog':
+ $lastpostdate = $wpdb->get_var("SELECT post_date FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
+ break;
+ case 'server':
+ $lastpostdate = $wpdb->get_var("SELECT DATE_ADD(post_date_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
+ break;
+ }
+ $cache_lastpostdate[$blog_id][$timezone] = $lastpostdate;
+ } else {
+ $lastpostdate = $cache_lastpostdate[$blog_id][$timezone];
+ }
+ return apply_filters( 'get_lastpostdate', $lastpostdate, $timezone );
+}
+
+/**
+ * Retrieve last post modified date depending on timezone.
+ *
+ * The server timezone is the default and is the difference between GMT and
+ * server time. The 'blog' value is just when the last post was modified. The
+ * 'gmt' is when the last post was modified in GMT time.
+ *
+ * @since 1.2.0
+ * @uses $wpdb
+ * @uses $blog_id
+ * @uses apply_filters() Calls 'get_lastpostmodified' filter
+ *
+ * @global mixed $cache_lastpostmodified Stores the date the last post was modified
+ *
+ * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
+ * @return string The date the post was last modified.
+ */
+function get_lastpostmodified($timezone = 'server') {
+ global $cache_lastpostmodified, $wpdb, $blog_id;
+ $add_seconds_server = date('Z');
+ if ( !isset($cache_lastpostmodified[$blog_id][$timezone]) ) {
+ switch(strtolower($timezone)) {
+ case 'gmt':
+ $lastpostmodified = $wpdb->get_var("SELECT post_modified_gmt FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
+ break;
+ case 'blog':
+ $lastpostmodified = $wpdb->get_var("SELECT post_modified FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
+ break;
+ case 'server':
+ $lastpostmodified = $wpdb->get_var("SELECT DATE_ADD(post_modified_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
+ break;
+ }
+ $lastpostdate = get_lastpostdate($timezone);
+ if ( $lastpostdate > $lastpostmodified ) {
+ $lastpostmodified = $lastpostdate;
+ }
+ $cache_lastpostmodified[$blog_id][$timezone] = $lastpostmodified;
+ } else {
+ $lastpostmodified = $cache_lastpostmodified[$blog_id][$timezone];
+ }
+ return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
+}
+
+/**
+ * Updates posts in cache.
+ *
+ * @usedby update_page_cache() Aliased by this function.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 1.5.1
+ *
+ * @param array $posts Array of post objects
+ */
+function update_post_cache(&$posts) {
+ if ( !$posts )
+ return;
+
+ foreach ( $posts as $post )
+ wp_cache_add($post->ID, $post, 'posts');
+}
+
+/**
+ * Will clean the post in the cache.
+ *
+ * Cleaning means delete from the cache of the post. Will call to clean the term
+ * object cache associated with the post ID.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 2.0.0
+ *
+ * @uses do_action() Will call the 'clean_post_cache' hook action.
+ *
+ * @param int $id The Post ID in the cache to clean
+ */
+function clean_post_cache($id) {
+ global $_wp_suspend_cache_invalidation, $wpdb;
+
+ if ( !empty($_wp_suspend_cache_invalidation) )
+ return;
+
+ $id = (int) $id;
+
+ wp_cache_delete($id, 'posts');
+ wp_cache_delete($id, 'post_meta');
+
+ clean_object_term_cache($id, 'post');
+
+ wp_cache_delete( 'wp_get_archives', 'general' );
+
+ do_action('clean_post_cache', $id);
+
+ if ( $children = $wpdb->get_col( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = %d", $id) ) ) {
+ foreach( $children as $cid )
+ clean_post_cache( $cid );
+ }
+}
+
+/**
+ * Alias of update_post_cache().
+ *
+ * @see update_post_cache() Posts and pages are the same, alias is intentional
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 1.5.1
+ *
+ * @param array $pages list of page objects
+ */
+function update_page_cache(&$pages) {
+ update_post_cache($pages);
+}
+
+/**
+ * Will clean the page in the cache.
+ *
+ * Clean (read: delete) page from cache that matches $id. Will also clean cache
+ * associated with 'all_page_ids' and 'get_pages'.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 2.0.0
+ *
+ * @uses do_action() Will call the 'clean_page_cache' hook action.
+ *
+ * @param int $id Page ID to clean
+ */
+function clean_page_cache($id) {
+ clean_post_cache($id);
+
+ wp_cache_delete( 'all_page_ids', 'posts' );
+ wp_cache_delete( 'get_pages', 'posts' );
+
+ do_action('clean_page_cache', $id);
+}
+
+/**
+ * Call major cache updating functions for list of Post objects.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 1.5.0
+ *
+ * @uses $wpdb
+ * @uses update_post_cache()
+ * @uses update_object_term_cache()
+ * @uses update_postmeta_cache()
+ *
+ * @param array $posts Array of Post objects
+ */
+function update_post_caches(&$posts) {
+ // No point in doing all this work if we didn't match any posts.
+ if ( !$posts )
+ return;
+
+ update_post_cache($posts);
+
+ $post_ids = array();
+
+ for ($i = 0; $i < count($posts); $i++)
+ $post_ids[] = $posts[$i]->ID;
+
+ update_object_term_cache($post_ids, 'post');
+
+ update_postmeta_cache($post_ids);
+}
+
+/**
+ * Updates metadata cache for list of post IDs.
+ *
+ * Performs SQL query to retrieve the metadata for the post IDs and updates the
+ * metadata cache for the posts. Therefore, the functions, which call this
+ * function, do not need to perform SQL queries on their own.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 2.1.0
+ *
+ * @uses $wpdb
+ *
+ * @param array $post_ids List of post IDs.
+ * @return bool|array Returns false if there is nothing to update or an array of metadata.
+ */
+function update_postmeta_cache($post_ids) {
+ global $wpdb;
+
+ if ( empty( $post_ids ) )
+ return false;
+
+ if ( !is_array($post_ids) ) {
+ $post_ids = preg_replace('|[^0-9,]|', '', $post_ids);
+ $post_ids = explode(',', $post_ids);
+ }
+
+ $post_ids = array_map('intval', $post_ids);
+
+ $ids = array();
+ foreach ( (array) $post_ids as $id ) {
+ if ( false === wp_cache_get($id, 'post_meta') )
+ $ids[] = $id;
+ }
+
+ if ( empty( $ids ) )
+ return false;
+
+ // Get post-meta info
+ $id_list = join(',', $ids);
+ $cache = array();
+ if ( $meta_list = $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM $wpdb->postmeta WHERE post_id IN ($id_list)", ARRAY_A) ) {
+ foreach ( (array) $meta_list as $metarow) {
+ $mpid = (int) $metarow['post_id'];
+ $mkey = $metarow['meta_key'];
+ $mval = $metarow['meta_value'];
+
+ // Force subkeys to be array type:
+ if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
+ $cache[$mpid] = array();
+ if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
+ $cache[$mpid][$mkey] = array();
+
+ // Add a value to the current pid/key:
+ $cache[$mpid][$mkey][] = $mval;
+ }
+ }
+
+ foreach ( (array) $ids as $id ) {
+ if ( ! isset($cache[$id]) )
+ $cache[$id] = array();
+ }
+
+ foreach ( (array) array_keys($cache) as $post)
+ wp_cache_set($post, $cache[$post], 'post_meta');
+
+ return $cache;
+}
+
+//
+// Hooks
+//
+
+/**
+ * Hook for managing future post transitions to published.
+ *
+ * @since 2.3.0
+ * @access private
+ * @uses $wpdb
+ *
+ * @param string $new_status New post status
+ * @param string $old_status Previous post status
+ * @param object $post Object type containing the post information
+ */
+function _transition_post_status($new_status, $old_status, $post) {
+ global $wpdb;
+
+ if ( $old_status != 'publish' && $new_status == 'publish' ) {
+ // Reset GUID if transitioning to publish and it is empty
+ if ( '' == get_the_guid($post->ID) )
+ $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post->ID ) ), array( 'ID' => $post->ID ) );
+ do_action('private_to_published', $post->ID); // Deprecated, use private_to_publish
+ }
+
+ // Always clears the hook in case the post status bounced from future to draft.
+ wp_clear_scheduled_hook('publish_future_post', $post->ID);
+}
+
+/**
+ * Hook used to schedule publication for a post marked for the future.
+ *
+ * The $post properties used and must exist are 'ID' and 'post_date_gmt'.
+ *
+ * @since 2.3.0
+ *
+ * @param int $deprecated Not Used. Can be set to null.
+ * @param object $post Object type containing the post information
+ */
+function _future_post_hook($deprecated = '', $post) {
+ wp_clear_scheduled_hook( 'publish_future_post', $post->ID );
+ wp_schedule_single_event(strtotime($post->post_date_gmt. ' GMT'), 'publish_future_post', array($post->ID));
+}
+
+/**
+ * Hook to schedule pings and enclosures when a post is published.
+ *
+ * @since 2.3.0
+ * @uses $wpdb
+ * @uses XMLRPC_REQUEST
+ * @uses APP_REQUEST
+ * @uses do_action Calls 'xmlprc_publish_post' action if XMLRPC_REQUEST is defined. Calls 'app_publish_post'
+ * action if APP_REQUEST is defined.
+ *
+ * @param int $post_id The ID in the database table of the post being published
+ */
+function _publish_post_hook($post_id) {
+ global $wpdb;
+
+ if ( defined('XMLRPC_REQUEST') )
+ do_action('xmlrpc_publish_post', $post_id);
+ if ( defined('APP_REQUEST') )
+ do_action('app_publish_post', $post_id);
+
+ if ( defined('WP_IMPORTING') )
+ return;
+
+ $data = array( 'post_id' => $post_id, 'meta_value' => '1' );
+ if ( get_option('default_pingback_flag') )
+ $wpdb->insert( $wpdb->postmeta, $data + array( 'meta_key' => '_pingme' ) );
+ $wpdb->insert( $wpdb->postmeta, $data + array( 'meta_key' => '_encloseme' ) );
+ wp_schedule_single_event(time(), 'do_pings');
+}
+
+/**
+ * Hook used to prevent page/post cache and rewrite rules from staying dirty.
+ *
+ * Does two things. If the post is a page and has a template then it will
+ * update/add that template to the meta. For both pages and posts, it will clean
+ * the post cache to make sure that the cache updates to the changes done
+ * recently. For pages, the rewrite rules of WordPress are flushed to allow for
+ * any changes.
+ *
+ * The $post parameter, only uses 'post_type' property and 'page_template'
+ * property.
+ *
+ * @since 2.3.0
+ * @uses $wp_rewrite Flushes Rewrite Rules.
+ *
+ * @param int $post_id The ID in the database table for the $post
+ * @param object $post Object type containing the post information
+ */
+function _save_post_hook($post_id, $post) {
+ if ( $post->post_type == 'page' ) {
+ clean_page_cache($post_id);
+ // Avoid flushing rules for every post during import.
+ if ( !defined('WP_IMPORTING') ) {
+ global $wp_rewrite;
+ $wp_rewrite->flush_rules();
+ }
+ } else {
+ clean_post_cache($post_id);
+ }
+}
+
+/**
+ * Retrieve post ancestors and append to post ancestors property.
+ *
+ * Will only retrieve ancestors once, if property is already set, then nothing
+ * will be done. If there is not a parent post, or post ID and post parent ID
+ * are the same then nothing will be done.
+ *
+ * The parameter is passed by reference, so nothing needs to be returned. The
+ * property will be updated and can be referenced after the function is
+ * complete. The post parent will be an ancestor and the parent of the post
+ * parent will be an ancestor. There will only be two ancestors at the most.
+ *
+ * @access private
+ * @since unknown
+ * @uses $wpdb
+ *
+ * @param object $_post Post data.
+ * @return null When nothing needs to be done.
+ */
+function _get_post_ancestors(&$_post) {
+ global $wpdb;
+
+ if ( isset($_post->ancestors) )
+ return;
+
+ $_post->ancestors = array();
+
+ if ( empty($_post->post_parent) || $_post->ID == $_post->post_parent )
+ return;
+
+ $id = $_post->ancestors[] = $_post->post_parent;
+ while ( $ancestor = $wpdb->get_var( $wpdb->prepare("SELECT `post_parent` FROM $wpdb->posts WHERE ID = %d LIMIT 1", $id) ) ) {
+ if ( $id == $ancestor )
+ break;
+ $id = $_post->ancestors[] = $ancestor;
+ }
+}
+
+/**
+ * Determines which fields of posts are to be saved in revisions.
+ *
+ * Does two things. If passed a post *array*, it will return a post array ready
+ * to be insterted into the posts table as a post revision. Otherwise, returns
+ * an array whose keys are the post fields to be saved for post revisions.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ * @access private
+ *
+ * @param array $post Optional a post array to be processed for insertion as a post revision.
+ * @param bool $autosave optional Is the revision an autosave?
+ * @return array Post array ready to be inserted as a post revision or array of fields that can be versioned.
+ */
+function _wp_post_revision_fields( $post = null, $autosave = false ) {
+ static $fields = false;
+
+ if ( !$fields ) {
+ // Allow these to be versioned
+ $fields = array(
+ 'post_title' => __( 'Title' ),
+ 'post_content' => __( 'Content' ),
+ 'post_excerpt' => __( 'Excerpt' ),
+ );
+
+ // Runs only once
+ $fields = apply_filters( '_wp_post_revision_fields', $fields );
+
+ // WP uses these internally either in versioning or elsewhere - they cannot be versioned
+ foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect )
+ unset( $fields[$protect] );
+ }
+
+ if ( !is_array($post) )
+ return $fields;
+
+ $return = array();
+ foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field )
+ $return[$field] = $post[$field];
+
+ $return['post_parent'] = $post['ID'];
+ $return['post_status'] = 'inherit';
+ $return['post_type'] = 'revision';
+ $return['post_name'] = $autosave ? "$post[ID]-autosave" : "$post[ID]-revision";
+ $return['post_date'] = isset($post['post_modified']) ? $post['post_modified'] : '';
+ $return['post_date_gmt'] = isset($post['post_modified_gmt']) ? $post['post_modified_gmt'] : '';
+
+ return $return;
+}
+
+/**
+ * Saves an already existing post as a post revision.
+ *
+ * Typically used immediately prior to post updates.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses _wp_put_post_revision()
+ *
+ * @param int $post_id The ID of the post to save as a revision.
+ * @return mixed Null or 0 if error, new revision ID, if success.
+ */
+function wp_save_post_revision( $post_id ) {
+ // We do autosaves manually with wp_create_post_autosave()
+ if ( @constant( 'DOING_AUTOSAVE' ) )
+ return;
+
+ // WP_POST_REVISIONS = 0, false
+ if ( !constant('WP_POST_REVISIONS') )
+ return;
+
+ if ( !$post = get_post( $post_id, ARRAY_A ) )
+ return;
+
+ if ( !in_array( $post['post_type'], array( 'post', 'page' ) ) )
+ return;
+
+ $return = _wp_put_post_revision( $post );
+
+ // WP_POST_REVISIONS = true (default), -1
+ if ( !is_numeric( WP_POST_REVISIONS ) || WP_POST_REVISIONS < 0 )
+ return $return;
+
+ // all revisions and (possibly) one autosave
+ $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) );
+
+ // WP_POST_REVISIONS = (int) (# of autasaves to save)
+ $delete = count($revisions) - WP_POST_REVISIONS;
+
+ if ( $delete < 1 )
+ return $return;
+
+ $revisions = array_slice( $revisions, 0, $delete );
+
+ for ( $i = 0; isset($revisions[$i]); $i++ ) {
+ if ( false !== strpos( $revisions[$i]->post_name, 'autosave' ) )
+ continue;
+ wp_delete_post_revision( $revisions[$i]->ID );
+ }
+
+ return $return;
+}
+
+/**
+ * Retrieve the autosaved data of the specified post.
+ *
+ * Returns a post object containing the information that was autosaved for the
+ * specified post.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @param int $post_id The post ID.
+ * @return object|bool The autosaved data or false on failure or when no autosave exists.
+ */
+function wp_get_post_autosave( $post_id ) {
+
+ if ( !$post = get_post( $post_id ) )
+ return false;
+
+ $q = array(
+ 'name' => "{$post->ID}-autosave",
+ 'post_parent' => $post->ID,
+ 'post_type' => 'revision',
+ 'post_status' => 'inherit'
+ );
+
+ // Use WP_Query so that the result gets cached
+ $autosave_query = new WP_Query;
+
+ add_action( 'parse_query', '_wp_get_post_autosave_hack' );
+ $autosave = $autosave_query->query( $q );
+ remove_action( 'parse_query', '_wp_get_post_autosave_hack' );
+
+ if ( $autosave && is_array($autosave) && is_object($autosave[0]) )
+ return $autosave[0];
+
+ return false;
+}
+
+/**
+ * Internally used to hack WP_Query into submission.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @param object $query WP_Query object
+ */
+function _wp_get_post_autosave_hack( $query ) {
+ $query->is_single = false;
+}
+
+/**
+ * Determines if the specified post is a revision.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @param int|object $post Post ID or post object.
+ * @return bool|int False if not a revision, ID of revision's parent otherwise.
+ */
+function wp_is_post_revision( $post ) {
+ if ( !$post = wp_get_post_revision( $post ) )
+ return false;
+ return (int) $post->post_parent;
+}
+
+/**
+ * Determines if the specified post is an autosave.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @param int|object $post Post ID or post object.
+ * @return bool|int False if not a revision, ID of autosave's parent otherwise
+ */
+function wp_is_post_autosave( $post ) {
+ if ( !$post = wp_get_post_revision( $post ) )
+ return false;
+ if ( "{$post->post_parent}-autosave" !== $post->post_name )
+ return false;
+ return (int) $post->post_parent;
+}
+
+/**
+ * Inserts post data into the posts table as a post revision.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses wp_insert_post()
+ *
+ * @param int|object|array $post Post ID, post object OR post array.
+ * @param bool $autosave Optional. Is the revision an autosave?
+ * @return mixed Null or 0 if error, new revision ID if success.
+ */
+function _wp_put_post_revision( $post = null, $autosave = false ) {
+ if ( is_object($post) )
+ $post = get_object_vars( $post );
+ elseif ( !is_array($post) )
+ $post = get_post($post, ARRAY_A);
+ if ( !$post || empty($post['ID']) )
+ return;
+
+ if ( isset($post['post_type']) && 'revision' == $post['post_type'] )
+ return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) );
+
+ $post = _wp_post_revision_fields( $post, $autosave );
+
+ $revision_id = wp_insert_post( $post );
+ if ( is_wp_error($revision_id) )
+ return $revision_id;
+
+ if ( $revision_id )
+ do_action( '_wp_put_post_revision', $revision_id );
+ return $revision_id;
+}
+
+/**
+ * Gets a post revision.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses get_post()
+ *
+ * @param int|object $post Post ID or post object
+ * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N.
+ * @param string $filter Optional sanitation filter. @see sanitize_post()
+ * @return mixed Null if error or post object if success
+ */
+function &wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') {
+ $null = null;
+ if ( !$revision = get_post( $post, OBJECT, $filter ) )
+ return $revision;
+ if ( 'revision' !== $revision->post_type )
+ return $null;
+
+ if ( $output == OBJECT ) {
+ return $revision;
+ } elseif ( $output == ARRAY_A ) {
+ $_revision = get_object_vars($revision);
+ return $_revision;
+ } elseif ( $output == ARRAY_N ) {
+ $_revision = array_values(get_object_vars($revision));
+ return $_revision;
+ }
+
+ return $revision;
+}
+
+/**
+ * Restores a post to the specified revision.
+ *
+ * Can restore a past using all fields of the post revision, or only selected
+ * fields.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses wp_get_post_revision()
+ * @uses wp_update_post()
+ *
+ * @param int|object $revision_id Revision ID or revision object.
+ * @param array $fields Optional. What fields to restore from. Defaults to all.
+ * @return mixed Null if error, false if no fields to restore, (int) post ID if success.
+ */
+function wp_restore_post_revision( $revision_id, $fields = null ) {
+ if ( !$revision = wp_get_post_revision( $revision_id, ARRAY_A ) )
+ return $revision;
+
+ if ( !is_array( $fields ) )
+ $fields = array_keys( _wp_post_revision_fields() );
+
+ $update = array();
+ foreach( array_intersect( array_keys( $revision ), $fields ) as $field )
+ $update[$field] = $revision[$field];
+
+ if ( !$update )
+ return false;
+
+ $update['ID'] = $revision['post_parent'];
+
+ $post_id = wp_update_post( $update );
+ if ( is_wp_error( $post_id ) )
+ return $post_id;
+
+ if ( $post_id )
+ do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] );
+
+ return $post_id;
+}
+
+/**
+ * Deletes a revision.
+ *
+ * Deletes the row from the posts table corresponding to the specified revision.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses wp_get_post_revision()
+ * @uses wp_delete_post()
+ *
+ * @param int|object $revision_id Revision ID or revision object.
+ * @param array $fields Optional. What fields to restore from. Defaults to all.
+ * @return mixed Null if error, false if no fields to restore, (int) post ID if success.
+ */
+function wp_delete_post_revision( $revision_id ) {
+ if ( !$revision = wp_get_post_revision( $revision_id ) )
+ return $revision;
+
+ $delete = wp_delete_post( $revision->ID );
+ if ( is_wp_error( $delete ) )
+ return $delete;
+
+ if ( $delete )
+ do_action( 'wp_delete_post_revision', $revision->ID, $revision );
+
+ return $delete;
+}
+
+/**
+ * Returns all revisions of specified post.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses get_children()
+ *
+ * @param int|object $post_id Post ID or post object
+ * @return array empty if no revisions
+ */
+function wp_get_post_revisions( $post_id = 0, $args = null ) {
+ if ( !constant('WP_POST_REVISIONS') )
+ return array();
+ if ( ( !$post = get_post( $post_id ) ) || empty( $post->ID ) )
+ return array();
+
+ $defaults = array( 'order' => 'DESC', 'orderby' => 'date' );
+ $args = wp_parse_args( $args, $defaults );
+ $args = array_merge( $args, array( 'post_parent' => $post->ID, 'post_type' => 'revision', 'post_status' => 'inherit' ) );
+
+ if ( !$revisions = get_children( $args ) )
+ return array();
+ return $revisions;
+}
+
+function _set_preview($post) {
+
+ if ( ! is_object($post) )
+ return $post;
+
+ $preview = wp_get_post_autosave($post->ID);
+
+ if ( ! is_object($preview) )
+ return $post;
+
+ $preview = sanitize_post($preview);
+
+ $post->post_content = $preview->post_content;
+ $post->post_title = $preview->post_title;
+ $post->post_excerpt = $preview->post_excerpt;
+
+ return $post;
+}
+
+function _show_post_preview() {
+
+ if ( isset($_GET['preview_id']) && isset($_GET['preview_nonce']) ) {
+ $id = (int) $_GET['preview_id'];
+
+ if ( false == wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $id ) )
+ wp_die( __('You do not have permission to preview drafts.') );
+
+ add_filter('the_preview', '_set_preview');
+ }
+}
diff -uNr a/blog/wp-includes/post-template.php b/blog/wp-includes/post-template.php
--- a/blog/wp-includes/post-template.php false
+++ b/blog/wp-includes/post-template.php ba648f60f2fde253ef08f2c11d283139b886d0e52f1b7c48828a1fc2a2c4237306678e54c0f8bc83341098365b6bb7a1b08f5169dc1706275c97716878e80be8
@@ -0,0 +1,1199 @@
+ '', 'after' => '', 'echo' => true);
+ $r = wp_parse_args($args, $defaults);
+ extract( $r, EXTR_SKIP );
+
+
+ $title = $before . $title . $after;
+ $title = attribute_escape(strip_tags($title));
+
+ if ( $echo )
+ echo $title;
+ else
+ return $title;
+}
+
+/**
+ * Retrieve post title.
+ *
+ * If the post is protected and the visitor is not an admin, then "Protected"
+ * will be displayed before the post title. If the post is private, then
+ * "Private" will be located before the post title.
+ *
+ * @since 0.71
+ *
+ * @param int $id Optional. Post ID.
+ * @return string
+ */
+function get_the_title( $id = 0 ) {
+ $post = &get_post($id);
+
+ $title = $post->post_title;
+
+ if ( !is_admin() ) {
+ if ( !empty($post->post_password) )
+ $title = sprintf(__('Protected: %s'), $title);
+ else if ( isset($post->post_status) && 'private' == $post->post_status )
+ $title = sprintf(__('Private: %s'), $title);
+ }
+ return apply_filters( 'the_title', $title );
+}
+
+/**
+ * Display the Post Global Unique Identifier (guid).
+ *
+ * The guid will appear to be a link, but should not be used as an link to the
+ * post. The reason you should not use it as a link, is because of moving the
+ * blog across domains.
+ *
+ * @since 1.5.0
+ *
+ * @param int $id Optional. Post ID.
+ */
+function the_guid( $id = 0 ) {
+ echo get_the_guid($id);
+}
+
+/**
+ * Retrieve the Post Global Unique Identifier (guid).
+ *
+ * The guid will appear to be a link, but should not be used as an link to the
+ * post. The reason you should not use it as a link, is because of moving the
+ * blog across domains.
+ *
+ * @since 1.5.0
+ *
+ * @param int $id Optional. Post ID.
+ * @return string
+ */
+function get_the_guid( $id = 0 ) {
+ $post = &get_post($id);
+
+ return apply_filters('get_the_guid', $post->guid);
+}
+
+/**
+ * Display the post content.
+ *
+ * @since 0.71
+ *
+ * @param string $more_link_text Optional. Content for when there is more text.
+ * @param string $stripteaser Optional. Teaser content before the more text.
+ * @param string $more_file Optional. Not used.
+ */
+function the_content($more_link_text = null, $stripteaser = 0, $more_file = '') {
+ $content = get_the_content($more_link_text, $stripteaser, $more_file);
+ $content = apply_filters('the_content', $content);
+ $content = str_replace(']]>', ']]>', $content);
+ echo $content;
+}
+
+/**
+ * Retrieve the post content.
+ *
+ * @since 0.71
+ *
+ * @param string $more_link_text Optional. Content for when there is more text.
+ * @param string $stripteaser Optional. Teaser content before the more text.
+ * @param string $more_file Optional. Not used.
+ * @return string
+ */
+function get_the_content($more_link_text = null, $stripteaser = 0, $more_file = '') {
+ global $id, $post, $more, $page, $pages, $multipage, $preview, $pagenow;
+
+ if ( null === $more_link_text )
+ $more_link_text = __( '(more...)' );
+
+ $output = '';
+
+ // If post password required and it doesn't match the cookie.
+ if ( post_password_required($post) ) {
+ $output = get_the_password_form();
+ return $output;
+ }
+
+ if ( $more_file != '' )
+ $file = $more_file;
+ else
+ $file = $pagenow; //$_SERVER['PHP_SELF'];
+
+ if ( $page > count($pages) ) // if the requested page doesn't exist
+ $page = count($pages); // give them the highest numbered page that DOES exist
+
+ $content = $pages[$page-1];
+ if ( preg_match('//', $content, $matches) ) {
+ $content = explode($matches[0], $content, 2);
+ if ( !empty($matches[1]) && !empty($more_link_text) )
+ $more_link_text = strip_tags(wp_kses_no_null(trim($matches[1])));
+ } else {
+ $content = array($content);
+ }
+ if ( (false !== strpos($post->post_content, '') && ((!$multipage) || ($page==1))) )
+ $stripteaser = 1;
+ $teaser = $content[0];
+ if ( ($more) && ($stripteaser) )
+ $teaser = '';
+ $output .= $teaser;
+ if ( count($content) > 1 ) {
+ if ( $more ) {
+ $output .= ' '.$content[1];
+ } else {
+ $output = balanceTags($output);
+ if ( ! empty($more_link_text) )
+ $output .= ' $more_link_text ";
+ }
+
+ }
+ if ( $preview ) // preview fix for javascript bug with foreign languages
+ $output = preg_replace('/\%u([0-9A-F]{4,4})/e', "'&#'.base_convert('\\1',16,10).';'", $output);
+
+ return $output;
+}
+
+/**
+ * Display the post excerpt.
+ *
+ * @since 0.71
+ * @uses apply_filters() Calls 'the_excerpt' hook on post excerpt.
+ */
+function the_excerpt() {
+ echo apply_filters('the_excerpt', get_the_excerpt());
+}
+
+/**
+ * Retrieve the post excerpt.
+ *
+ * @since 0.71
+ *
+ * @param mixed $deprecated Not used.
+ * @return string
+ */
+function get_the_excerpt($deprecated = '') {
+ global $post;
+ $output = '';
+ $output = $post->post_excerpt;
+ if ( post_password_required($post) ) {
+ $output = __('There is no excerpt because this is a protected post.');
+ return $output;
+ }
+
+ return apply_filters('get_the_excerpt', $output);
+}
+
+/**
+ * Whether post has excerpt.
+ *
+ * @since 2.3.0
+ *
+ * @param int $id Optional. Post ID.
+ * @return bool
+ */
+function has_excerpt( $id = 0 ) {
+ $post = &get_post( $id );
+ return ( !empty( $post->post_excerpt ) );
+}
+
+/**
+ * Display the classes for the post div.
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $class One or more classes to add to the class list.
+ * @param int $post_id An optional post ID.
+ */
+function post_class( $class = '', $post_id = null ) {
+ // Separates classes with a single space, collates classes for post DIV
+ echo 'class="' . join( ' ', get_post_class( $class, $post_id ) ) . '"';
+}
+
+/**
+ * Retrieve the classes for the post div as an array.
+ *
+ * The class names are add are many. If the post is a sticky, then the 'sticky'
+ * class name. The class 'hentry' is always added to each post. For each
+ * category, the class will be added with 'category-' with category slug is
+ * added. The tags are the same way as the categories with 'tag-' before the tag
+ * slug. All classes are passed through the filter, 'post_class' with the list
+ * of classes, followed by $class parameter value, with the post ID as the last
+ * parameter.
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $class One or more classes to add to the class list.
+ * @param int $post_id An optional post ID.
+ * @return array Array of classes.
+ */
+function get_post_class( $class = '', $post_id = null ) {
+ $post = get_post($post_id);
+
+ $classes = array();
+
+ $classes[] = $post->post_type;
+
+ // sticky for Sticky Posts
+ if ( is_sticky($post->ID) && is_home())
+ $classes[] = 'sticky';
+
+ // hentry for hAtom compliace
+ $classes[] = 'hentry';
+
+ // Categories
+ foreach ( (array) get_the_category($post->ID) as $cat ) {
+ if ( empty($cat->slug ) )
+ continue;
+ $classes[] = 'category-' . $cat->slug;
+ }
+
+ // Tags
+ foreach ( (array) get_the_tags($post->ID) as $tag ) {
+ if ( empty($tag->slug ) )
+ continue;
+ $classes[] = 'tag-' . $tag->slug;
+ }
+
+ if ( !empty($class) ) {
+ if ( !is_array( $class ) )
+ $class = preg_split('#\s+#', $class);
+ $classes = array_merge($classes, $class);
+ }
+
+ return apply_filters('post_class', $classes, $class, $post_id);
+}
+
+/**
+ * Whether post requires password and correct password has been provided.
+ *
+ * @since 2.7.0
+ *
+ * @param int|object $post An optional post. Global $post used if not provided.
+ * @return bool false if a password is not required or the correct password cookie is present, true otherwise.
+ */
+function post_password_required( $post = null ) {
+ $post = get_post($post);
+
+ if ( empty($post->post_password) )
+ return false;
+
+ if ( !isset($_COOKIE['wp-postpass_' . COOKIEHASH]) )
+ return true;
+
+ if ( $_COOKIE['wp-postpass_' . COOKIEHASH] != $post->post_password )
+ return true;
+
+ return false;
+}
+
+/**
+ * Display "sticky" CSS class, if a post is sticky.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id An optional post ID.
+ */
+function sticky_class( $post_id = null ) {
+ if ( !is_sticky($post_id) )
+ return;
+
+ echo " sticky";
+}
+
+/**
+ * Page Template Functions for usage in Themes
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * The formatted output of a list of pages.
+ *
+ * Displays page links for paginated posts (i.e. includes the .
+ * Quicktag one or more times). This tag must be within The Loop.
+ *
+ * The defaults for overwriting are:
+ * 'next_or_number' - Default is 'number' (string). Indicates whether page
+ * numbers should be used. Valid values are number and next.
+ * 'nextpagelink' - Default is 'Next Page' (string). Text for link to next page.
+ * of the bookmark.
+ * 'previouspagelink' - Default is 'Previous Page' (string). Text for link to
+ * previous page, if available.
+ * 'pagelink' - Default is '%' (String).Format string for page numbers. The % in
+ * the parameter string will be replaced with the page number, so Page %
+ * generates "Page 1", "Page 2", etc. Defaults to %, just the page number.
+ * 'before' - Default is ' Pages:' (string). The html or text to prepend to
+ * each bookmarks.
+ * 'after' - Default is '
' (string). The html or text to append to each
+ * bookmarks.
+ * 'more_file' - Default is '' (string) Page the links should point to. Defaults
+ * to the current page.
+ * 'link_before' - Default is '' (string). The html or text to prepend to each
+ * Pages link inside the tag.
+ * 'link_after' - Default is '' (string). The html or text to append to each
+ * Pages link inside the tag.
+ *
+ * @since 1.2.0
+ * @access private
+ *
+ * @param string|array $args Optional. Overwrite the defaults.
+ * @return string Formatted output in HTML.
+ */
+function wp_link_pages($args = '') {
+ $defaults = array(
+ 'before' => '' . __('Pages:'), 'after' => '
',
+ 'link_before' => '', 'link_after' => '',
+ 'next_or_number' => 'number', 'nextpagelink' => __('Next page'),
+ 'previouspagelink' => __('Previous page'), 'pagelink' => '%',
+ 'more_file' => '', 'echo' => 1
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ global $post, $page, $numpages, $multipage, $more, $pagenow;
+ if ( $more_file != '' )
+ $file = $more_file;
+ else
+ $file = $pagenow;
+
+ $output = '';
+ if ( $multipage ) {
+ if ( 'number' == $next_or_number ) {
+ $output .= $before;
+ for ( $i = 1; $i < ($numpages+1); $i = $i + 1 ) {
+ $j = str_replace('%',"$i",$pagelink);
+ $output .= ' ';
+ if ( ($i != $page) || ((!$more) && ($page==1)) ) {
+ if ( 1 == $i ) {
+ $output .= ' ';
+ } else {
+ if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
+ $output .= ' ';
+ else
+ $output .= ' ';
+ }
+
+ }
+ $output .= $link_before;
+ $output .= $j;
+ $output .= $link_after;
+ if ( ($i != $page) || ((!$more) && ($page==1)) )
+ $output .= ' ';
+ }
+ $output .= $after;
+ } else {
+ if ( $more ) {
+ $output .= $before;
+ $i = $page - 1;
+ if ( $i && $more ) {
+ if ( 1 == $i ) {
+ $output .= '' . $link_before. $previouspagelink . $link_after . ' ';
+ } else {
+ if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
+ $output .= '' . $link_before. $previouspagelink . $link_after . ' ';
+ else
+ $output .= '' . $link_before. $previouspagelink . $link_after . ' ';
+ }
+ }
+ $i = $page + 1;
+ if ( $i <= $numpages && $more ) {
+ if ( 1 == $i ) {
+ $output .= '' . $link_before. $nextpagelink . $link_after . ' ';
+ } else {
+ if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
+ $output .= '' . $link_before. $nextpagelink . $link_after . ' ';
+ else
+ $output .= '' . $link_before. $nextpagelink . $link_after . ' ';
+ }
+ }
+ $output .= $after;
+ }
+ }
+ }
+
+ if ( $echo )
+ echo $output;
+
+ return $output;
+}
+
+
+//
+// Post-meta: Custom per-post fields.
+//
+
+/**
+ * Retrieve post custom meta data field.
+ *
+ * @since 1.5.0
+ *
+ * @param string $key Meta data key name.
+ * @return string|array Array of values or single value, if only one element exists.
+ */
+function post_custom( $key = '' ) {
+ $custom = get_post_custom();
+
+ if ( 1 == count($custom[$key]) )
+ return $custom[$key][0];
+ else
+ return $custom[$key];
+}
+
+/**
+ * Display list of post custom fields.
+ *
+ * @internal This will probably change at some point...
+ * @since 1.2.0
+ * @uses apply_filters() Calls 'the_meta_key' on list item HTML content, with key and value as separate parameters.
+ */
+function the_meta() {
+ if ( $keys = get_post_custom_keys() ) {
+ echo "\n";
+ foreach ( (array) $keys as $key ) {
+ $keyt = trim($key);
+ if ( '_' == $keyt{0} )
+ continue;
+ $values = array_map('trim', get_post_custom_values($key));
+ $value = implode($values,', ');
+ echo apply_filters('the_meta_key', "$key: $value \n", $key, $value);
+ }
+ echo " \n";
+ }
+}
+
+//
+// Pages
+//
+
+/**
+ * Retrieve or display list of pages as a dropdown (select list).
+ *
+ * @since 2.1.0
+ *
+ * @param array|string $args Optional. Override default arguments.
+ * @return string HTML content, if not displaying.
+ */
+function wp_dropdown_pages($args = '') {
+ $defaults = array(
+ 'depth' => 0, 'child_of' => 0,
+ 'selected' => 0, 'echo' => 1,
+ 'name' => 'page_id', 'show_option_none' => '', 'show_option_no_change' => '',
+ 'option_none_value' => ''
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $pages = get_pages($r);
+ $output = '';
+
+ if ( ! empty($pages) ) {
+ $output = "\n";
+ if ( $show_option_no_change )
+ $output .= "\t$show_option_no_change ";
+ if ( $show_option_none )
+ $output .= "\t$show_option_none \n";
+ $output .= walk_page_dropdown_tree($pages, $depth, $r);
+ $output .= " \n";
+ }
+
+ $output = apply_filters('wp_dropdown_pages', $output);
+
+ if ( $echo )
+ echo $output;
+
+ return $output;
+}
+
+/**
+ * Retrieve or display list of pages in list (li) format.
+ *
+ * @since 1.5.0
+ *
+ * @param array|string $args Optional. Override default arguments.
+ * @return string HTML content, if not displaying.
+ */
+function wp_list_pages($args = '') {
+ $defaults = array(
+ 'depth' => 0, 'show_date' => '',
+ 'date_format' => get_option('date_format'),
+ 'child_of' => 0, 'exclude' => '',
+ 'title_li' => __('Pages'), 'echo' => 1,
+ 'authors' => '', 'sort_column' => 'menu_order, post_title',
+ 'link_before' => '', 'link_after' => ''
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $output = '';
+ $current_page = 0;
+
+ // sanitize, mostly to keep spaces out
+ $r['exclude'] = preg_replace('[^0-9,]', '', $r['exclude']);
+
+ // Allow plugins to filter an array of excluded pages
+ $r['exclude'] = implode(',', apply_filters('wp_list_pages_excludes', explode(',', $r['exclude'])));
+
+ // Query pages.
+ $r['hierarchical'] = 0;
+ $pages = get_pages($r);
+
+ if ( !empty($pages) ) {
+ if ( $r['title_li'] )
+ $output .= '' . $r['title_li'] . '';
+
+ global $wp_query;
+ if ( is_page() || $wp_query->is_posts_page )
+ $current_page = $wp_query->get_queried_object_id();
+ $output .= walk_page_tree($pages, $r['depth'], $current_page, $r);
+
+ if ( $r['title_li'] )
+ $output .= ' ';
+ }
+
+ $output = apply_filters('wp_list_pages', $output);
+
+ if ( $r['echo'] )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Display or retrieve list of pages with optional home link.
+ *
+ * The arguments are listed below and part of the arguments are for {@link
+ * wp_list_pages()} function. Check that function for more info on those
+ * arguments.
+ *
+ *
+ * sort_column - How to sort the list of pages. Defaults
+ * to page title. Use column for posts table.
+ * menu_class - Class to use for the div ID which contains
+ * the page list. Defaults to 'menu'.
+ * echo - Whether to echo list or return it. Defaults to
+ * echo.
+ * link_before - Text before show_home argument text.
+ * link_after - Text after show_home argument text.
+ * show_home - If you set this argument, then it will
+ * display the link to the home page. The show_home argument really just needs
+ * to be set to the value of the text of the link.
+ *
+ *
+ * @since 2.7.0
+ *
+ * @param array|string $args
+ */
+function wp_page_menu( $args = array() ) {
+ $defaults = array('sort_column' => 'post_title', 'menu_class' => 'menu', 'echo' => true, 'link_before' => '', 'link_after' => '');
+ $args = wp_parse_args( $args, $defaults );
+ $args = apply_filters( 'wp_page_menu_args', $args );
+
+ $menu = '';
+
+ $list_args = $args;
+
+ // Show Home in the menu
+ if ( isset($args['show_home']) && ! empty($args['show_home']) ) {
+ if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] )
+ $text = __('Home');
+ else
+ $text = $args['show_home'];
+ $class = '';
+ if ( is_front_page() && !is_paged() )
+ $class = 'class="current_page_item"';
+ $menu .= '' . $link_before . $text . $link_after . ' ';
+ // If the front page is a page, add it to the exclude list
+ if (get_option('show_on_front') == 'page') {
+ if ( !empty( $list_args['exclude'] ) ) {
+ $list_args['exclude'] .= ',';
+ } else {
+ $list_args['exclude'] = '';
+ }
+ $list_args['exclude'] .= get_option('page_on_front');
+ }
+ }
+
+ $list_args['echo'] = false;
+ $list_args['title_li'] = '';
+ $menu .= str_replace( array( "\r", "\n", "\t" ), '', wp_list_pages($list_args) );
+
+ if ( $menu )
+ $menu = '';
+
+ $menu = '\n";
+ $menu = apply_filters( 'wp_page_menu', $menu, $args );
+ if ( $args['echo'] )
+ echo $menu;
+ else
+ return $menu;
+}
+
+//
+// Page helpers
+//
+
+/**
+ * Retrieve HTML list content for page list.
+ *
+ * @uses Walker_Page to create HTML list content.
+ * @since 2.1.0
+ * @see Walker_Page::walk() for parameters and return description.
+ */
+function walk_page_tree($pages, $depth, $current_page, $r) {
+ $walker = new Walker_Page;
+ $args = array($pages, $depth, $r, $current_page);
+ return call_user_func_array(array(&$walker, 'walk'), $args);
+}
+
+/**
+ * Retrieve HTML dropdown (select) content for page list.
+ *
+ * @uses Walker_PageDropdown to create HTML dropdown content.
+ * @since 2.1.0
+ * @see Walker_PageDropdown::walk() for parameters and return description.
+ */
+function walk_page_dropdown_tree() {
+ $walker = new Walker_PageDropdown;
+ $args = func_get_args();
+ return call_user_func_array(array(&$walker, 'walk'), $args);
+}
+
+//
+// Attachments
+//
+
+/**
+ * Display an attachment page link using an image or icon.
+ *
+ * @since 2.0.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default is false. Whether to use full size.
+ * @param bool $deprecated Deprecated. Not used.
+ * @param bool $permalink Optional, default is false. Whether to include permalink.
+ */
+function the_attachment_link($id = 0, $fullsize = false, $deprecated = false, $permalink = false) {
+ if ( $fullsize )
+ echo wp_get_attachment_link($id, 'full', $permalink);
+ else
+ echo wp_get_attachment_link($id, 'thumbnail', $permalink);
+}
+
+/**
+ * Retrieve an attachment page link using an image or icon, if possible.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'wp_get_attachment_link' filter on HTML content with same parameters as function.
+ *
+ * @param int $id Optional. Post ID.
+ * @param string $size Optional. Image size.
+ * @param bool $permalink Optional, default is false. Whether to add permalink to image.
+ * @param bool $icon Optional, default is false. Whether to include icon.
+ * @return string HTML content.
+ */
+function wp_get_attachment_link($id = 0, $size = 'thumbnail', $permalink = false, $icon = false) {
+ $id = intval($id);
+ $_post = & get_post( $id );
+
+ if ( ('attachment' != $_post->post_type) || !$url = wp_get_attachment_url($_post->ID) )
+ return __('Missing Attachment');
+
+ if ( $permalink )
+ $url = get_attachment_link($_post->ID);
+
+ $post_title = attribute_escape($_post->post_title);
+
+ $link_text = wp_get_attachment_image($id, $size, $icon);
+ if ( !$link_text )
+ $link_text = $_post->post_title;
+
+ return apply_filters( 'wp_get_attachment_link', "$link_text ", $id, $size, $permalink, $icon );
+}
+
+/**
+ * Retrieve HTML content of attachment image with link.
+ *
+ * @since 2.0.0
+ * @deprecated Use {@link wp_get_attachment_link()}
+ * @see wp_get_attachment_link() Use instead.
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default is false. Whether to use full size image.
+ * @param array $max_dims Optional. Max image dimensions.
+ * @param bool $permalink Optional, default is false. Whether to include permalink to image.
+ * @return string
+ */
+function get_the_attachment_link($id = 0, $fullsize = false, $max_dims = false, $permalink = false) {
+ $id = (int) $id;
+ $_post = & get_post($id);
+
+ if ( ('attachment' != $_post->post_type) || !$url = wp_get_attachment_url($_post->ID) )
+ return __('Missing Attachment');
+
+ if ( $permalink )
+ $url = get_attachment_link($_post->ID);
+
+ $post_title = attribute_escape($_post->post_title);
+
+ $innerHTML = get_attachment_innerHTML($_post->ID, $fullsize, $max_dims);
+ return "$innerHTML ";
+}
+
+/**
+ * Retrieve icon URL and Path.
+ *
+ * @since 2.1.0
+ * @deprecated Use {@link wp_get_attachment_image_src()}
+ * @see wp_get_attachment_image_src() Use instead.
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default to false. Whether to have full image.
+ * @return array Icon URL and full path to file, respectively.
+ */
+function get_attachment_icon_src( $id = 0, $fullsize = false ) {
+ $id = (int) $id;
+ if ( !$post = & get_post($id) )
+ return false;
+
+ $file = get_attached_file( $post->ID );
+
+ if ( !$fullsize && $src = wp_get_attachment_thumb_url( $post->ID ) ) {
+ // We have a thumbnail desired, specified and existing
+
+ $src_file = basename($src);
+ $class = 'attachmentthumb';
+ } elseif ( wp_attachment_is_image( $post->ID ) ) {
+ // We have an image without a thumbnail
+
+ $src = wp_get_attachment_url( $post->ID );
+ $src_file = & $file;
+ $class = 'attachmentimage';
+ } elseif ( $src = wp_mime_type_icon( $post->ID ) ) {
+ // No thumb, no image. We'll look for a mime-related icon instead.
+
+ $icon_dir = apply_filters( 'icon_dir', get_template_directory() . '/images' );
+ $src_file = $icon_dir . '/' . basename($src);
+ }
+
+ if ( !isset($src) || !$src )
+ return false;
+
+ return array($src, $src_file);
+}
+
+/**
+ * Retrieve HTML content of icon attachment image element.
+ *
+ * @since 2.0.0
+ * @deprecated Use {@link wp_get_attachment_image()}
+ * @see wp_get_attachment_image() Use instead of.
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default to false. Whether to have full size image.
+ * @param array $max_dims Optional. Dimensions of image.
+ * @return string HTML content.
+ */
+function get_attachment_icon( $id = 0, $fullsize = false, $max_dims = false ) {
+ $id = (int) $id;
+ if ( !$post = & get_post($id) )
+ return false;
+
+ if ( !$src = get_attachment_icon_src( $post->ID, $fullsize ) )
+ return false;
+
+ list($src, $src_file) = $src;
+
+ // Do we need to constrain the image?
+ if ( ($max_dims = apply_filters('attachment_max_dims', $max_dims)) && file_exists($src_file) ) {
+
+ $imagesize = getimagesize($src_file);
+
+ if (($imagesize[0] > $max_dims[0]) || $imagesize[1] > $max_dims[1] ) {
+ $actual_aspect = $imagesize[0] / $imagesize[1];
+ $desired_aspect = $max_dims[0] / $max_dims[1];
+
+ if ( $actual_aspect >= $desired_aspect ) {
+ $height = $actual_aspect * $max_dims[0];
+ $constraint = "width='{$max_dims[0]}' ";
+ $post->iconsize = array($max_dims[0], $height);
+ } else {
+ $width = $max_dims[1] / $actual_aspect;
+ $constraint = "height='{$max_dims[1]}' ";
+ $post->iconsize = array($width, $max_dims[1]);
+ }
+ } else {
+ $post->iconsize = array($imagesize[0], $imagesize[1]);
+ $constraint = '';
+ }
+ } else {
+ $constraint = '';
+ }
+
+ $post_title = attribute_escape($post->post_title);
+
+ $icon = " ";
+
+ return apply_filters( 'attachment_icon', $icon, $post->ID );
+}
+
+/**
+ * Retrieve HTML content of image element.
+ *
+ * @since 2.0.0
+ * @deprecated Use {@link wp_get_attachment_image()}
+ * @see wp_get_attachment_image() Use instead.
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default to false. Whether to have full size image.
+ * @param array $max_dims Optional. Dimensions of image.
+ * @return string
+ */
+function get_attachment_innerHTML($id = 0, $fullsize = false, $max_dims = false) {
+ $id = (int) $id;
+ if ( !$post = & get_post($id) )
+ return false;
+
+ if ( $innerHTML = get_attachment_icon($post->ID, $fullsize, $max_dims))
+ return $innerHTML;
+
+
+ $innerHTML = attribute_escape($post->post_title);
+
+ return apply_filters('attachment_innerHTML', $innerHTML, $post->ID);
+}
+
+/**
+ * Wrap attachment in <> element before content.
+ *
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'prepend_attachment' hook on HTML content.
+ *
+ * @param string $content
+ * @return string
+ */
+function prepend_attachment($content) {
+ global $post;
+
+ if ( empty($post->post_type) || $post->post_type != 'attachment' )
+ return $content;
+
+ $p = '
';
+ // show the medium sized image representation of the attachment if available, and link to the raw file
+ $p .= wp_get_attachment_link(0, 'medium', false);
+ $p .= '
';
+ $p = apply_filters('prepend_attachment', $p);
+
+ return "$p\n$content";
+}
+
+//
+// Misc
+//
+
+/**
+ * Retrieve protected post password form content.
+ *
+ * @since 1.0.0
+ * @uses apply_filters() Calls 'the_password_form' filter on output.
+ *
+ * @return string HTML content for password form for password protected post.
+ */
+function get_the_password_form() {
+ global $post;
+ $label = 'pwbox-'.(empty($post->ID) ? rand() : $post->ID);
+ $output = '
+ ';
+ return apply_filters('the_password_form', $output);
+}
+
+/**
+ * Whether currently in a page template.
+ *
+ * This template tag allows you to determine whether or not you are in a page
+ * template. You can optional provide a template name and then the check will be
+ * specific to that template.
+ *
+ * @since 2.5.0
+ * @uses $wp_query
+ *
+ * @param string $template The specific template name if specific matching is required.
+ * @return bool False on failure, true if success.
+ */
+function is_page_template($template = '') {
+ if (!is_page()) {
+ return false;
+ }
+
+ global $wp_query;
+
+ $page = $wp_query->get_queried_object();
+ $custom_fields = get_post_custom_values('_wp_page_template',$page->ID);
+ $page_template = $custom_fields[0];
+
+ // We have no argument passed so just see if a page_template has been specified
+ if ( empty( $template ) ) {
+ if (!empty( $page_template ) ) {
+ return true;
+ }
+ } elseif ( $template == $page_template) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Retrieve formatted date timestamp of a revision (linked to that revisions's page).
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses date_i18n()
+ *
+ * @param int|object $revision Revision ID or revision object.
+ * @param bool $link Optional, default is true. Link to revisions's page?
+ * @return string i18n formatted datetimestamp or localized 'Current Revision'.
+ */
+function wp_post_revision_title( $revision, $link = true ) {
+ if ( !$revision = get_post( $revision ) )
+ return $revision;
+
+ if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) )
+ return false;
+
+ $datef = _c( 'j F, Y @ G:i|revision date format');
+ $autosavef = __( '%s [Autosave]' );
+ $currentf = __( '%s [Current Revision]' );
+
+ $date = date_i18n( $datef, strtotime( $revision->post_modified_gmt . ' +0000' ) );
+ if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) )
+ $date = "$date ";
+
+ if ( !wp_is_post_revision( $revision ) )
+ $date = sprintf( $currentf, $date );
+ elseif ( wp_is_post_autosave( $revision ) )
+ $date = sprintf( $autosavef, $date );
+
+ return $date;
+}
+
+/**
+ * Display list of a post's revisions.
+ *
+ * Can output either a UL with edit links or a TABLE with diff interface, and
+ * restore action links.
+ *
+ * Second argument controls parameters:
+ * (bool) parent : include the parent (the "Current Revision") in the list.
+ * (string) format : 'list' or 'form-table'. 'list' outputs UL, 'form-table'
+ * outputs TABLE with UI.
+ * (int) right : what revision is currently being viewed - used in
+ * form-table format.
+ * (int) left : what revision is currently being diffed against right -
+ * used in form-table format.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses wp_get_post_revisions()
+ * @uses wp_post_revision_title()
+ * @uses get_edit_post_link()
+ * @uses get_author_name()
+ *
+ * @todo split into two functions (list, form-table) ?
+ *
+ * @param int|object $post_id Post ID or post object.
+ * @param string|array $args See description {@link wp_parse_args()}.
+ * @return null
+ */
+function wp_list_post_revisions( $post_id = 0, $args = null ) {
+ if ( !$post = get_post( $post_id ) )
+ return;
+
+ $defaults = array( 'parent' => false, 'right' => false, 'left' => false, 'format' => 'list', 'type' => 'all' );
+ extract( wp_parse_args( $args, $defaults ), EXTR_SKIP );
+
+ switch ( $type ) {
+ case 'autosave' :
+ if ( !$autosave = wp_get_post_autosave( $post->ID ) )
+ return;
+ $revisions = array( $autosave );
+ break;
+ case 'revision' : // just revisions - remove autosave later
+ case 'all' :
+ default :
+ if ( !$revisions = wp_get_post_revisions( $post->ID ) )
+ return;
+ break;
+ }
+
+ $titlef = _c( '%1$s by %2$s|post revision 1:datetime, 2:name' );
+
+ if ( $parent )
+ array_unshift( $revisions, $post );
+
+ $rows = '';
+ $class = false;
+ $can_edit_post = current_user_can( 'edit_post', $post->ID );
+ foreach ( $revisions as $revision ) {
+ if ( !current_user_can( 'read_post', $revision->ID ) )
+ continue;
+ if ( 'revision' === $type && wp_is_post_autosave( $revision ) )
+ continue;
+
+ $date = wp_post_revision_title( $revision );
+ $name = get_author_name( $revision->post_author );
+
+ if ( 'form-table' == $format ) {
+ if ( $left )
+ $left_checked = $left == $revision->ID ? ' checked="checked"' : '';
+ else
+ $left_checked = $right_checked ? ' checked="checked"' : ''; // [sic] (the next one)
+ $right_checked = $right == $revision->ID ? ' checked="checked"' : '';
+
+ $class = $class ? '' : " class='alternate'";
+
+ if ( $post->ID != $revision->ID && $can_edit_post )
+ $actions = 'ID|$revision->ID" ) . '">' . __( 'Restore' ) . ' ';
+ else
+ $actions = '';
+
+ $rows .= "\n";
+ $rows .= "\t \n";
+ $rows .= "\t$date\n";
+ $rows .= "\t$name\n";
+ $rows .= "\t$actions\n";
+ $rows .= "\n";
+ } else {
+ $title = sprintf( $titlef, $date, $name );
+ $rows .= "\t$title \n";
+ }
+ }
+
+ if ( 'form-table' == $format ) : ?>
+
+
+
+\n";
+ echo $rows;
+ echo "";
+ endif;
+
+}
diff -uNr a/blog/wp-includes/query.php b/blog/wp-includes/query.php
--- a/blog/wp-includes/query.php false
+++ b/blog/wp-includes/query.php 74a9f6d5ceb0939b2366905c62c1edc2f08c09c1864e33d730bbec93e293ab03b3b8aec4ebe9f9b2fbe347c9a34d747c13ae65452a6de51489405793ea4efc0f
@@ -0,0 +1,2684 @@
+get($var);
+}
+
+/**
+ * Set query variable.
+ *
+ * @see WP_Query::set()
+ * @since 2.2.0
+ * @uses $wp_query
+ *
+ * @param string $var Query variable key.
+ * @param mixed $value
+ * @return null
+ */
+function set_query_var($var, $value) {
+ global $wp_query;
+
+ return $wp_query->set($var, $value);
+}
+
+/**
+ * Setup The Loop with query parameters.
+ *
+ * This will override the current WordPress Loop and shouldn't be used more than
+ * once. This must not be used within the WordPress Loop.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param string $query
+ * @return array List of posts
+ */
+function &query_posts($query) {
+ unset($GLOBALS['wp_query']);
+ $GLOBALS['wp_query'] = new WP_Query();
+ return $GLOBALS['wp_query']->query($query);
+}
+
+/**
+ * Destroy the previous query and setup a new query.
+ *
+ * This should be used after {@link query_posts()} and before another {@link
+ * query_posts()}. This will remove obscure bugs that occur when the previous
+ * wp_query object is not destroyed properly before another is setup.
+ *
+ * @since 2.3.0
+ * @uses $wp_query
+ */
+function wp_reset_query() {
+ unset($GLOBALS['wp_query']);
+ $GLOBALS['wp_query'] =& $GLOBALS['wp_the_query'];
+ global $wp_query;
+ if ( !empty($wp_query->post) ) {
+ $GLOBALS['post'] = $wp_query->post;
+ setup_postdata($wp_query->post);
+ }
+}
+
+/*
+ * Query type checks.
+ */
+
+/**
+ * Whether the current request is in WordPress admin Panel
+ *
+ * Does not inform on whether the user is an admin! Use capability checks to
+ * tell if the user should be accessing a section or not.
+ *
+ * @since 1.5.1
+ *
+ * @return bool True if inside WordPress administration pages.
+ */
+function is_admin () {
+ if ( defined('WP_ADMIN') )
+ return WP_ADMIN;
+ return false;
+}
+
+/**
+ * Is query requesting an archive page.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool True if page is archive.
+ */
+function is_archive () {
+ global $wp_query;
+
+ return $wp_query->is_archive;
+}
+
+/**
+ * Is query requesting an attachment page.
+ *
+ * @since 2.0.0
+ * @uses $wp_query
+ *
+ * @return bool True if page is attachment.
+ */
+function is_attachment () {
+ global $wp_query;
+
+ return $wp_query->is_attachment;
+}
+
+/**
+ * Is query requesting an author page.
+ *
+ * If the $author parameter is specified then the check will be expanded to
+ * include whether the queried author matches the one given in the parameter.
+ * You can match against integers and against strings.
+ *
+ * If matching against an integer, the ID should be used of the author for the
+ * test. If the $author is an ID and matches the author page user ID, then
+ * 'true' will be returned.
+ *
+ * If matching against strings, then the test will be matched against both the
+ * nickname and user nicename and will return true on success.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param string|int $author Optional. Is current page this author.
+ * @return bool True if page is author or $author (if set).
+ */
+function is_author ($author = '') {
+ global $wp_query;
+
+ if ( !$wp_query->is_author )
+ return false;
+
+ if ( empty($author) )
+ return true;
+
+ $author_obj = $wp_query->get_queried_object();
+
+ $author = (array) $author;
+
+ if ( in_array( $author_obj->ID, $author ) )
+ return true;
+ elseif ( in_array( $author_obj->nickname, $author ) )
+ return true;
+ elseif ( in_array( $author_obj->user_nicename, $author ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Whether current page query contains a category name or given category name.
+ *
+ * The category list can contain category IDs, names, or category slugs. If any
+ * of them are part of the query, then it will return true.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param string|array $category Optional.
+ * @return bool
+ */
+function is_category ($category = '') {
+ global $wp_query;
+
+ if ( !$wp_query->is_category )
+ return false;
+
+ if ( empty($category) )
+ return true;
+
+ $cat_obj = $wp_query->get_queried_object();
+
+ $category = (array) $category;
+
+ if ( in_array( $cat_obj->term_id, $category ) )
+ return true;
+ elseif ( in_array( $cat_obj->name, $category ) )
+ return true;
+ elseif ( in_array( $cat_obj->slug, $category ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Whether the current page query has the given tag slug or contains tag.
+ *
+ * @since 2.3.0
+ * @uses $wp_query
+ *
+ * @param string|array $slug Optional. Single tag or list of tags to check for.
+ * @return bool
+ */
+function is_tag( $slug = '' ) {
+ global $wp_query;
+
+ if ( !$wp_query->is_tag )
+ return false;
+
+ if ( empty( $slug ) )
+ return true;
+
+ $tag_obj = $wp_query->get_queried_object();
+
+ $slug = (array) $slug;
+
+ if ( in_array( $tag_obj->slug, $slug ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Whether the current page query has the given taxonomy slug or contains taxonomy.
+ *
+ * @since 2.5.0
+ * @uses $wp_query
+ *
+ * @param string|array $slug Optional. Slug or slugs to check in current query.
+ * @return bool
+ */
+function is_tax( $slug = '' ) {
+ global $wp_query;
+
+ if ( !$wp_query->is_tax )
+ return false;
+
+ if ( empty($slug) )
+ return true;
+
+ $term = $wp_query->get_queried_object();
+
+ $slug = (array) $slug;
+
+ if ( in_array( $term->slug, $slug ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Whether the current URL is within the comments popup window.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_comments_popup () {
+ global $wp_query;
+
+ return $wp_query->is_comments_popup;
+}
+
+/**
+ * Whether current URL is based on a date.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_date () {
+ global $wp_query;
+
+ return $wp_query->is_date;
+}
+
+/**
+ * Whether current blog URL contains a day.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_day () {
+ global $wp_query;
+
+ return $wp_query->is_day;
+}
+
+/**
+ * Whether current page query is feed URL.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_feed () {
+ global $wp_query;
+
+ return $wp_query->is_feed;
+}
+
+/**
+ * Whether current page query is the front of the site.
+ *
+ * @since 2.5.0
+ * @uses is_home()
+ * @uses get_option()
+ *
+ * @return bool True, if front of site.
+ */
+function is_front_page () {
+ // most likely case
+ if ( 'posts' == get_option('show_on_front') && is_home() )
+ return true;
+ elseif ( 'page' == get_option('show_on_front') && get_option('page_on_front') && is_page(get_option('page_on_front')) )
+ return true;
+ else
+ return false;
+}
+
+/**
+ * Whether current page view is the blog homepage.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool True if blog view homepage.
+ */
+function is_home () {
+ global $wp_query;
+
+ return $wp_query->is_home;
+}
+
+/**
+ * Whether current page query contains a month.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_month () {
+ global $wp_query;
+
+ return $wp_query->is_month;
+}
+
+/**
+ * Whether query is page or contains given page(s).
+ *
+ * Calls the function without any parameters will only test whether the current
+ * query is of the page type. Either a list or a single item can be tested
+ * against for whether the query is a page and also is the value or one of the
+ * values in the page parameter.
+ *
+ * The parameter can contain the page ID, page title, or page name. The
+ * parameter can also be an array of those three values.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $page Either page or list of pages to test against.
+ * @return bool
+ */
+function is_page ($page = '') {
+ global $wp_query;
+
+ if ( !$wp_query->is_page )
+ return false;
+
+ if ( empty($page) )
+ return true;
+
+ $page_obj = $wp_query->get_queried_object();
+
+ $page = (array) $page;
+
+ if ( in_array( $page_obj->ID, $page ) )
+ return true;
+ elseif ( in_array( $page_obj->post_title, $page ) )
+ return true;
+ else if ( in_array( $page_obj->post_name, $page ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Whether query contains multiple pages for the results.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_paged () {
+ global $wp_query;
+
+ return $wp_query->is_paged;
+}
+
+/**
+ * Whether the current page was created by a plugin.
+ *
+ * The plugin can set this by using the global $plugin_page and setting it to
+ * true.
+ *
+ * @since 1.5.0
+ * @global bool $plugin_page Used by plugins to tell the query that current is a plugin page.
+ *
+ * @return bool
+ */
+function is_plugin_page() {
+ global $plugin_page;
+
+ if ( isset($plugin_page) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Whether the current query is preview of post or page.
+ *
+ * @since 2.0.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_preview() {
+ global $wp_query;
+
+ return $wp_query->is_preview;
+}
+
+/**
+ * Whether the current query post is robots.
+ *
+ * @since 2.1.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_robots() {
+ global $wp_query;
+
+ return $wp_query->is_robots;
+}
+
+/**
+ * Whether current query is the result of a user search.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_search () {
+ global $wp_query;
+
+ return $wp_query->is_search;
+}
+
+/**
+ * Whether the current page query is single page.
+ *
+ * The parameter can contain the post ID, post title, or post name. The
+ * parameter can also be an array of those three values.
+ *
+ * This applies to other post types, attachments, pages, posts. Just means that
+ * the current query has only a single object.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $post Either post or list of posts to test against.
+ * @return bool
+ */
+function is_single ($post = '') {
+ global $wp_query;
+
+ if ( !$wp_query->is_single )
+ return false;
+
+ if ( empty( $post) )
+ return true;
+
+ $post_obj = $wp_query->get_queried_object();
+
+ $post = (array) $post;
+
+ if ( in_array( $post_obj->ID, $post ) )
+ return true;
+ elseif ( in_array( $post_obj->post_title, $post ) )
+ return true;
+ elseif ( in_array( $post_obj->post_name, $post ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Whether is single post, is a page, or is an attachment.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_singular() {
+ global $wp_query;
+
+ return $wp_query->is_singular;
+}
+
+/**
+ * Whether the query contains a time.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_time () {
+ global $wp_query;
+
+ return $wp_query->is_time;
+}
+
+/**
+ * Whether the query is a trackback.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_trackback () {
+ global $wp_query;
+
+ return $wp_query->is_trackback;
+}
+
+/**
+ * Whether the query contains a year.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_year () {
+ global $wp_query;
+
+ return $wp_query->is_year;
+}
+
+/**
+ * Whether current page query is a 404 and no results for WordPress query.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool True, if nothing is found matching WordPress Query.
+ */
+function is_404 () {
+ global $wp_query;
+
+ return $wp_query->is_404;
+}
+
+/*
+ * The Loop. Post loop control.
+ */
+
+/**
+ * Whether current WordPress query has results to loop over.
+ *
+ * @see WP_Query::have_posts()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function have_posts() {
+ global $wp_query;
+
+ return $wp_query->have_posts();
+}
+
+/**
+ * Whether the caller is in the Loop.
+ *
+ * @since 2.0.0
+ * @uses $wp_query
+ *
+ * @return bool True if caller is within loop, false if loop hasn't started or ended.
+ */
+function in_the_loop() {
+ global $wp_query;
+
+ return $wp_query->in_the_loop;
+}
+
+/**
+ * Rewind the loop posts.
+ *
+ * @see WP_Query::rewind_posts()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return null
+ */
+function rewind_posts() {
+ global $wp_query;
+
+ return $wp_query->rewind_posts();
+}
+
+/**
+ * Iterate the post index in the loop.
+ *
+ * @see WP_Query::the_post()
+ * @since 1.5.0
+ * @uses $wp_query
+ */
+function the_post() {
+ global $wp_query;
+
+ $wp_query->the_post();
+}
+
+/*
+ * Comments loop.
+ */
+
+/**
+ * Whether there are comments to loop over.
+ *
+ * @see WP_Query::have_comments()
+ * @since 2.2.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function have_comments() {
+ global $wp_query;
+ return $wp_query->have_comments();
+}
+
+/**
+ * Iterate comment index in the comment loop.
+ *
+ * @see WP_Query::the_comment()
+ * @since 2.2.0
+ * @uses $wp_query
+ *
+ * @return object
+ */
+function the_comment() {
+ global $wp_query;
+ return $wp_query->the_comment();
+}
+
+/*
+ * WP_Query
+ */
+
+/**
+ * The WordPress Query class.
+ *
+ * @link http://codex.wordpress.org/Function_Reference/WP_Query Codex page.
+ *
+ * @since 1.5.0
+ */
+class WP_Query {
+
+ /**
+ * Query string
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $query;
+
+ /**
+ * Query search variables set by the user.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var array
+ */
+ var $query_vars = array();
+
+ /**
+ * Holds the data for a single object that is queried.
+ *
+ * Holds the contents of a post, page, category, attachment.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var object|array
+ */
+ var $queried_object;
+
+ /**
+ * The ID of the queried object.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var int
+ */
+ var $queried_object_id;
+
+ /**
+ * Get post database query.
+ *
+ * @since 2.0.1
+ * @access public
+ * @var string
+ */
+ var $request;
+
+ /**
+ * List of posts.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var array
+ */
+ var $posts;
+
+ /**
+ * The amount of posts for the current query.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var int
+ */
+ var $post_count = 0;
+
+ /**
+ * Index of the current item in the loop.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var int
+ */
+ var $current_post = -1;
+
+ /**
+ * Whether the loop has started and the caller is in the loop.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $in_the_loop = false;
+
+ /**
+ * The current post ID.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var int
+ */
+ var $post;
+
+ /**
+ * The list of comments for current post.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var array
+ */
+ var $comments;
+
+ /**
+ * The amount of comments for the posts.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var int
+ */
+ var $comment_count = 0;
+
+ /**
+ * The index of the comment in the comment loop.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var int
+ */
+ var $current_comment = -1;
+
+ /**
+ * Current comment ID.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var int
+ */
+ var $comment;
+
+ /**
+ * Amount of posts if limit clause was not used.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var int
+ */
+ var $found_posts = 0;
+
+ /**
+ * The amount of pages.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var int
+ */
+ var $max_num_pages = 0;
+
+ /**
+ * The amount of comment pages.
+ *
+ * @since 2.7.0
+ * @access public
+ * @var int
+ */
+ var $max_num_comment_pages = 0;
+
+ /**
+ * Set if query is single post.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_single = false;
+
+ /**
+ * Set if query is preview of blog.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $is_preview = false;
+
+ /**
+ * Set if query returns a page.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_page = false;
+
+ /**
+ * Set if query is an archive list.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_archive = false;
+
+ /**
+ * Set if query is part of a date.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_date = false;
+
+ /**
+ * Set if query contains a year.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_year = false;
+
+ /**
+ * Set if query contains a month.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_month = false;
+
+ /**
+ * Set if query contains a day.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_day = false;
+
+ /**
+ * Set if query contains time.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_time = false;
+
+ /**
+ * Set if query contains an author.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_author = false;
+
+ /**
+ * Set if query contains category.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_category = false;
+
+ /**
+ * Set if query contains tag.
+ *
+ * @since 2.3.0
+ * @access public
+ * @var bool
+ */
+ var $is_tag = false;
+
+ /**
+ * Set if query contains taxonomy.
+ *
+ * @since 2.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_tax = false;
+
+ /**
+ * Set if query was part of a search result.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_search = false;
+
+ /**
+ * Set if query is feed display.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_feed = false;
+
+ /**
+ * Set if query is comment feed display.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var bool
+ */
+ var $is_comment_feed = false;
+
+ /**
+ * Set if query is trackback.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_trackback = false;
+
+ /**
+ * Set if query is blog homepage.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_home = false;
+
+ /**
+ * Set if query couldn't found anything.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_404 = false;
+
+ /**
+ * Set if query is within comments popup window.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_comments_popup = false;
+
+ /**
+ * Set if query is part of administration page.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_admin = false;
+
+ /**
+ * Set if query is an attachment.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $is_attachment = false;
+
+ /**
+ * Set if is single, is a page, or is an attachment.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var bool
+ */
+ var $is_singular = false;
+
+ /**
+ * Set if query is for robots.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var bool
+ */
+ var $is_robots = false;
+
+ /**
+ * Set if query contains posts.
+ *
+ * Basically, the homepage if the option isn't set for the static homepage.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var bool
+ */
+ var $is_posts_page = false;
+
+ /**
+ * Resets query flags to false.
+ *
+ * The query flags are what page info WordPress was able to figure out.
+ *
+ * @since 2.0.0
+ * @access private
+ */
+ function init_query_flags() {
+ $this->is_single = false;
+ $this->is_page = false;
+ $this->is_archive = false;
+ $this->is_date = false;
+ $this->is_year = false;
+ $this->is_month = false;
+ $this->is_day = false;
+ $this->is_time = false;
+ $this->is_author = false;
+ $this->is_category = false;
+ $this->is_tag = false;
+ $this->is_tax = false;
+ $this->is_search = false;
+ $this->is_feed = false;
+ $this->is_comment_feed = false;
+ $this->is_trackback = false;
+ $this->is_home = false;
+ $this->is_404 = false;
+ $this->is_paged = false;
+ $this->is_admin = false;
+ $this->is_attachment = false;
+ $this->is_singular = false;
+ $this->is_robots = false;
+ $this->is_posts_page = false;
+ }
+
+ /**
+ * Initiates object properties and sets default values.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function init () {
+ unset($this->posts);
+ unset($this->query);
+ $this->query_vars = array();
+ unset($this->queried_object);
+ unset($this->queried_object_id);
+ $this->post_count = 0;
+ $this->current_post = -1;
+ $this->in_the_loop = false;
+
+ $this->init_query_flags();
+ }
+
+ /**
+ * Reparse the query vars.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function parse_query_vars() {
+ $this->parse_query('');
+ }
+
+ /**
+ * Fills in the query variables, which do not exist within the parameter.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param array $array Defined query variables.
+ * @return array Complete query variables with undefined ones filled in empty.
+ */
+ function fill_query_vars($array) {
+ $keys = array(
+ 'error'
+ , 'm'
+ , 'p'
+ , 'post_parent'
+ , 'subpost'
+ , 'subpost_id'
+ , 'attachment'
+ , 'attachment_id'
+ , 'name'
+ , 'hour'
+ , 'static'
+ , 'pagename'
+ , 'page_id'
+ , 'second'
+ , 'minute'
+ , 'hour'
+ , 'day'
+ , 'monthnum'
+ , 'year'
+ , 'w'
+ , 'category_name'
+ , 'tag'
+ , 'cat'
+ , 'tag_id'
+ , 'author_name'
+ , 'feed'
+ , 'tb'
+ , 'paged'
+ , 'comments_popup'
+ , 'meta_key'
+ , 'meta_value'
+ , 'preview'
+ );
+
+ foreach ($keys as $key) {
+ if ( !isset($array[$key]))
+ $array[$key] = '';
+ }
+
+ $array_keys = array('category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in',
+ 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and');
+
+ foreach ( $array_keys as $key ) {
+ if ( !isset($array[$key]))
+ $array[$key] = array();
+ }
+ return $array;
+ }
+
+ /**
+ * Parse a query string and set query type booleans.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string|array $query
+ */
+ function parse_query ($query) {
+ if ( !empty($query) || !isset($this->query) ) {
+ $this->init();
+ if ( is_array($query) )
+ $this->query_vars = $query;
+ else
+ parse_str($query, $this->query_vars);
+ $this->query = $query;
+ }
+
+ $this->query_vars = $this->fill_query_vars($this->query_vars);
+ $qv = &$this->query_vars;
+
+ if ( ! empty($qv['robots']) )
+ $this->is_robots = true;
+
+ $qv['p'] = absint($qv['p']);
+ $qv['page_id'] = absint($qv['page_id']);
+ $qv['year'] = absint($qv['year']);
+ $qv['monthnum'] = absint($qv['monthnum']);
+ $qv['day'] = absint($qv['day']);
+ $qv['w'] = absint($qv['w']);
+ $qv['m'] = absint($qv['m']);
+ $qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers
+ $qv['pagename'] = trim( $qv['pagename'] );
+ $qv['name'] = trim( $qv['name'] );
+ if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']);
+ if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']);
+ if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']);
+
+ // Compat. Map subpost to attachment.
+ if ( '' != $qv['subpost'] )
+ $qv['attachment'] = $qv['subpost'];
+ if ( '' != $qv['subpost_id'] )
+ $qv['attachment_id'] = $qv['subpost_id'];
+
+ $qv['attachment_id'] = absint($qv['attachment_id']);
+
+ if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
+ $this->is_single = true;
+ $this->is_attachment = true;
+ } elseif ( '' != $qv['name'] ) {
+ $this->is_single = true;
+ } elseif ( $qv['p'] ) {
+ $this->is_single = true;
+ } elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) {
+ // If year, month, day, hour, minute, and second are set, a single
+ // post is being queried.
+ $this->is_single = true;
+ } elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) {
+ $this->is_page = true;
+ $this->is_single = false;
+ } elseif ( !empty($qv['s']) ) {
+ $this->is_search = true;
+ } else {
+ // Look for archive queries. Dates, categories, authors.
+
+ if ( '' !== $qv['second'] ) {
+ $this->is_time = true;
+ $this->is_date = true;
+ }
+
+ if ( '' !== $qv['minute'] ) {
+ $this->is_time = true;
+ $this->is_date = true;
+ }
+
+ if ( '' !== $qv['hour'] ) {
+ $this->is_time = true;
+ $this->is_date = true;
+ }
+
+ if ( $qv['day'] ) {
+ if (! $this->is_date) {
+ $this->is_day = true;
+ $this->is_date = true;
+ }
+ }
+
+ if ( $qv['monthnum'] ) {
+ if (! $this->is_date) {
+ $this->is_month = true;
+ $this->is_date = true;
+ }
+ }
+
+ if ( $qv['year'] ) {
+ if (! $this->is_date) {
+ $this->is_year = true;
+ $this->is_date = true;
+ }
+ }
+
+ if ( $qv['m'] ) {
+ $this->is_date = true;
+ if (strlen($qv['m']) > 9) {
+ $this->is_time = true;
+ } else if (strlen($qv['m']) > 7) {
+ $this->is_day = true;
+ } else if (strlen($qv['m']) > 5) {
+ $this->is_month = true;
+ } else {
+ $this->is_year = true;
+ }
+ }
+
+ if ('' != $qv['w']) {
+ $this->is_date = true;
+ }
+
+ if ( empty($qv['cat']) || ($qv['cat'] == '0') ) {
+ $this->is_category = false;
+ } else {
+ if (strpos($qv['cat'], '-') !== false) {
+ $this->is_category = false;
+ } else {
+ $this->is_category = true;
+ }
+ }
+
+ if ( '' != $qv['category_name'] ) {
+ $this->is_category = true;
+ }
+
+ if ( !is_array($qv['category__in']) || empty($qv['category__in']) ) {
+ $qv['category__in'] = array();
+ } else {
+ $qv['category__in'] = array_map('absint', $qv['category__in']);
+ $this->is_category = true;
+ }
+
+ if ( !is_array($qv['category__not_in']) || empty($qv['category__not_in']) ) {
+ $qv['category__not_in'] = array();
+ } else {
+ $qv['category__not_in'] = array_map('absint', $qv['category__not_in']);
+ }
+
+ if ( !is_array($qv['category__and']) || empty($qv['category__and']) ) {
+ $qv['category__and'] = array();
+ } else {
+ $qv['category__and'] = array_map('absint', $qv['category__and']);
+ $this->is_category = true;
+ }
+
+ if ( '' != $qv['tag'] )
+ $this->is_tag = true;
+
+ $qv['tag_id'] = absint($qv['tag_id']);
+ if ( !empty($qv['tag_id']) )
+ $this->is_tag = true;
+
+ if ( !is_array($qv['tag__in']) || empty($qv['tag__in']) ) {
+ $qv['tag__in'] = array();
+ } else {
+ $qv['tag__in'] = array_map('absint', $qv['tag__in']);
+ $this->is_tag = true;
+ }
+
+ if ( !is_array($qv['tag__not_in']) || empty($qv['tag__not_in']) ) {
+ $qv['tag__not_in'] = array();
+ } else {
+ $qv['tag__not_in'] = array_map('absint', $qv['tag__not_in']);
+ }
+
+ if ( !is_array($qv['tag__and']) || empty($qv['tag__and']) ) {
+ $qv['tag__and'] = array();
+ } else {
+ $qv['tag__and'] = array_map('absint', $qv['tag__and']);
+ $this->is_category = true;
+ }
+
+ if ( !is_array($qv['tag_slug__in']) || empty($qv['tag_slug__in']) ) {
+ $qv['tag_slug__in'] = array();
+ } else {
+ $qv['tag_slug__in'] = array_map('sanitize_title', $qv['tag_slug__in']);
+ $this->is_tag = true;
+ }
+
+ if ( !is_array($qv['tag_slug__and']) || empty($qv['tag_slug__and']) ) {
+ $qv['tag_slug__and'] = array();
+ } else {
+ $qv['tag_slug__and'] = array_map('sanitize_title', $qv['tag_slug__and']);
+ $this->is_tag = true;
+ }
+
+ if ( empty($qv['taxonomy']) || empty($qv['term']) ) {
+ $this->is_tax = false;
+ foreach ( $GLOBALS['wp_taxonomies'] as $t ) {
+ if ( isset($t->query_var) && isset($qv[$t->query_var]) && '' != $qv[$t->query_var] ) {
+ $this->is_tax = true;
+ break;
+ }
+ }
+ } else {
+ $this->is_tax = true;
+ }
+
+ if ( empty($qv['author']) || ($qv['author'] == '0') ) {
+ $this->is_author = false;
+ } else {
+ $this->is_author = true;
+ }
+
+ if ( '' != $qv['author_name'] ) {
+ $this->is_author = true;
+ }
+
+ if ( ($this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax) )
+ $this->is_archive = true;
+ }
+
+ if ( '' != $qv['feed'] )
+ $this->is_feed = true;
+
+ if ( '' != $qv['tb'] )
+ $this->is_trackback = true;
+
+ if ( '' != $qv['paged'] )
+ $this->is_paged = true;
+
+ if ( '' != $qv['comments_popup'] )
+ $this->is_comments_popup = true;
+
+ // if we're previewing inside the write screen
+ if ('' != $qv['preview'])
+ $this->is_preview = true;
+
+ if ( is_admin() )
+ $this->is_admin = true;
+
+ if ( false !== strpos($qv['feed'], 'comments-') ) {
+ $qv['feed'] = str_replace('comments-', '', $qv['feed']);
+ $qv['withcomments'] = 1;
+ }
+
+ $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
+
+ if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
+ $this->is_comment_feed = true;
+
+ if ( !( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_comments_popup ) )
+ $this->is_home = true;
+
+ // Correct is_* for page_on_front and page_for_posts
+ if ( $this->is_home && ( empty($this->query) || $qv['preview'] == 'true' ) && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
+ $this->is_page = true;
+ $this->is_home = false;
+ $qv['page_id'] = get_option('page_on_front');
+ }
+
+ if ( '' != $qv['pagename'] ) {
+ $this->queried_object =& get_page_by_path($qv['pagename']);
+ if ( !empty($this->queried_object) )
+ $this->queried_object_id = (int) $this->queried_object->ID;
+ else
+ unset($this->queried_object);
+
+ if ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) {
+ $this->is_page = false;
+ $this->is_home = true;
+ $this->is_posts_page = true;
+ }
+ }
+
+ if ( $qv['page_id'] ) {
+ if ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
+ $this->is_page = false;
+ $this->is_home = true;
+ $this->is_posts_page = true;
+ }
+ }
+
+ if ( !empty($qv['post_type']) )
+ $qv['post_type'] = sanitize_user($qv['post_type'], true);
+
+ if ( !empty($qv['post_status']) )
+ $qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']);
+
+ if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) )
+ $this->is_comment_feed = false;
+
+ $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
+ // Done correcting is_* for page_on_front and page_for_posts
+
+ if ('404' == $qv['error'])
+ $this->set_404();
+
+ if ( !empty($query) )
+ do_action_ref_array('parse_query', array(&$this));
+ }
+
+ /**
+ * Sets the 404 property and saves whether query is feed.
+ *
+ * @since 2.0.0
+ * @access public
+ */
+ function set_404() {
+ $is_feed = $this->is_feed;
+
+ $this->init_query_flags();
+ $this->is_404 = true;
+
+ $this->is_feed = $is_feed;
+ }
+
+ /**
+ * Retrieve query variable.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query_var Query variable key.
+ * @return mixed
+ */
+ function get($query_var) {
+ if (isset($this->query_vars[$query_var])) {
+ return $this->query_vars[$query_var];
+ }
+
+ return '';
+ }
+
+ /**
+ * Set query variable.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query_var Query variable key.
+ * @param mixed $value Query variable value.
+ */
+ function set($query_var, $value) {
+ $this->query_vars[$query_var] = $value;
+ }
+
+ /**
+ * Retrieve the posts based on query variables.
+ *
+ * There are a few filters and actions that can be used to modify the post
+ * database query.
+ *
+ * @since 1.5.0
+ * @access public
+ * @uses do_action_ref_array() Calls 'pre_get_posts' hook before retrieving posts.
+ *
+ * @return array List of posts.
+ */
+ function &get_posts() {
+ global $wpdb, $user_ID;
+
+ do_action_ref_array('pre_get_posts', array(&$this));
+
+ // Shorthand.
+ $q = &$this->query_vars;
+
+ $q = $this->fill_query_vars($q);
+
+ // First let's clear some variables
+ $distinct = '';
+ $whichcat = '';
+ $whichauthor = '';
+ $whichmimetype = '';
+ $where = '';
+ $limits = '';
+ $join = '';
+ $search = '';
+ $groupby = '';
+ $fields = "$wpdb->posts.*";
+ $post_status_join = false;
+ $page = 1;
+
+ if ( !isset($q['caller_get_posts']) )
+ $q['caller_get_posts'] = false;
+
+ if ( !isset($q['suppress_filters']) )
+ $q['suppress_filters'] = false;
+
+ if ( !isset($q['post_type']) ) {
+ if ( $this->is_search )
+ $q['post_type'] = 'any';
+ else
+ $q['post_type'] = 'post';
+ }
+ $post_type = $q['post_type'];
+ if ( !isset($q['posts_per_page']) || $q['posts_per_page'] == 0 )
+ $q['posts_per_page'] = get_option('posts_per_page');
+ if ( isset($q['showposts']) && $q['showposts'] ) {
+ $q['showposts'] = (int) $q['showposts'];
+ $q['posts_per_page'] = $q['showposts'];
+ }
+ if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
+ $q['posts_per_page'] = $q['posts_per_archive_page'];
+ if ( !isset($q['nopaging']) ) {
+ if ($q['posts_per_page'] == -1) {
+ $q['nopaging'] = true;
+ } else {
+ $q['nopaging'] = false;
+ }
+ }
+ if ( $this->is_feed ) {
+ $q['posts_per_page'] = get_option('posts_per_rss');
+ $q['nopaging'] = false;
+ }
+ $q['posts_per_page'] = (int) $q['posts_per_page'];
+ if ( $q['posts_per_page'] < -1 )
+ $q['posts_per_page'] = abs($q['posts_per_page']);
+ else if ( $q['posts_per_page'] == 0 )
+ $q['posts_per_page'] = 1;
+
+ if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
+ $q['comments_per_page'] = get_option('comments_per_page');
+
+ if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
+ $this->is_page = true;
+ $this->is_home = false;
+ $q['page_id'] = get_option('page_on_front');
+ }
+
+ if (isset($q['page'])) {
+ $q['page'] = trim($q['page'], '/');
+ $q['page'] = absint($q['page']);
+ }
+
+ // If a month is specified in the querystring, load that month
+ if ( $q['m'] ) {
+ $q['m'] = '' . preg_replace('|[^0-9]|', '', $q['m']);
+ $where .= " AND YEAR($wpdb->posts.post_date)=" . substr($q['m'], 0, 4);
+ if (strlen($q['m'])>5)
+ $where .= " AND MONTH($wpdb->posts.post_date)=" . substr($q['m'], 4, 2);
+ if (strlen($q['m'])>7)
+ $where .= " AND DAYOFMONTH($wpdb->posts.post_date)=" . substr($q['m'], 6, 2);
+ if (strlen($q['m'])>9)
+ $where .= " AND HOUR($wpdb->posts.post_date)=" . substr($q['m'], 8, 2);
+ if (strlen($q['m'])>11)
+ $where .= " AND MINUTE($wpdb->posts.post_date)=" . substr($q['m'], 10, 2);
+ if (strlen($q['m'])>13)
+ $where .= " AND SECOND($wpdb->posts.post_date)=" . substr($q['m'], 12, 2);
+ }
+
+ if ( '' !== $q['hour'] )
+ $where .= " AND HOUR($wpdb->posts.post_date)='" . $q['hour'] . "'";
+
+ if ( '' !== $q['minute'] )
+ $where .= " AND MINUTE($wpdb->posts.post_date)='" . $q['minute'] . "'";
+
+ if ( '' !== $q['second'] )
+ $where .= " AND SECOND($wpdb->posts.post_date)='" . $q['second'] . "'";
+
+ if ( $q['year'] )
+ $where .= " AND YEAR($wpdb->posts.post_date)='" . $q['year'] . "'";
+
+ if ( $q['monthnum'] )
+ $where .= " AND MONTH($wpdb->posts.post_date)='" . $q['monthnum'] . "'";
+
+ if ( $q['day'] )
+ $where .= " AND DAYOFMONTH($wpdb->posts.post_date)='" . $q['day'] . "'";
+
+ if ('' != $q['name']) {
+ $q['name'] = sanitize_title($q['name']);
+ $where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";
+ } else if ('' != $q['pagename']) {
+ if ( isset($this->queried_object_id) )
+ $reqpage = $this->queried_object_id;
+ else {
+ $reqpage = get_page_by_path($q['pagename']);
+ if ( !empty($reqpage) )
+ $reqpage = $reqpage->ID;
+ else
+ $reqpage = 0;
+ }
+
+ $page_for_posts = get_option('page_for_posts');
+ if ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
+ $q['pagename'] = str_replace('%2F', '/', urlencode(urldecode($q['pagename'])));
+ $page_paths = '/' . trim($q['pagename'], '/');
+ $q['pagename'] = sanitize_title(basename($page_paths));
+ $q['name'] = $q['pagename'];
+ $where .= " AND ($wpdb->posts.ID = '$reqpage')";
+ $reqpage_obj = get_page($reqpage);
+ if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
+ $this->is_attachment = true;
+ $this->is_page = true;
+ $q['attachment_id'] = $reqpage;
+ }
+ }
+ } elseif ('' != $q['attachment']) {
+ $q['attachment'] = str_replace('%2F', '/', urlencode(urldecode($q['attachment'])));
+ $attach_paths = '/' . trim($q['attachment'], '/');
+ $q['attachment'] = sanitize_title(basename($attach_paths));
+ $q['name'] = $q['attachment'];
+ $where .= " AND $wpdb->posts.post_name = '" . $q['attachment'] . "'";
+ }
+
+ if ( $q['w'] )
+ $where .= " AND WEEK($wpdb->posts.post_date, 1)='" . $q['w'] . "'";
+
+ if ( intval($q['comments_popup']) )
+ $q['p'] = absint($q['comments_popup']);
+
+ // If an attachment is requested by number, let it supercede any post number.
+ if ( $q['attachment_id'] )
+ $q['p'] = absint($q['attachment_id']);
+
+ // If a post number is specified, load that post
+ if ( $q['p'] ) {
+ $where .= " AND {$wpdb->posts}.ID = " . $q['p'];
+ } elseif ( $q['post__in'] ) {
+ $post__in = implode(',', array_map( 'absint', $q['post__in'] ));
+ $where .= " AND {$wpdb->posts}.ID IN ($post__in)";
+ } elseif ( $q['post__not_in'] ) {
+ $post__not_in = implode(',', array_map( 'absint', $q['post__not_in'] ));
+ $where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
+ }
+
+ if ( is_numeric($q['post_parent']) )
+ $where .= $wpdb->prepare( " AND $wpdb->posts.post_parent = %d ", $q['post_parent'] );
+
+ if ( $q['page_id'] ) {
+ if ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
+ $q['p'] = $q['page_id'];
+ $where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
+ }
+ }
+
+ // If a search pattern is specified, load the posts that match
+ if ( !empty($q['s']) ) {
+ // added slashes screw with quote grouping when done early, so done later
+ $q['s'] = stripslashes($q['s']);
+ if ( !empty($q['sentence']) ) {
+ $q['search_terms'] = array($q['s']);
+ } else {
+ preg_match_all('/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $q['s'], $matches);
+ $q['search_terms'] = array_map(create_function('$a', 'return trim($a, "\\"\'\\n\\r ");'), $matches[0]);
+ }
+ $n = !empty($q['exact']) ? '' : '%';
+ $searchand = '';
+ foreach( (array) $q['search_terms'] as $term) {
+ $term = addslashes_gpc($term);
+ $search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";
+ $searchand = ' AND ';
+ }
+ $term = $wpdb->escape($q['s']);
+ if (empty($q['sentence']) && count($q['search_terms']) > 1 && $q['search_terms'][0] != $q['s'] )
+ $search .= " OR ($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}')";
+
+ if ( !empty($search) )
+ $search = " AND ({$search}) ";
+ }
+
+ // Category stuff
+
+ if ( empty($q['cat']) || ($q['cat'] == '0') ||
+ // Bypass cat checks if fetching specific posts
+ $this->is_singular ) {
+ $whichcat = '';
+ } else {
+ $q['cat'] = ''.urldecode($q['cat']).'';
+ $q['cat'] = addslashes_gpc($q['cat']);
+ $cat_array = preg_split('/[,\s]+/', $q['cat']);
+ $q['cat'] = '';
+ $req_cats = array();
+ foreach ( (array) $cat_array as $cat ) {
+ $cat = intval($cat);
+ $req_cats[] = $cat;
+ $in = ($cat > 0);
+ $cat = abs($cat);
+ if ( $in ) {
+ $q['category__in'][] = $cat;
+ $q['category__in'] = array_merge($q['category__in'], get_term_children($cat, 'category'));
+ } else {
+ $q['category__not_in'][] = $cat;
+ $q['category__not_in'] = array_merge($q['category__not_in'], get_term_children($cat, 'category'));
+ }
+ }
+ $q['cat'] = implode(',', $req_cats);
+ }
+
+ if ( !empty($q['category__in']) ) {
+ $groupby = "{$wpdb->posts}.ID";
+ }
+
+ if ( !empty($q['category__in']) ) {
+ $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) ";
+ $whichcat .= " AND $wpdb->term_taxonomy.taxonomy = 'category' ";
+ $include_cats = "'" . implode("', '", $q['category__in']) . "'";
+ $whichcat .= " AND $wpdb->term_taxonomy.term_id IN ($include_cats) ";
+ }
+
+ if ( !empty($q['category__not_in']) ) {
+ if ( $wpdb->has_cap( 'subqueries' ) ) {
+ $cat_string = "'" . implode("', '", $q['category__not_in']) . "'";
+ $whichcat .= " AND $wpdb->posts.ID NOT IN ( SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy = 'category' AND tt.term_id IN ($cat_string) )";
+ } else {
+ $ids = get_objects_in_term($q['category__not_in'], 'category');
+ if ( is_wp_error( $ids ) )
+ $ids = array();
+ if ( is_array($ids) && count($ids > 0) ) {
+ $out_posts = "'" . implode("', '", $ids) . "'";
+ $whichcat .= " AND $wpdb->posts.ID NOT IN ($out_posts)";
+ }
+ }
+ }
+
+ // Category stuff for nice URLs
+ if ( '' != $q['category_name'] && !$this->is_singular ) {
+ $reqcat = get_category_by_path($q['category_name']);
+ $q['category_name'] = str_replace('%2F', '/', urlencode(urldecode($q['category_name'])));
+ $cat_paths = '/' . trim($q['category_name'], '/');
+ $q['category_name'] = sanitize_title(basename($cat_paths));
+
+ $cat_paths = '/' . trim(urldecode($q['category_name']), '/');
+ $q['category_name'] = sanitize_title(basename($cat_paths));
+ $cat_paths = explode('/', $cat_paths);
+ $cat_path = '';
+ foreach ( (array) $cat_paths as $pathdir )
+ $cat_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title($pathdir);
+
+ //if we don't match the entire hierarchy fallback on just matching the nicename
+ if ( empty($reqcat) )
+ $reqcat = get_category_by_path($q['category_name'], false);
+
+ if ( !empty($reqcat) )
+ $reqcat = $reqcat->term_id;
+ else
+ $reqcat = 0;
+
+ $q['cat'] = $reqcat;
+
+ $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) ";
+ $whichcat = " AND $wpdb->term_taxonomy.taxonomy = 'category' ";
+ $in_cats = array($q['cat']);
+ $in_cats = array_merge($in_cats, get_term_children($q['cat'], 'category'));
+ $in_cats = "'" . implode("', '", $in_cats) . "'";
+ $whichcat .= "AND $wpdb->term_taxonomy.term_id IN ($in_cats)";
+ $groupby = "{$wpdb->posts}.ID";
+ }
+
+ // Tags
+ if ( '' != $q['tag'] ) {
+ if ( strpos($q['tag'], ',') !== false ) {
+ $tags = preg_split('/[,\s]+/', $q['tag']);
+ foreach ( (array) $tags as $tag ) {
+ $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
+ $q['tag_slug__in'][] = $tag;
+ }
+ } else if ( preg_match('/[+\s]+/', $q['tag']) ) {
+ $tags = preg_split('/[+\s]+/', $q['tag']);
+ foreach ( (array) $tags as $tag ) {
+ $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
+ $q['tag_slug__and'][] = $tag;
+ }
+ } else {
+ $q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
+ $q['tag_slug__in'][] = $q['tag'];
+ }
+ }
+
+ if ( !empty($q['tag__in']) || !empty($q['tag_slug__in']) ) {
+ $groupby = "{$wpdb->posts}.ID";
+ }
+
+ if ( !empty($q['tag__in']) ) {
+ $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) ";
+ $whichcat .= " AND $wpdb->term_taxonomy.taxonomy = 'post_tag' ";
+ $include_tags = "'" . implode("', '", $q['tag__in']) . "'";
+ $whichcat .= " AND $wpdb->term_taxonomy.term_id IN ($include_tags) ";
+ $reqtag = is_term( $q['tag__in'][0], 'post_tag' );
+ if ( !empty($reqtag) )
+ $q['tag_id'] = $reqtag['term_id'];
+ }
+
+ if ( !empty($q['tag_slug__in']) ) {
+ $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) INNER JOIN $wpdb->terms ON ($wpdb->term_taxonomy.term_id = $wpdb->terms.term_id) ";
+ $whichcat .= " AND $wpdb->term_taxonomy.taxonomy = 'post_tag' ";
+ $include_tags = "'" . implode("', '", $q['tag_slug__in']) . "'";
+ $whichcat .= " AND $wpdb->terms.slug IN ($include_tags) ";
+ $reqtag = get_term_by( 'slug', $q['tag_slug__in'][0], 'post_tag' );
+ if ( !empty($reqtag) )
+ $q['tag_id'] = $reqtag->term_id;
+ }
+
+ if ( !empty($q['tag__not_in']) ) {
+ if ( $wpdb->has_cap( 'subqueries' ) ) {
+ $tag_string = "'" . implode("', '", $q['tag__not_in']) . "'";
+ $whichcat .= " AND $wpdb->posts.ID NOT IN ( SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy = 'post_tag' AND tt.term_id IN ($tag_string) )";
+ } else {
+ $ids = get_objects_in_term($q['tag__not_in'], 'post_tag');
+ if ( is_wp_error( $ids ) )
+ $ids = array();
+ if ( is_array($ids) && count($ids > 0) ) {
+ $out_posts = "'" . implode("', '", $ids) . "'";
+ $whichcat .= " AND $wpdb->posts.ID NOT IN ($out_posts)";
+ }
+ }
+ }
+
+ // Tag and slug intersections.
+ $intersections = array('category__and' => 'category', 'tag__and' => 'post_tag', 'tag_slug__and' => 'post_tag');
+ foreach ($intersections as $item => $taxonomy) {
+ if ( empty($q[$item]) ) continue;
+
+ if ( $item != 'category__and' ) {
+ $reqtag = is_term( $q[$item][0], 'post_tag' );
+ if ( !empty($reqtag) )
+ $q['tag_id'] = $reqtag['term_id'];
+ }
+
+ $taxonomy_field = $item == 'tag_slug__and' ? 'slug' : 'term_id';
+
+ $q[$item] = array_unique($q[$item]);
+ $tsql = "SELECT p.ID FROM $wpdb->posts p INNER JOIN $wpdb->term_relationships tr ON (p.ID = tr.object_id) INNER JOIN $wpdb->term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id) INNER JOIN $wpdb->terms t ON (tt.term_id = t.term_id)";
+ $tsql .= " WHERE tt.taxonomy = '$taxonomy' AND t.$taxonomy_field IN ('" . implode("', '", $q[$item]) . "')";
+ $tsql .= " GROUP BY p.ID HAVING count(p.ID) = " . count($q[$item]);
+
+ $post_ids = $wpdb->get_col($tsql);
+
+ if ( count($post_ids) )
+ $whichcat .= " AND $wpdb->posts.ID IN (" . implode(', ', $post_ids) . ") ";
+ else {
+ $whichcat = " AND 0 = 1";
+ break;
+ }
+ }
+
+ // Taxonomies
+ if ( $this->is_tax ) {
+ if ( '' != $q['taxonomy'] ) {
+ $taxonomy = $q['taxonomy'];
+ $tt[$taxonomy] = $q['term'];
+ $terms = get_terms($q['taxonomy'], array('slug'=>$q['term']));
+ } else {
+ foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) {
+ if ( isset($t->query_var) && '' != $q[$t->query_var] ) {
+ $terms = get_terms($taxonomy, array('slug'=>$q[$t->query_var]));
+ if ( !is_wp_error($terms) )
+ break;
+ }
+ }
+ }
+ if ( is_wp_error($terms) || empty($terms) ) {
+ $whichcat = " AND 0 ";
+ } else {
+ foreach ( $terms as $term )
+ $term_ids[] = $term->term_id;
+ $post_ids = get_objects_in_term($term_ids, $taxonomy);
+ if ( !is_wp_error($post_ids) && count($post_ids) ) {
+ $whichcat .= " AND $wpdb->posts.ID IN (" . implode(', ', $post_ids) . ") ";
+ $post_type = 'any';
+ $q['post_status'] = 'publish';
+ $post_status_join = true;
+ } else {
+ $whichcat = " AND 0 ";
+ }
+ }
+ }
+
+ // Author/user stuff
+
+ if ( empty($q['author']) || ($q['author'] == '0') ) {
+ $whichauthor='';
+ } else {
+ $q['author'] = ''.urldecode($q['author']).'';
+ $q['author'] = addslashes_gpc($q['author']);
+ if (strpos($q['author'], '-') !== false) {
+ $eq = '!=';
+ $andor = 'AND';
+ $q['author'] = explode('-', $q['author']);
+ $q['author'] = '' . absint($q['author'][1]);
+ } else {
+ $eq = '=';
+ $andor = 'OR';
+ }
+ $author_array = preg_split('/[,\s]+/', $q['author']);
+ $whichauthor .= " AND ($wpdb->posts.post_author ".$eq.' '.absint($author_array[0]);
+ for ($i = 1; $i < (count($author_array)); $i = $i + 1) {
+ $whichauthor .= ' '.$andor." $wpdb->posts.post_author ".$eq.' '.absint($author_array[$i]);
+ }
+ $whichauthor .= ')';
+ }
+
+ // Author stuff for nice URLs
+
+ if ('' != $q['author_name']) {
+ if (strpos($q['author_name'], '/') !== false) {
+ $q['author_name'] = explode('/',$q['author_name']);
+ if ($q['author_name'][count($q['author_name'])-1]) {
+ $q['author_name'] = $q['author_name'][count($q['author_name'])-1];#no trailing slash
+ } else {
+ $q['author_name'] = $q['author_name'][count($q['author_name'])-2];#there was a trailling slash
+ }
+ }
+ $q['author_name'] = sanitize_title($q['author_name']);
+ $q['author'] = $wpdb->get_var("SELECT ID FROM $wpdb->users WHERE user_nicename='".$q['author_name']."'");
+ $whichauthor .= " AND ($wpdb->posts.post_author = ".absint($q['author']).')';
+ }
+
+ // MIME-Type stuff for attachment browsing
+
+ if ( isset($q['post_mime_type']) && '' != $q['post_mime_type'] )
+ $whichmimetype = wp_post_mime_type_where($q['post_mime_type']);
+
+ $where .= $search.$whichcat.$whichauthor.$whichmimetype;
+
+ if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) )
+ $q['order'] = 'DESC';
+
+ // Order by
+ if ( empty($q['orderby']) ) {
+ $q['orderby'] = "$wpdb->posts.post_date ".$q['order'];
+ } else {
+ // Used to filter values
+ $allowed_keys = array('author', 'date', 'category', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand');
+ if ( !empty($q['meta_key']) ) {
+ $allowed_keys[] = $q['meta_key'];
+ $allowed_keys[] = 'meta_value';
+ }
+ $q['orderby'] = urldecode($q['orderby']);
+ $q['orderby'] = addslashes_gpc($q['orderby']);
+ $orderby_array = explode(' ',$q['orderby']);
+ if ( empty($orderby_array) )
+ $orderby_array[] = $q['orderby'];
+ $q['orderby'] = '';
+ for ($i = 0; $i < count($orderby_array); $i++) {
+ // Only allow certain values for safety
+ $orderby = $orderby_array[$i];
+ switch ($orderby) {
+ case 'menu_order':
+ break;
+ case 'ID':
+ $orderby = "$wpdb->posts.ID";
+ break;
+ case 'rand':
+ $orderby = 'RAND()';
+ break;
+ case $q['meta_key']:
+ case 'meta_value':
+ $orderby = "$wpdb->postmeta.meta_value";
+ break;
+ default:
+ $orderby = "$wpdb->posts.post_" . $orderby;
+ }
+ if ( in_array($orderby_array[$i], $allowed_keys) )
+ $q['orderby'] .= (($i == 0) ? '' : ',') . $orderby;
+ }
+ // append ASC or DESC at the end
+ if ( !empty($q['orderby']))
+ $q['orderby'] .= " {$q['order']}";
+
+ if ( empty($q['orderby']) )
+ $q['orderby'] = "$wpdb->posts.post_date ".$q['order'];
+ }
+
+ if ( $this->is_attachment ) {
+ $where .= " AND $wpdb->posts.post_type = 'attachment'";
+ } elseif ($this->is_page) {
+ $where .= " AND $wpdb->posts.post_type = 'page'";
+ } elseif ($this->is_single) {
+ $where .= " AND $wpdb->posts.post_type = 'post'";
+ } elseif ( 'any' == $post_type ) {
+ $where .= '';
+ } else {
+ $where .= " AND $wpdb->posts.post_type = '$post_type'";
+ }
+
+ if ( isset($q['post_status']) && '' != $q['post_status'] ) {
+ $statuswheres = array();
+ $q_status = explode(',', $q['post_status']);
+ $r_status = array();
+ $p_status = array();
+ if ( in_array( 'draft' , $q_status ) )
+ $r_status[] = "$wpdb->posts.post_status = 'draft'";
+ if ( in_array( 'pending', $q_status ) )
+ $r_status[] = "$wpdb->posts.post_status = 'pending'";
+ if ( in_array( 'future' , $q_status ) )
+ $r_status[] = "$wpdb->posts.post_status = 'future'";
+ if ( in_array( 'inherit' , $q_status ) )
+ $r_status[] = "$wpdb->posts.post_status = 'inherit'";
+ if ( in_array( 'private', $q_status ) )
+ $p_status[] = "$wpdb->posts.post_status = 'private'";
+ if ( in_array( 'publish', $q_status ) )
+ $r_status[] = "$wpdb->posts.post_status = 'publish'";
+
+ if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
+ $r_status = array_merge($r_status, $p_status);
+ unset($p_status);
+ }
+
+ if ( !empty($r_status) ) {
+ if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can("edit_others_{$post_type}s") )
+ $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $r_status ) . "))";
+ else
+ $statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
+ }
+ if ( !empty($p_status) ) {
+ if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can("read_private_{$post_type}s") )
+ $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $p_status ) . "))";
+ else
+ $statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
+ }
+ if ( $post_status_join ) {
+ $join .= " LEFT JOIN $wpdb->posts AS p2 ON ($wpdb->posts.post_parent = p2.ID) ";
+ foreach ( $statuswheres as $index => $statuswhere )
+ $statuswheres[$index] = "($statuswhere OR ($wpdb->posts.post_status = 'inherit' AND " . str_replace($wpdb->posts, 'p2', $statuswhere) . "))";
+ }
+ foreach ( $statuswheres as $statuswhere )
+ $where .= " AND $statuswhere";
+ } elseif ( !$this->is_singular ) {
+ $where .= " AND ($wpdb->posts.post_status = 'publish'";
+
+ if ( is_admin() )
+ $where .= " OR $wpdb->posts.post_status = 'future' OR $wpdb->posts.post_status = 'draft' OR $wpdb->posts.post_status = 'pending'";
+
+ if ( is_user_logged_in() ) {
+ $where .= current_user_can( "read_private_{$post_type}s" ) ? " OR $wpdb->posts.post_status = 'private'" : " OR $wpdb->posts.post_author = $user_ID AND $wpdb->posts.post_status = 'private'";
+ }
+
+ $where .= ')';
+ }
+
+ // postmeta queries
+ if ( ! empty($q['meta_key']) || ! empty($q['meta_value']) )
+ $join .= " LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id) ";
+ if ( ! empty($q['meta_key']) )
+ $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s ", $q['meta_key']);
+ if ( ! empty($q['meta_value']) ) {
+ if ( ! isset($q['meta_compare']) || empty($q['meta_compare']) || ! in_array($q['meta_compare'], array('=', '!=', '>', '>=', '<', '<=')) )
+ $q['meta_compare'] = '=';
+
+ $where .= $wpdb->prepare("AND $wpdb->postmeta.meta_value {$q['meta_compare']} %s ", $q['meta_value']);
+ }
+
+ // Apply filters on where and join prior to paging so that any
+ // manipulations to them are reflected in the paging by day queries.
+ if ( !$q['suppress_filters'] ) {
+ $where = apply_filters('posts_where', $where);
+ $join = apply_filters('posts_join', $join);
+ }
+
+ // Paging
+ if ( empty($q['nopaging']) && !$this->is_singular ) {
+ $page = absint($q['paged']);
+ if (empty($page)) {
+ $page = 1;
+ }
+
+ if ( empty($q['offset']) ) {
+ $pgstrt = '';
+ $pgstrt = ($page - 1) * $q['posts_per_page'] . ', ';
+ $limits = 'LIMIT '.$pgstrt.$q['posts_per_page'];
+ } else { // we're ignoring $page and using 'offset'
+ $q['offset'] = absint($q['offset']);
+ $pgstrt = $q['offset'] . ', ';
+ $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
+ }
+ }
+
+ // Comments feeds
+ if ( $this->is_comment_feed && ( $this->is_archive || $this->is_search || !$this->is_singular ) ) {
+ if ( $this->is_archive || $this->is_search ) {
+ $cjoin = "LEFT JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID = $wpdb->posts.ID) $join ";
+ $cwhere = "WHERE comment_approved = '1' $where";
+ $cgroupby = "GROUP BY $wpdb->comments.comment_id";
+ } else { // Other non singular e.g. front
+ $cjoin = "LEFT JOIN $wpdb->posts ON ( $wpdb->comments.comment_post_ID = $wpdb->posts.ID )";
+ $cwhere = "WHERE post_status = 'publish' AND comment_approved = '1'";
+ $cgroupby = '';
+ }
+
+ if ( !$q['suppress_filters'] ) {
+ $cjoin = apply_filters('comment_feed_join', $cjoin);
+ $cwhere = apply_filters('comment_feed_where', $cwhere);
+ $cgroupby = apply_filters('comment_feed_groupby', $cgroupby);
+ }
+
+ $this->comments = (array) $wpdb->get_results("SELECT $distinct $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby ORDER BY comment_date_gmt DESC LIMIT " . get_option('posts_per_rss'));
+ $this->comment_count = count($this->comments);
+
+ $post_ids = array();
+
+ foreach ($this->comments as $comment)
+ $post_ids[] = (int) $comment->comment_post_ID;
+
+ $post_ids = join(',', $post_ids);
+ $join = '';
+ if ( $post_ids )
+ $where = "AND $wpdb->posts.ID IN ($post_ids) ";
+ else
+ $where = "AND 0";
+ }
+
+ $orderby = $q['orderby'];
+
+ // Apply post-paging filters on where and join. Only plugins that
+ // manipulate paging queries should use these hooks.
+ if ( !$q['suppress_filters'] ) {
+ $where = apply_filters('posts_where_paged', $where);
+ $groupby = apply_filters('posts_groupby', $groupby);
+ $join = apply_filters('posts_join_paged', $join);
+ $orderby = apply_filters('posts_orderby', $orderby);
+ $distinct = apply_filters('posts_distinct', $distinct);
+ $limits = apply_filters( 'post_limits', $limits );
+
+ if ( ! empty($q['meta_key']) )
+ $fields = "$fields, $wpdb->postmeta.meta_value";
+
+ $fields = apply_filters('posts_fields', $fields);
+ }
+
+ // Announce current selection parameters. For use by caching plugins.
+ do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
+
+ // Filter again for the benefit of caching plugins. Regular plugins should use the hooks above.
+ if ( !$q['suppress_filters'] ) {
+ $where = apply_filters('posts_where_request', $where);
+ $groupby = apply_filters('posts_groupby_request', $groupby);
+ $join = apply_filters('posts_join_request', $join);
+ $orderby = apply_filters('posts_orderby_request', $orderby);
+ $distinct = apply_filters('posts_distinct_request', $distinct);
+ $fields = apply_filters('posts_fields_request', $fields);
+ $limits = apply_filters( 'post_limits_request', $limits );
+ }
+
+ if ( ! empty($groupby) )
+ $groupby = 'GROUP BY ' . $groupby;
+ if ( !empty( $orderby ) )
+ $orderby = 'ORDER BY ' . $orderby;
+ $found_rows = '';
+ if ( !empty($limits) )
+ $found_rows = 'SQL_CALC_FOUND_ROWS';
+
+ $this->request = " SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
+ if ( !$q['suppress_filters'] )
+ $this->request = apply_filters('posts_request', $this->request);
+
+ $this->posts = $wpdb->get_results($this->request);
+ // Raw results filter. Prior to status checks.
+ if ( !$q['suppress_filters'] )
+ $this->posts = apply_filters('posts_results', $this->posts);
+
+ if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
+ $cjoin = apply_filters('comment_feed_join', '');
+ $cwhere = apply_filters('comment_feed_where', "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'");
+ $comments_request = "SELECT $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere ORDER BY comment_date_gmt DESC LIMIT " . get_option('posts_per_rss');
+ $this->comments = $wpdb->get_results($comments_request);
+ $this->comment_count = count($this->comments);
+ }
+
+ if ( !empty($limits) ) {
+ $found_posts_query = apply_filters( 'found_posts_query', 'SELECT FOUND_ROWS()' );
+ $this->found_posts = $wpdb->get_var( $found_posts_query );
+ $this->found_posts = apply_filters( 'found_posts', $this->found_posts );
+ $this->max_num_pages = ceil($this->found_posts / $q['posts_per_page']);
+ }
+
+ // Check post status to determine if post should be displayed.
+ if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
+ $status = get_post_status($this->posts[0]);
+ //$type = get_post_type($this->posts[0]);
+ if ( ('publish' != $status) ) {
+ if ( ! is_user_logged_in() ) {
+ // User must be logged in to view unpublished posts.
+ $this->posts = array();
+ } else {
+ if (in_array($status, array('draft', 'pending')) ) {
+ // User must have edit permissions on the draft to preview.
+ if (! current_user_can('edit_post', $this->posts[0]->ID)) {
+ $this->posts = array();
+ } else {
+ $this->is_preview = true;
+ $this->posts[0]->post_date = current_time('mysql');
+ }
+ } else if ('future' == $status) {
+ $this->is_preview = true;
+ if (!current_user_can('edit_post', $this->posts[0]->ID)) {
+ $this->posts = array ( );
+ }
+ } else {
+ if (! current_user_can('read_post', $this->posts[0]->ID))
+ $this->posts = array();
+ }
+ }
+ }
+
+ if ( $this->is_preview && current_user_can( "edit_{$post_type}", $this->posts[0]->ID ) )
+ $this->posts[0] = apply_filters('the_preview', $this->posts[0]);
+ }
+
+ // Put sticky posts at the top of the posts array
+ $sticky_posts = get_option('sticky_posts');
+ if ( $this->is_home && $page <= 1 && !empty($sticky_posts) && !$q['caller_get_posts'] ) {
+ $num_posts = count($this->posts);
+ $sticky_offset = 0;
+ // Loop over posts and relocate stickies to the front.
+ for ( $i = 0; $i < $num_posts; $i++ ) {
+ if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
+ $sticky_post = $this->posts[$i];
+ // Remove sticky from current position
+ array_splice($this->posts, $i, 1);
+ // Move to front, after other stickies
+ array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
+ // Increment the sticky offset. The next sticky will be placed at this offset.
+ $sticky_offset++;
+ // Remove post from sticky posts array
+ $offset = array_search($sticky_post->ID, $sticky_posts);
+ array_splice($sticky_posts, $offset, 1);
+ }
+ }
+
+ // Fetch sticky posts that weren't in the query results
+ if ( !empty($sticky_posts) ) {
+ $stickies__in = implode(',', array_map( 'absint', $sticky_posts ));
+ $stickies = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE $wpdb->posts.ID IN ($stickies__in)" );
+ /** @todo Make sure post is published or viewable by the current user */
+ foreach ( $stickies as $sticky_post ) {
+ if ( 'publish' != $sticky_post->post_status )
+ continue;
+ array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
+ $sticky_offset++;
+ }
+ }
+ }
+
+ if ( !$q['suppress_filters'] )
+ $this->posts = apply_filters('the_posts', $this->posts);
+
+ update_post_caches($this->posts);
+
+ $this->post_count = count($this->posts);
+ if ($this->post_count > 0) {
+ $this->post = $this->posts[0];
+ }
+
+ return $this->posts;
+ }
+
+ /**
+ * Setup the next post and iterate current post index.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return object Next post.
+ */
+ function next_post() {
+
+ $this->current_post++;
+
+ $this->post = $this->posts[$this->current_post];
+ return $this->post;
+ }
+
+ /**
+ * Sets up the current post.
+ *
+ * Retrieves the next post, sets up the post, sets the 'in the loop'
+ * property to true.
+ *
+ * @since 1.5.0
+ * @access public
+ * @uses $post
+ * @uses do_action() Calls 'loop_start' if loop has just started
+ */
+ function the_post() {
+ global $post;
+ $this->in_the_loop = true;
+ $post = $this->next_post();
+ setup_postdata($post);
+
+ if ( $this->current_post == 0 ) // loop has just started
+ do_action('loop_start');
+ }
+
+ /**
+ * Whether there are more posts available in the loop.
+ *
+ * Calls action 'loop_end', when the loop is complete.
+ *
+ * @since 1.5.0
+ * @access public
+ * @uses do_action() Calls 'loop_start' if loop has just started
+ *
+ * @return bool True if posts are available, false if end of loop.
+ */
+ function have_posts() {
+ if ($this->current_post + 1 < $this->post_count) {
+ return true;
+ } elseif ($this->current_post + 1 == $this->post_count && $this->post_count > 0) {
+ do_action('loop_end');
+ // Do some cleaning up after the loop
+ $this->rewind_posts();
+ }
+
+ $this->in_the_loop = false;
+ return false;
+ }
+
+ /**
+ * Rewind the posts and reset post index.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function rewind_posts() {
+ $this->current_post = -1;
+ if ($this->post_count > 0) {
+ $this->post = $this->posts[0];
+ }
+ }
+
+ /**
+ * Iterate current comment index and return comment object.
+ *
+ * @since 2.2.0
+ * @access public
+ *
+ * @return object Comment object.
+ */
+ function next_comment() {
+ $this->current_comment++;
+
+ $this->comment = $this->comments[$this->current_comment];
+ return $this->comment;
+ }
+
+ /**
+ * Sets up the current comment.
+ *
+ * @since 2.2.0
+ * @access public
+ * @global object $comment Current comment.
+ * @uses do_action() Calls 'comment_loop_start' hook when first comment is processed.
+ */
+ function the_comment() {
+ global $comment;
+
+ $comment = $this->next_comment();
+
+ if ($this->current_comment == 0) {
+ do_action('comment_loop_start');
+ }
+ }
+
+ /**
+ * Whether there are more comments available.
+ *
+ * Automatically rewinds comments when finished.
+ *
+ * @since 2.2.0
+ * @access public
+ *
+ * @return bool True, if more comments. False, if no more posts.
+ */
+ function have_comments() {
+ if ($this->current_comment + 1 < $this->comment_count) {
+ return true;
+ } elseif ($this->current_comment + 1 == $this->comment_count) {
+ $this->rewind_comments();
+ }
+
+ return false;
+ }
+
+ /**
+ * Rewind the comments, resets the comment index and comment to first.
+ *
+ * @since 2.2.0
+ * @access public
+ */
+ function rewind_comments() {
+ $this->current_comment = -1;
+ if ($this->comment_count > 0) {
+ $this->comment = $this->comments[0];
+ }
+ }
+
+ /**
+ * Sets up the WordPress query by parsing query string.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query URL query string.
+ * @return array List of posts.
+ */
+ function &query($query) {
+ $this->parse_query($query);
+ return $this->get_posts();
+ }
+
+ /**
+ * Retrieve queried object.
+ *
+ * If queried object is not set, then the queried object will be set from
+ * the category, tag, taxonomy, posts page, single post, page, or author
+ * query variable. After it is set up, it will be returned.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return object
+ */
+ function get_queried_object() {
+ if (isset($this->queried_object)) {
+ return $this->queried_object;
+ }
+
+ $this->queried_object = NULL;
+ $this->queried_object_id = 0;
+
+ if ($this->is_category) {
+ $cat = $this->get('cat');
+ $category = &get_category($cat);
+ if ( is_wp_error( $category ) )
+ return NULL;
+ $this->queried_object = &$category;
+ $this->queried_object_id = (int) $cat;
+ } else if ($this->is_tag) {
+ $tag_id = $this->get('tag_id');
+ $tag = &get_term($tag_id, 'post_tag');
+ if ( is_wp_error( $tag ) )
+ return NULL;
+ $this->queried_object = &$tag;
+ $this->queried_object_id = (int) $tag_id;
+ } else if ($this->is_tax) {
+ $tax = $this->get('taxonomy');
+ $slug = $this->get('term');
+ $term = &get_terms($tax, array('slug'=>$slug));
+ if ( is_wp_error($term) || empty($term) )
+ return NULL;
+ $term = $term[0];
+ $this->queried_object = $term;
+ $this->queried_object_id = $term->term_id;
+ } else if ($this->is_posts_page) {
+ $this->queried_object = & get_page(get_option('page_for_posts'));
+ $this->queried_object_id = (int) $this->queried_object->ID;
+ } else if ($this->is_single) {
+ $this->queried_object = $this->post;
+ $this->queried_object_id = (int) $this->post->ID;
+ } else if ($this->is_page) {
+ $this->queried_object = $this->post;
+ $this->queried_object_id = (int) $this->post->ID;
+ } else if ($this->is_author) {
+ $author_id = (int) $this->get('author');
+ $author = get_userdata($author_id);
+ $this->queried_object = $author;
+ $this->queried_object_id = $author_id;
+ }
+
+ return $this->queried_object;
+ }
+
+ /**
+ * Retrieve ID of the current queried object.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return int
+ */
+ function get_queried_object_id() {
+ $this->get_queried_object();
+
+ if (isset($this->queried_object_id)) {
+ return $this->queried_object_id;
+ }
+
+ return 0;
+ }
+
+ /**
+ * PHP4 type constructor.
+ *
+ * Sets up the WordPress query, if parameter is not empty.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query URL query string.
+ * @return WP_Query
+ */
+ function WP_Query ($query = '') {
+ if (! empty($query)) {
+ $this->query($query);
+ }
+ }
+}
+
+/**
+ * Redirect old slugs to the correct permalink.
+ *
+ * Attempts to find the current slug from the past slugs.
+ *
+ * @since 2.1.0
+ * @uses $wp_query
+ * @uses $wpdb
+ *
+ * @return null If no link is found, null is returned.
+ */
+function wp_old_slug_redirect () {
+ global $wp_query;
+ if ( is_404() && '' != $wp_query->query_vars['name'] ) :
+ global $wpdb;
+
+ $query = "SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND meta_key = '_wp_old_slug' AND meta_value='" . $wp_query->query_vars['name'] . "'";
+
+ // if year, monthnum, or day have been specified, make our query more precise
+ // just in case there are multiple identical _wp_old_slug values
+ if ( '' != $wp_query->query_vars['year'] )
+ $query .= " AND YEAR(post_date) = '{$wp_query->query_vars['year']}'";
+ if ( '' != $wp_query->query_vars['monthnum'] )
+ $query .= " AND MONTH(post_date) = '{$wp_query->query_vars['monthnum']}'";
+ if ( '' != $wp_query->query_vars['day'] )
+ $query .= " AND DAYOFMONTH(post_date) = '{$wp_query->query_vars['day']}'";
+
+ $id = (int) $wpdb->get_var($query);
+
+ if ( !$id )
+ return;
+
+ $link = get_permalink($id);
+
+ if ( !$link )
+ return;
+
+ wp_redirect($link, '301'); // Permanent redirect
+ exit;
+ endif;
+}
+
+/**
+ * Setup global post data.
+ *
+ * @since 1.5.0
+ *
+ * @param object $post Post data.
+ * @return bool True when finished.
+ */
+function setup_postdata($post) {
+ global $id, $authordata, $day, $currentmonth, $page, $pages, $multipage, $more, $numpages;
+
+ $id = (int) $post->ID;
+
+ $authordata = get_userdata($post->post_author);
+
+ $day = mysql2date('d.m.y', $post->post_date);
+ $currentmonth = mysql2date('m', $post->post_date);
+ $numpages = 1;
+ $page = get_query_var('page');
+ if ( !$page )
+ $page = 1;
+ if ( is_single() || is_page() || is_feed() )
+ $more = 1;
+ $content = $post->post_content;
+ if ( strpos( $content, '' ) ) {
+ if ( $page > 1 )
+ $more = 1;
+ $multipage = 1;
+ $content = str_replace("\n\n", '', $content);
+ $content = str_replace("\n", '', $content);
+ $content = str_replace("\n", '', $content);
+ $pages = explode('', $content);
+ $numpages = count($pages);
+ } else {
+ $pages[0] = $post->post_content;
+ $multipage = 0;
+ }
+ return true;
+}
+
+?>
diff -uNr a/blog/wp-includes/registration-functions.php b/blog/wp-includes/registration-functions.php
--- a/blog/wp-includes/registration-functions.php false
+++ b/blog/wp-includes/registration-functions.php 001ddebf09561632416fccd5a260d740709062b089efd6f3c246162b244d471281ebbff0e55dd8a3e69a3a60e71e9f19c738bcfd29bd4b9603084d812050c04a
@@ -0,0 +1,9 @@
+
diff -uNr a/blog/wp-includes/registration.php b/blog/wp-includes/registration.php
--- a/blog/wp-includes/registration.php false
+++ b/blog/wp-includes/registration.php 3e1aec2c6c9c8223d6d8333e99d23b8765b1505dac86bce9dae18298a699a6fe5cc499037de49755387456d87d60936d1bc0b43140f82c22d6c05825f4f23c8f
@@ -0,0 +1,299 @@
+ID;
+ } else {
+ return null;
+ }
+}
+
+/**
+ * Checks whether the given email exists.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $email Email.
+ * @return bool|int The user's ID on success, and false on failure.
+ */
+function email_exists( $email ) {
+ if ( $user = get_user_by_email($email) )
+ return $user->ID;
+
+ return false;
+}
+
+/**
+ * Checks whether an username is valid.
+ *
+ * @since 2.0.1
+ * @uses apply_filters() Calls 'validate_username' hook on $valid check and $username as parameters
+ *
+ * @param string $username Username.
+ * @return bool Whether username given is valid
+ */
+function validate_username( $username ) {
+ $sanitized = sanitize_user( $username, true );
+ $valid = ( $sanitized == $username );
+ return apply_filters( 'validate_username', $valid, $username );
+}
+
+/**
+ * Insert an user into the database.
+ *
+ * Can update a current user or insert a new user based on whether the user's ID
+ * is present.
+ *
+ * Can be used to update the user's info (see below), set the user's role, and
+ * set the user's preference on whether they want the rich editor on.
+ *
+ * Most of the $userdata array fields have filters associated with the values.
+ * The exceptions are 'rich_editing', 'role', 'jabber', 'aim', 'yim',
+ * 'user_registered', and 'ID'. The filters have the prefix 'pre_user_' followed
+ * by the field name. An example using 'description' would have the filter
+ * called, 'pre_user_description' that can be hooked into.
+ *
+ * The $userdata array can contain the following fields:
+ * 'ID' - An integer that will be used for updating an existing user.
+ * 'user_pass' - A string that contains the plain text password for the user.
+ * 'user_login' - A string that contains the user's username for logging in.
+ * 'user_nicename' - A string that contains a nicer looking name for the user.
+ * The default is the user's username.
+ * 'user_url' - A string containing the user's URL for the user's web site.
+ * 'user_email' - A string containing the user's email address.
+ * 'display_name' - A string that will be shown on the site. Defaults to user's
+ * username. It is likely that you will want to change this, for both
+ * appearance and security through obscurity (that is if you don't use and
+ * delete the default 'admin' user).
+ * 'nickname' - The user's nickname, defaults to the user's username.
+ * 'first_name' - The user's first name.
+ * 'last_name' - The user's last name.
+ * 'description' - A string containing content about the user.
+ * 'rich_editing' - A string for whether to enable the rich editor or not. False
+ * if not empty.
+ * 'user_registered' - The date the user registered. Format is 'Y-m-d H:i:s'.
+ * 'role' - A string used to set the user's role.
+ * 'jabber' - User's Jabber account.
+ * 'aim' - User's AOL IM account.
+ * 'yim' - User's Yahoo IM account.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database layer.
+ * @uses apply_filters() Calls filters for most of the $userdata fields with the prefix 'pre_user'. See note above.
+ * @uses do_action() Calls 'profile_update' hook when updating giving the user's ID
+ * @uses do_action() Calls 'user_register' hook when creating a new user giving the user's ID
+ *
+ * @param array $userdata An array of user data.
+ * @return int The newly created user's ID.
+ */
+function wp_insert_user($userdata) {
+ global $wpdb;
+
+ extract($userdata, EXTR_SKIP);
+
+ // Are we updating or creating?
+ if ( !empty($ID) ) {
+ $ID = (int) $ID;
+ $update = true;
+ $old_user_data = get_userdata($ID);
+ } else {
+ $update = false;
+ // Hash the password
+ $user_pass = wp_hash_password($user_pass);
+ }
+
+ $user_login = sanitize_user($user_login, true);
+ $user_login = apply_filters('pre_user_login', $user_login);
+
+ if ( empty($user_nicename) )
+ $user_nicename = sanitize_title( $user_login );
+ $user_nicename = apply_filters('pre_user_nicename', $user_nicename);
+
+ if ( empty($user_url) )
+ $user_url = '';
+ $user_url = apply_filters('pre_user_url', $user_url);
+
+ if ( empty($user_email) )
+ $user_email = '';
+ $user_email = apply_filters('pre_user_email', $user_email);
+
+ if ( empty($display_name) )
+ $display_name = $user_login;
+ $display_name = apply_filters('pre_user_display_name', $display_name);
+
+ if ( empty($nickname) )
+ $nickname = $user_login;
+ $nickname = apply_filters('pre_user_nickname', $nickname);
+
+ if ( empty($first_name) )
+ $first_name = '';
+ $first_name = apply_filters('pre_user_first_name', $first_name);
+
+ if ( empty($last_name) )
+ $last_name = '';
+ $last_name = apply_filters('pre_user_last_name', $last_name);
+
+ if ( empty($description) )
+ $description = '';
+ $description = apply_filters('pre_user_description', $description);
+
+ if ( empty($rich_editing) )
+ $rich_editing = 'true';
+
+ if ( empty($comment_shortcuts) )
+ $comment_shortcuts = 'false';
+
+ if ( empty($admin_color) )
+ $admin_color = 'fresh';
+ $admin_color = preg_replace('|[^a-z0-9 _.\-@]|i', '', $admin_color);
+
+ if ( empty($use_ssl) )
+ $use_ssl = 0;
+
+ if ( empty($jabber) )
+ $jabber = '';
+
+ if ( empty($aim) )
+ $aim = '';
+
+ if ( empty($yim) )
+ $yim = '';
+
+ if ( empty($user_registered) )
+ $user_registered = gmdate('Y-m-d H:i:s');
+
+ $data = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
+ $data = stripslashes_deep( $data );
+
+ if ( $update ) {
+ $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
+ $user_id = (int) $ID;
+ } else {
+ $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
+ $user_id = (int) $wpdb->insert_id;
+ }
+
+ update_usermeta( $user_id, 'first_name', $first_name);
+ update_usermeta( $user_id, 'last_name', $last_name);
+ update_usermeta( $user_id, 'nickname', $nickname );
+ update_usermeta( $user_id, 'description', $description );
+ update_usermeta( $user_id, 'jabber', $jabber );
+ update_usermeta( $user_id, 'aim', $aim );
+ update_usermeta( $user_id, 'yim', $yim );
+ update_usermeta( $user_id, 'rich_editing', $rich_editing);
+ update_usermeta( $user_id, 'comment_shortcuts', $comment_shortcuts);
+ update_usermeta( $user_id, 'admin_color', $admin_color);
+ update_usermeta( $user_id, 'use_ssl', $use_ssl);
+
+ if ( $update && isset($role) ) {
+ $user = new WP_User($user_id);
+ $user->set_role($role);
+ }
+
+ if ( !$update ) {
+ $user = new WP_User($user_id);
+ $user->set_role(get_option('default_role'));
+ }
+
+ wp_cache_delete($user_id, 'users');
+ wp_cache_delete($user_login, 'userlogins');
+
+ if ( $update )
+ do_action('profile_update', $user_id, $old_user_data);
+ else
+ do_action('user_register', $user_id);
+
+ return $user_id;
+}
+
+/**
+ * Update an user in the database.
+ *
+ * It is possible to update a user's password by specifying the 'user_pass'
+ * value in the $userdata parameter array.
+ *
+ * If $userdata does not contain an 'ID' key, then a new user will be created
+ * and the new user's ID will be returned.
+ *
+ * If current user's password is being updated, then the cookies will be
+ * cleared.
+ *
+ * @since 2.0.0
+ * @see wp_insert_user() For what fields can be set in $userdata
+ * @uses wp_insert_user() Used to update existing user or add new one if user doesn't exist already
+ *
+ * @param array $userdata An array of user data.
+ * @return int The updated user's ID.
+ */
+function wp_update_user($userdata) {
+ $ID = (int) $userdata['ID'];
+
+ // First, get all of the original fields
+ $user = get_userdata($ID);
+
+ // Escape data pulled from DB.
+ $user = add_magic_quotes(get_object_vars($user));
+
+ // If password is changing, hash it now.
+ if ( ! empty($userdata['user_pass']) ) {
+ $plaintext_pass = $userdata['user_pass'];
+ $userdata['user_pass'] = wp_hash_password($userdata['user_pass']);
+ }
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $userdata = array_merge($user, $userdata);
+ $user_id = wp_insert_user($userdata);
+
+ // Update the cookies if the password changed.
+ $current_user = wp_get_current_user();
+ if ( $current_user->id == $ID ) {
+ if ( isset($plaintext_pass) ) {
+ wp_clear_auth_cookie();
+ wp_set_auth_cookie($ID);
+ }
+ }
+
+ return $user_id;
+}
+
+/**
+ * A simpler way of inserting an user into the database.
+ *
+ * Creates a new user with just the username, password, and email. For a more
+ * detail creation of a user, use wp_insert_user() to specify more infomation.
+ *
+ * @since 2.0.0
+ * @see wp_insert_user() More complete way to create a new user
+ * @uses $wpdb Escapes $username and $email parameters
+ *
+ * @param string $username The user's username.
+ * @param string $password The user's password.
+ * @param string $email The user's email (optional).
+ * @return int The new user's ID.
+ */
+function wp_create_user($username, $password, $email = '') {
+ global $wpdb;
+
+ $user_login = $wpdb->escape($username);
+ $user_email = $wpdb->escape($email);
+ $user_pass = $password;
+
+ $userdata = compact('user_login', 'user_email', 'user_pass');
+ return wp_insert_user($userdata);
+}
+
+?>
diff -uNr a/blog/wp-includes/rewrite.php b/blog/wp-includes/rewrite.php
--- a/blog/wp-includes/rewrite.php false
+++ b/blog/wp-includes/rewrite.php de31e12509d6d0c02ee8f367a30cd133fef733fc80f40fb345915c5206fad6e986568be92915381ff9c40b9a4a364075b339ad184e15f05322fac45b4373a89a
@@ -0,0 +1,1904 @@
+add_rule($regex, $redirect, $after);
+}
+
+/**
+ * Add a new tag (like %postname%).
+ *
+ * Warning: you must call this on init or earlier, otherwise the query var
+ * addition stuff won't work.
+ *
+ * @since 2.1.0
+ *
+ * @param string $tagname
+ * @param string $regex
+ */
+function add_rewrite_tag($tagname, $regex) {
+ //validation
+ if (strlen($tagname) < 3 || $tagname{0} != '%' || $tagname{strlen($tagname)-1} != '%') {
+ return;
+ }
+
+ $qv = trim($tagname, '%');
+
+ global $wp_rewrite, $wp;
+ $wp->add_query_var($qv);
+ $wp_rewrite->add_rewrite_tag($tagname, $regex, $qv . '=');
+}
+
+/**
+ * Add a new feed type like /atom1/.
+ *
+ * @since 2.1.0
+ *
+ * @param string $feedname
+ * @param callback $function Callback to run on feed display.
+ * @return string Feed action name.
+ */
+function add_feed($feedname, $function) {
+ global $wp_rewrite;
+ if (!in_array($feedname, $wp_rewrite->feeds)) { //override the file if it is
+ $wp_rewrite->feeds[] = $feedname;
+ }
+ $hook = 'do_feed_' . $feedname;
+ // Remove default function hook
+ remove_action($hook, $hook, 10, 1);
+ add_action($hook, $function, 10, 1);
+ return $hook;
+}
+
+/**
+ * Endpoint Mask for Permalink.
+ *
+ * @since 2.1.0
+ */
+define('EP_PERMALINK', 1);
+
+/**
+ * Endpoint Mask for Attachment.
+ *
+ * @since 2.1.0
+ */
+define('EP_ATTACHMENT', 2);
+
+/**
+ * Endpoint Mask for date.
+ *
+ * @since 2.1.0
+ */
+define('EP_DATE', 4);
+
+/**
+ * Endpoint Mask for year
+ *
+ * @since 2.1.0
+ */
+define('EP_YEAR', 8);
+
+/**
+ * Endpoint Mask for month.
+ *
+ * @since 2.1.0
+ */
+define('EP_MONTH', 16);
+
+/**
+ * Endpoint Mask for day.
+ *
+ * @since 2.1.0
+ */
+define('EP_DAY', 32);
+
+/**
+ * Endpoint Mask for root.
+ *
+ * @since 2.1.0
+ */
+define('EP_ROOT', 64);
+
+/**
+ * Endpoint Mask for comments.
+ *
+ * @since 2.1.0
+ */
+define('EP_COMMENTS', 128);
+
+/**
+ * Endpoint Mask for searches.
+ *
+ * @since 2.1.0
+ */
+define('EP_SEARCH', 256);
+
+/**
+ * Endpoint Mask for categories.
+ *
+ * @since 2.1.0
+ */
+define('EP_CATEGORIES', 512);
+
+/**
+ * Endpoint Mask for tags.
+ *
+ * @since 2.3.0
+ */
+define('EP_TAGS', 1024);
+
+/**
+ * Endpoint Mask for authors.
+ *
+ * @since 2.1.0
+ */
+define('EP_AUTHORS', 2048);
+
+/**
+ * Endpoint Mask for pages.
+ *
+ * @since 2.1.0
+ */
+define('EP_PAGES', 4096);
+
+//pseudo-places
+/**
+ * Endpoint Mask for default, which is nothing.
+ *
+ * @since 2.1.0
+ */
+define('EP_NONE', 0);
+
+/**
+ * Endpoint Mask for everything.
+ *
+ * @since 2.1.0
+ */
+define('EP_ALL', 8191);
+
+/**
+ * Add an endpoint, like /trackback/.
+ *
+ * The endpoints are added to the end of the request. So a request matching
+ * "/2008/10/14/my_post/myep/", the endpoint will be "/myep/".
+ *
+ * @since 2.1.0
+ * @see WP_Rewrite::add_endpoint() Parameters and more description.
+ * @uses $wp_rewrite
+ *
+ * @param unknown_type $name
+ * @param unknown_type $places
+ */
+function add_rewrite_endpoint($name, $places) {
+ global $wp_rewrite;
+ $wp_rewrite->add_endpoint($name, $places);
+}
+
+/**
+ * Filter the URL base for taxonomies.
+ *
+ * To remove any manually prepended /index.php/.
+ *
+ * @access private
+ * @since 2.6.0
+ * @author Mark Jaquith
+ *
+ * @param string $base The taxonomy base that we're going to filter
+ * @return string
+ */
+function _wp_filter_taxonomy_base( $base ) {
+ if ( !empty( $base ) ) {
+ $base = preg_replace( '|^/index\.php/|', '', $base );
+ $base = trim( $base, '/' );
+ }
+ return $base;
+}
+
+/**
+ * Examine a url and try to determine the post ID it represents.
+ *
+ * Checks are supposedly from the hosted site blog.
+ *
+ * @since 1.0.0
+ *
+ * @param string $url Permalink to check.
+ * @return int Post ID, or 0 on failure.
+ */
+function url_to_postid($url) {
+ global $wp_rewrite;
+
+ $url = apply_filters('url_to_postid', $url);
+
+ // First, check to see if there is a 'p=N' or 'page_id=N' to match against
+ if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) ) {
+ $id = absint($values[2]);
+ if ($id)
+ return $id;
+ }
+
+ // Check to see if we are using rewrite rules
+ $rewrite = $wp_rewrite->wp_rewrite_rules();
+
+ // Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
+ if ( empty($rewrite) )
+ return 0;
+
+ // $url cleanup by Mark Jaquith
+ // This fixes things like #anchors, ?query=strings, missing 'www.',
+ // added 'www.', or added 'index.php/' that will mess up our WP_Query
+ // and return a false negative
+
+ // Get rid of the #anchor
+ $url_split = explode('#', $url);
+ $url = $url_split[0];
+
+ // Get rid of URL ?query=string
+ $url_split = explode('?', $url);
+ $url = $url_split[0];
+
+ // Add 'www.' if it is absent and should be there
+ if ( false !== strpos(get_option('home'), '://www.') && false === strpos($url, '://www.') )
+ $url = str_replace('://', '://www.', $url);
+
+ // Strip 'www.' if it is present and shouldn't be
+ if ( false === strpos(get_option('home'), '://www.') )
+ $url = str_replace('://www.', '://', $url);
+
+ // Strip 'index.php/' if we're not using path info permalinks
+ if ( !$wp_rewrite->using_index_permalinks() )
+ $url = str_replace('index.php/', '', $url);
+
+ if ( false !== strpos($url, get_option('home')) ) {
+ // Chop off http://domain.com
+ $url = str_replace(get_option('home'), '', $url);
+ } else {
+ // Chop off /path/to/blog
+ $home_path = parse_url(get_option('home'));
+ $home_path = $home_path['path'];
+ $url = str_replace($home_path, '', $url);
+ }
+
+ // Trim leading and lagging slashes
+ $url = trim($url, '/');
+
+ $request = $url;
+
+ // Done with cleanup
+
+ // Look for matches.
+ $request_match = $request;
+ foreach ($rewrite as $match => $query) {
+ // If the requesting file is the anchor of the match, prepend it
+ // to the path info.
+ if ( (! empty($url)) && (strpos($match, $url) === 0) && ($url != $request)) {
+ $request_match = $url . '/' . $request;
+ }
+
+ if ( preg_match("!^$match!", $request_match, $matches) ) {
+ // Got a match.
+ // Trim the query of everything up to the '?'.
+ $query = preg_replace("!^.+\?!", '', $query);
+
+ // Substitute the substring matches into the query.
+ eval("\$query = \"" . addslashes($query) . "\";");
+ // Filter out non-public query vars
+ global $wp;
+ parse_str($query, $query_vars);
+ $query = array();
+ foreach ( (array) $query_vars as $key => $value ) {
+ if ( in_array($key, $wp->public_query_vars) )
+ $query[$key] = $value;
+ }
+ // Do the query
+ $query = new WP_Query($query);
+ if ( $query->is_single || $query->is_page )
+ return $query->post->ID;
+ else
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * WordPress Rewrite Component.
+ *
+ * The WordPress Rewrite class writes the rewrite module rules to the .htaccess
+ * file. It also handles parsing the request to get the correct setup for the
+ * WordPress Query class.
+ *
+ * The Rewrite along with WP class function as a front controller for WordPress.
+ * You can add rules to trigger your page view and processing using this
+ * component. The full functionality of a front controller does not exist,
+ * meaning you can't define how the template files load based on the rewrite
+ * rules.
+ *
+ * @since 1.5.0
+ */
+class WP_Rewrite {
+ /**
+ * Default permalink structure for WordPress.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $permalink_structure;
+
+ /**
+ * Whether to add trailing slashes.
+ *
+ * @since 2.2.0
+ * @access private
+ * @var bool
+ */
+ var $use_trailing_slashes;
+
+ /**
+ * Customized or default category permalink base ( example.com/xx/tagname ).
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $category_base;
+
+ /**
+ * Customized or default tag permalink base ( example.com/xx/tagname ).
+ *
+ * @since 2.3.0
+ * @access private
+ * @var string
+ */
+ var $tag_base;
+
+ /**
+ * Permalink request structure for categories.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $category_structure;
+
+ /**
+ * Permalink request structure for tags.
+ *
+ * @since 2.3.0
+ * @access private
+ * @var string
+ */
+ var $tag_structure;
+
+ /**
+ * Permalink author request base ( example.com/author/authorname ).
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $author_base = 'author';
+
+ /**
+ * Permalink request structure for author pages.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $author_structure;
+
+ /**
+ * Permalink request structure for dates.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $date_structure;
+
+ /**
+ * Permalink request structure for pages.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $page_structure;
+
+ /**
+ * Search permalink base ( example.com/search/query ).
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $search_base = 'search';
+
+ /**
+ * Permalink request structure for searches.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $search_structure;
+
+ /**
+ * Comments permalink base.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $comments_base = 'comments';
+
+ /**
+ * Feed permalink base.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $feed_base = 'feed';
+
+ /**
+ * Comments feed request structure permalink.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $comments_feed_structure;
+
+ /**
+ * Feed request structure permalink.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $feed_structure;
+
+ /**
+ * Front URL path.
+ *
+ * The difference between the root property is that WordPress might be
+ * located at example/WordPress/index.php, if permalinks are turned off. The
+ * WordPress/index.php will be the front portion. If permalinks are turned
+ * on, this will most likely be empty or not set.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $front;
+
+ /**
+ * Root URL path to WordPress (without domain).
+ *
+ * The difference between front property is that WordPress might be located
+ * at example.com/WordPress/. The root is the 'WordPress/' portion.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $root = '';
+
+ /**
+ * Permalink to the home page.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $index = 'index.php';
+
+ /**
+ * Request match string.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $matches = '';
+
+ /**
+ * Rewrite rules to match against the request to find the redirect or query.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $rules;
+
+ /**
+ * Additional rules added external to the rewrite class.
+ *
+ * Those not generated by the class, see add_rewrite_rule().
+ *
+ * @since 2.1.0
+ * @access private
+ * @var array
+ */
+ var $extra_rules = array(); //
+
+ /**
+ * Additional rules that belong at the beginning to match first.
+ *
+ * Those not generated by the class, see add_rewrite_rule().
+ *
+ * @since 2.3.0
+ * @access private
+ * @var array
+ */
+ var $extra_rules_top = array(); //
+
+ /**
+ * Rules that don't redirect to WP's index.php.
+ *
+ * These rules are written to the mod_rewrite portion of the .htaccess.
+ *
+ * @since 2.1.0
+ * @access private
+ * @var array
+ */
+ var $non_wp_rules = array(); //
+
+ /**
+ * Extra permalink structures.
+ *
+ * @since 2.1.0
+ * @access private
+ * @var array
+ */
+ var $extra_permastructs = array();
+
+ /**
+ * Endpoints permalinks
+ *
+ * @since unknown
+ * @access private
+ * @var array
+ */
+ var $endpoints;
+
+ /**
+ * Whether to write every mod_rewrite rule for WordPress.
+ *
+ * This is off by default, turning it on might print a lot of rewrite rules
+ * to the .htaccess file.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $use_verbose_rules = false;
+
+ /**
+ * Whether to write every mod_rewrite rule for WordPress pages.
+ *
+ * @since 2.5.0
+ * @access public
+ * @var bool
+ */
+ var $use_verbose_page_rules = true;
+
+ /**
+ * Permalink structure search for preg_replace.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $rewritecode =
+ array(
+ '%year%',
+ '%monthnum%',
+ '%day%',
+ '%hour%',
+ '%minute%',
+ '%second%',
+ '%postname%',
+ '%post_id%',
+ '%category%',
+ '%tag%',
+ '%author%',
+ '%pagename%',
+ '%search%'
+ );
+
+ /**
+ * Preg_replace values for the search, see {@link WP_Rewrite::$rewritecode}.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $rewritereplace =
+ array(
+ '([0-9]{4})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([^/]+)',
+ '([0-9]+)',
+ '(.+?)',
+ '(.+?)',
+ '([^/]+)',
+ '([^/]+?)',
+ '(.+)'
+ );
+
+ /**
+ * Search for the query to look for replacing.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $queryreplace =
+ array (
+ 'year=',
+ 'monthnum=',
+ 'day=',
+ 'hour=',
+ 'minute=',
+ 'second=',
+ 'name=',
+ 'p=',
+ 'category_name=',
+ 'tag=',
+ 'author_name=',
+ 'pagename=',
+ 's='
+ );
+
+ /**
+ * Supported default feeds.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $feeds = array ( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
+
+ /**
+ * Whether permalinks are being used.
+ *
+ * This can be either rewrite module or permalink in the HTTP query string.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool True, if permalinks are enabled.
+ */
+ function using_permalinks() {
+ if (empty($this->permalink_structure))
+ return false;
+ else
+ return true;
+ }
+
+ /**
+ * Whether permalinks are being used and rewrite module is not enabled.
+ *
+ * Means that permalink links are enabled and index.php is in the URL.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool
+ */
+ function using_index_permalinks() {
+ if (empty($this->permalink_structure)) {
+ return false;
+ }
+
+ // If the index is not in the permalink, we're using mod_rewrite.
+ if (preg_match('#^/*' . $this->index . '#', $this->permalink_structure)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Whether permalinks are being used and rewrite module is enabled.
+ *
+ * Using permalinks and index.php is not in the URL.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool
+ */
+ function using_mod_rewrite_permalinks() {
+ if ( $this->using_permalinks() && ! $this->using_index_permalinks())
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Index for matches for usage in preg_*() functions.
+ *
+ * The format of the string is, with empty matches property value, '$NUM'.
+ * The 'NUM' will be replaced with the value in the $number parameter. With
+ * the matches property not empty, the value of the returned string will
+ * contain that value of the matches property. The format then will be
+ * '$MATCHES[NUM]', with MATCHES as the value in the property and NUM the
+ * value of the $number parameter.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param int $number Index number.
+ * @return string
+ */
+ function preg_index($number) {
+ $match_prefix = '$';
+ $match_suffix = '';
+
+ if ( ! empty($this->matches) ) {
+ $match_prefix = '$' . $this->matches . '[';
+ $match_suffix = ']';
+ }
+
+ return "$match_prefix$number$match_suffix";
+ }
+
+ /**
+ * Retrieve all page and attachments for pages URIs.
+ *
+ * The attachments are for those that have pages as parents and will be
+ * retrieved.
+ *
+ * @since 2.5.0
+ * @access public
+ *
+ * @return array Array of page URIs as first element and attachment URIs as second element.
+ */
+ function page_uri_index() {
+ global $wpdb;
+
+ //get pages in order of hierarchy, i.e. children after parents
+ $posts = get_page_hierarchy($wpdb->get_results("SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'page'"));
+ //now reverse it, because we need parents after children for rewrite rules to work properly
+ $posts = array_reverse($posts, true);
+
+ $page_uris = array();
+ $page_attachment_uris = array();
+
+ if ( !$posts )
+ return array( array(), array() );
+
+ foreach ($posts as $id => $post) {
+ // URL => page name
+ $uri = get_page_uri($id);
+ $attachments = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND post_parent = %d", $id ));
+ if ( $attachments ) {
+ foreach ( $attachments as $attachment ) {
+ $attach_uri = get_page_uri($attachment->ID);
+ $page_attachment_uris[$attach_uri] = $attachment->ID;
+ }
+ }
+
+ $page_uris[$uri] = $id;
+ }
+
+ return array( $page_uris, $page_attachment_uris );
+ }
+
+ /**
+ * Retrieve all of the rewrite rules for pages.
+ *
+ * If the 'use_verbose_page_rules' property is false, then there will only
+ * be a single rewrite rule for pages for those matching '%pagename%'. With
+ * the property set to true, the attachments and the pages will be added for
+ * each individual attachment URI and page URI, respectively.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return array
+ */
+ function page_rewrite_rules() {
+ $rewrite_rules = array();
+ $page_structure = $this->get_page_permastruct();
+
+ if ( ! $this->use_verbose_page_rules ) {
+ $this->add_rewrite_tag('%pagename%', "(.+?)", 'pagename=');
+ $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
+ return $rewrite_rules;
+ }
+
+ $page_uris = $this->page_uri_index();
+ $uris = $page_uris[0];
+ $attachment_uris = $page_uris[1];
+
+ if( is_array( $attachment_uris ) ) {
+ foreach ($attachment_uris as $uri => $pagename) {
+ $this->add_rewrite_tag('%pagename%', "($uri)", 'attachment=');
+ $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
+ }
+ }
+ if( is_array( $uris ) ) {
+ foreach ($uris as $uri => $pagename) {
+ $this->add_rewrite_tag('%pagename%', "($uri)", 'pagename=');
+ $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES));
+ }
+ }
+
+ return $rewrite_rules;
+ }
+
+ /**
+ * Retrieve date permalink structure, with year, month, and day.
+ *
+ * The permalink structure for the date, if not set already depends on the
+ * permalink structure. It can be one of three formats. The first is year,
+ * month, day; the second is day, month, year; and the last format is month,
+ * day, year. These are matched against the permalink structure for which
+ * one is used. If none matches, then the default will be used, which is
+ * year, month, day.
+ *
+ * Prevents post ID and date permalinks from overlapping. In the case of
+ * post_id, the date permalink will be prepended with front permalink with
+ * 'date/' before the actual permalink to form the complete date permalink
+ * structure.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on no permalink structure. Date permalink structure.
+ */
+ function get_date_permastruct() {
+ if (isset($this->date_structure)) {
+ return $this->date_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->date_structure = '';
+ return false;
+ }
+
+ // The date permalink must have year, month, and day separated by slashes.
+ $endians = array('%year%/%monthnum%/%day%', '%day%/%monthnum%/%year%', '%monthnum%/%day%/%year%');
+
+ $this->date_structure = '';
+ $date_endian = '';
+
+ foreach ($endians as $endian) {
+ if (false !== strpos($this->permalink_structure, $endian)) {
+ $date_endian= $endian;
+ break;
+ }
+ }
+
+ if ( empty($date_endian) )
+ $date_endian = '%year%/%monthnum%/%day%';
+
+ // Do not allow the date tags and %post_id% to overlap in the permalink
+ // structure. If they do, move the date tags to $front/date/.
+ $front = $this->front;
+ preg_match_all('/%.+?%/', $this->permalink_structure, $tokens);
+ $tok_index = 1;
+ foreach ( (array) $tokens[0] as $token) {
+ if ( ($token == '%post_id%') && ($tok_index <= 3) ) {
+ $front = $front . 'date/';
+ break;
+ }
+ $tok_index++;
+ }
+
+ $this->date_structure = $front . $date_endian;
+
+ return $this->date_structure;
+ }
+
+ /**
+ * Retrieve the year permalink structure without month and day.
+ *
+ * Gets the date permalink structure and strips out the month and day
+ * permalink structures.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Year structure on success.
+ */
+ function get_year_permastruct() {
+ $structure = $this->get_date_permastruct($this->permalink_structure);
+
+ if (empty($structure)) {
+ return false;
+ }
+
+ $structure = str_replace('%monthnum%', '', $structure);
+ $structure = str_replace('%day%', '', $structure);
+
+ $structure = preg_replace('#/+#', '/', $structure);
+
+ return $structure;
+ }
+
+ /**
+ * Retrieve the month permalink structure without day and with year.
+ *
+ * Gets the date permalink structure and strips out the day permalink
+ * structures. Keeps the year permalink structure.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Year/Month structure on success.
+ */
+ function get_month_permastruct() {
+ $structure = $this->get_date_permastruct($this->permalink_structure);
+
+ if (empty($structure)) {
+ return false;
+ }
+
+ $structure = str_replace('%day%', '', $structure);
+
+ $structure = preg_replace('#/+#', '/', $structure);
+
+ return $structure;
+ }
+
+ /**
+ * Retrieve the day permalink structure with month and year.
+ *
+ * Keeps date permalink structure with all year, month, and day.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Year/Month/Day structure on success.
+ */
+ function get_day_permastruct() {
+ return $this->get_date_permastruct($this->permalink_structure);
+ }
+
+ /**
+ * Retrieve the permalink structure for categories.
+ *
+ * If the category_base property has no value, then the category structure
+ * will have the front property value, followed by 'category', and finally
+ * '%category%'. If it does, then the root property will be used, along with
+ * the category_base property value.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Category permalink structure.
+ */
+ function get_category_permastruct() {
+ if (isset($this->category_structure)) {
+ return $this->category_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->category_structure = '';
+ return false;
+ }
+
+ if (empty($this->category_base))
+ $this->category_structure = trailingslashit( $this->front . 'category' );
+ else
+ $this->category_structure = trailingslashit( '/' . $this->root . $this->category_base );
+
+ $this->category_structure .= '%category%';
+
+ return $this->category_structure;
+ }
+
+ /**
+ * Retrieve the permalink structure for tags.
+ *
+ * If the tag_base property has no value, then the tag structure will have
+ * the front property value, followed by 'tag', and finally '%tag%'. If it
+ * does, then the root property will be used, along with the tag_base
+ * property value.
+ *
+ * @since 2.3.0
+ * @access public
+ *
+ * @return bool|string False on failure. Tag permalink structure.
+ */
+ function get_tag_permastruct() {
+ if (isset($this->tag_structure)) {
+ return $this->tag_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->tag_structure = '';
+ return false;
+ }
+
+ if (empty($this->tag_base))
+ $this->tag_structure = trailingslashit( $this->front . 'tag' );
+ else
+ $this->tag_structure = trailingslashit( '/' . $this->root . $this->tag_base );
+
+ $this->tag_structure .= '%tag%';
+
+ return $this->tag_structure;
+ }
+
+ /**
+ * Retrieve extra permalink structure by name.
+ *
+ * @since unknown
+ * @access public
+ *
+ * @param string $name Permalink structure name.
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_extra_permastruct($name) {
+ if ( isset($this->extra_permastructs[$name]) )
+ return $this->extra_permastructs[$name];
+ return false;
+ }
+
+ /**
+ * Retrieve the author permalink structure.
+ *
+ * The permalink structure is front property, author base, and finally
+ * '/%author%'. Will set the author_structure property and then return it
+ * without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_author_permastruct() {
+ if (isset($this->author_structure)) {
+ return $this->author_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->author_structure = '';
+ return false;
+ }
+
+ $this->author_structure = $this->front . $this->author_base . '/%author%';
+
+ return $this->author_structure;
+ }
+
+ /**
+ * Retrieve the search permalink structure.
+ *
+ * The permalink structure is root property, search base, and finally
+ * '/%search%'. Will set the search_structure property and then return it
+ * without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_search_permastruct() {
+ if (isset($this->search_structure)) {
+ return $this->search_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->search_structure = '';
+ return false;
+ }
+
+ $this->search_structure = $this->root . $this->search_base . '/%search%';
+
+ return $this->search_structure;
+ }
+
+ /**
+ * Retrieve the page permalink structure.
+ *
+ * The permalink structure is root property, and '%pagename%'. Will set the
+ * page_structure property and then return it without attempting to set the
+ * value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_page_permastruct() {
+ if (isset($this->page_structure)) {
+ return $this->page_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->page_structure = '';
+ return false;
+ }
+
+ $this->page_structure = $this->root . '%pagename%';
+
+ return $this->page_structure;
+ }
+
+ /**
+ * Retrieve the feed permalink structure.
+ *
+ * The permalink structure is root property, feed base, and finally
+ * '/%feed%'. Will set the feed_structure property and then return it
+ * without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_feed_permastruct() {
+ if (isset($this->feed_structure)) {
+ return $this->feed_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->feed_structure = '';
+ return false;
+ }
+
+ $this->feed_structure = $this->root . $this->feed_base . '/%feed%';
+
+ return $this->feed_structure;
+ }
+
+ /**
+ * Retrieve the comment feed permalink structure.
+ *
+ * The permalink structure is root property, comment base property, feed
+ * base and finally '/%feed%'. Will set the comment_feed_structure property
+ * and then return it without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_comment_feed_permastruct() {
+ if (isset($this->comment_feed_structure)) {
+ return $this->comment_feed_structure;
+ }
+
+ if (empty($this->permalink_structure)) {
+ $this->comment_feed_structure = '';
+ return false;
+ }
+
+ $this->comment_feed_structure = $this->root . $this->comments_base . '/' . $this->feed_base . '/%feed%';
+
+ return $this->comment_feed_structure;
+ }
+
+ /**
+ * Append or update tag, pattern, and query for replacement.
+ *
+ * If the tag already exists, replace the existing pattern and query for
+ * that tag, otherwise add the new tag, pattern, and query to the end of the
+ * arrays.
+ *
+ * @internal What is the purpose of this function again? Need to finish long
+ * description.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $tag Append tag to rewritecode property array.
+ * @param string $pattern Append pattern to rewritereplace property array.
+ * @param string $query Append query to queryreplace property array.
+ */
+ function add_rewrite_tag($tag, $pattern, $query) {
+ $position = array_search($tag, $this->rewritecode);
+ if ( false !== $position && null !== $position ) {
+ $this->rewritereplace[$position] = $pattern;
+ $this->queryreplace[$position] = $query;
+ } else {
+ $this->rewritecode[] = $tag;
+ $this->rewritereplace[] = $pattern;
+ $this->queryreplace[] = $query;
+ }
+ }
+
+ /**
+ * Generate the rules from permalink structure.
+ *
+ * The main WP_Rewrite function for building the rewrite rule list. The
+ * contents of the function is a mix of black magic and regular expressions,
+ * so best just ignore the contents and move to the parameters.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $permalink_structure The permalink structure.
+ * @param int $ep_mask Optional, default is EP_NONE. Endpoint constant, see EP_* constants.
+ * @param bool $paged Optional, default is true. Whether permalink request is paged.
+ * @param bool $feed Optional, default is true. Whether for feed.
+ * @param bool $forcomments Optional, default is false. Whether for comments.
+ * @param bool $walk_dirs Optional, default is true. Whether to create list of directories to walk over.
+ * @param bool $endpoints Optional, default is true. Whether endpoints are enabled.
+ * @return array Rewrite rule list.
+ */
+ function generate_rewrite_rules($permalink_structure, $ep_mask = EP_NONE, $paged = true, $feed = true, $forcomments = false, $walk_dirs = true, $endpoints = true) {
+ //build a regex to match the feed section of URLs, something like (feed|atom|rss|rss2)/?
+ $feedregex2 = '';
+ foreach ( (array) $this->feeds as $feed_name) {
+ $feedregex2 .= $feed_name . '|';
+ }
+ $feedregex2 = '(' . trim($feedregex2, '|') . ')/?$';
+ //$feedregex is identical but with /feed/ added on as well, so URLs like /feed/atom
+ //and /atom are both possible
+ $feedregex = $this->feed_base . '/' . $feedregex2;
+
+ //build a regex to match the trackback and page/xx parts of URLs
+ $trackbackregex = 'trackback/?$';
+ $pageregex = 'page/?([0-9]{1,})/?$';
+ $commentregex = 'comment-page-([0-9]{1,})/?$';
+
+ //build up an array of endpoint regexes to append => queries to append
+ if ($endpoints) {
+ $ep_query_append = array ();
+ foreach ( (array) $this->endpoints as $endpoint) {
+ //match everything after the endpoint name, but allow for nothing to appear there
+ $epmatch = $endpoint[1] . '(/(.*))?/?$';
+ //this will be appended on to the rest of the query for each dir
+ $epquery = '&' . $endpoint[1] . '=';
+ $ep_query_append[$epmatch] = array ( $endpoint[0], $epquery );
+ }
+ }
+
+ //get everything up to the first rewrite tag
+ $front = substr($permalink_structure, 0, strpos($permalink_structure, '%'));
+ //build an array of the tags (note that said array ends up being in $tokens[0])
+ preg_match_all('/%.+?%/', $permalink_structure, $tokens);
+
+ $num_tokens = count($tokens[0]);
+
+ $index = $this->index; //probably 'index.php'
+ $feedindex = $index;
+ $trackbackindex = $index;
+ //build a list from the rewritecode and queryreplace arrays, that will look something like
+ //tagname=$matches[i] where i is the current $i
+ for ($i = 0; $i < $num_tokens; ++$i) {
+ if (0 < $i) {
+ $queries[$i] = $queries[$i - 1] . '&';
+ } else {
+ $queries[$i] = '';
+ }
+
+ $query_token = str_replace($this->rewritecode, $this->queryreplace, $tokens[0][$i]) . $this->preg_index($i+1);
+ $queries[$i] .= $query_token;
+ }
+
+ //get the structure, minus any cruft (stuff that isn't tags) at the front
+ $structure = $permalink_structure;
+ if ($front != '/') {
+ $structure = str_replace($front, '', $structure);
+ }
+ //create a list of dirs to walk over, making rewrite rules for each level
+ //so for example, a $structure of /%year%/%month%/%postname% would create
+ //rewrite rules for /%year%/, /%year%/%month%/ and /%year%/%month%/%postname%
+ $structure = trim($structure, '/');
+ if ($walk_dirs) {
+ $dirs = explode('/', $structure);
+ } else {
+ $dirs[] = $structure;
+ }
+ $num_dirs = count($dirs);
+
+ //strip slashes from the front of $front
+ $front = preg_replace('|^/+|', '', $front);
+
+ //the main workhorse loop
+ $post_rewrite = array();
+ $struct = $front;
+ for ($j = 0; $j < $num_dirs; ++$j) {
+ //get the struct for this dir, and trim slashes off the front
+ $struct .= $dirs[$j] . '/'; //accumulate. see comment near explode('/', $structure) above
+ $struct = ltrim($struct, '/');
+ //replace tags with regexes
+ $match = str_replace($this->rewritecode, $this->rewritereplace, $struct);
+ //make a list of tags, and store how many there are in $num_toks
+ $num_toks = preg_match_all('/%.+?%/', $struct, $toks);
+ //get the 'tagname=$matches[i]'
+ $query = ( isset($queries) && is_array($queries) ) ? $queries[$num_toks - 1] : '';
+
+ //set up $ep_mask_specific which is used to match more specific URL types
+ switch ($dirs[$j]) {
+ case '%year%': $ep_mask_specific = EP_YEAR; break;
+ case '%monthnum%': $ep_mask_specific = EP_MONTH; break;
+ case '%day%': $ep_mask_specific = EP_DAY; break;
+ }
+
+ //create query for /page/xx
+ $pagematch = $match . $pageregex;
+ $pagequery = $index . '?' . $query . '&paged=' . $this->preg_index($num_toks + 1);
+
+ //create query for /comment-page-xx
+ $commentmatch = $match . $commentregex;
+ $commentquery = $index . '?' . $query . '&cpage=' . $this->preg_index($num_toks + 1);
+
+ //create query for /feed/(feed|atom|rss|rss2|rdf)
+ $feedmatch = $match . $feedregex;
+ $feedquery = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
+
+ //create query for /(feed|atom|rss|rss2|rdf) (see comment near creation of $feedregex)
+ $feedmatch2 = $match . $feedregex2;
+ $feedquery2 = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
+
+ //if asked to, turn the feed queries into comment feed ones
+ if ($forcomments) {
+ $feedquery .= '&withcomments=1';
+ $feedquery2 .= '&withcomments=1';
+ }
+
+ //start creating the array of rewrites for this dir
+ $rewrite = array();
+ if ($feed) //...adding on /feed/ regexes => queries
+ $rewrite = array($feedmatch => $feedquery, $feedmatch2 => $feedquery2);
+ if ($paged) //...and /page/xx ones
+ $rewrite = array_merge($rewrite, array($pagematch => $pagequery));
+
+ //only on pages with comments add ../comment-page-xx/
+ if ( EP_PAGES & $ep_mask || EP_PERMALINK & $ep_mask || EP_NONE & $ep_mask )
+ $rewrite = array_merge($rewrite, array($commentmatch => $commentquery));
+
+ //do endpoints
+ if ($endpoints) {
+ foreach ( (array) $ep_query_append as $regex => $ep) {
+ //add the endpoints on if the mask fits
+ if ($ep[0] & $ep_mask || $ep[0] & $ep_mask_specific) {
+ $rewrite[$match . $regex] = $index . '?' . $query . $ep[1] . $this->preg_index($num_toks + 2);
+ }
+ }
+ }
+
+ //if we've got some tags in this dir
+ if ($num_toks) {
+ $post = false;
+ $page = false;
+
+ //check to see if this dir is permalink-level: i.e. the structure specifies an
+ //individual post. Do this by checking it contains at least one of 1) post name,
+ //2) post ID, 3) page name, 4) timestamp (year, month, day, hour, second and
+ //minute all present). Set these flags now as we need them for the endpoints.
+ if (strpos($struct, '%postname%') !== false || strpos($struct, '%post_id%') !== false
+ || strpos($struct, '%pagename%') !== false
+ || (strpos($struct, '%year%') !== false && strpos($struct, '%monthnum%') !== false && strpos($struct, '%day%') !== false && strpos($struct, '%hour%') !== false && strpos($struct, '%minute%') !== false && strpos($struct, '%second%') !== false)) {
+ $post = true;
+ if (strpos($struct, '%pagename%') !== false)
+ $page = true;
+ }
+
+ //if we're creating rules for a permalink, do all the endpoints like attachments etc
+ if ($post) {
+ $post = true;
+ //create query and regex for trackback
+ $trackbackmatch = $match . $trackbackregex;
+ $trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
+ //trim slashes from the end of the regex for this dir
+ $match = rtrim($match, '/');
+ //get rid of brackets
+ $submatchbase = str_replace(array('(',')'),'',$match);
+
+ //add a rule for at attachments, which take the form of /some-text
+ $sub1 = $submatchbase . '/([^/]+)/';
+ $sub1tb = $sub1 . $trackbackregex; //add trackback regex /trackback/...
+ $sub1feed = $sub1 . $feedregex; //and /feed/(atom|...)
+ $sub1feed2 = $sub1 . $feedregex2; //and /(feed|atom...)
+ $sub1comment = $sub1 . $commentregex; //and /comment-page-xx
+ //add an ? as we don't have to match that last slash, and finally a $ so we
+ //match to the end of the URL
+
+ //add another rule to match attachments in the explicit form:
+ ///attachment/some-text
+ $sub2 = $submatchbase . '/attachment/([^/]+)/';
+ $sub2tb = $sub2 . $trackbackregex; //and add trackbacks /attachment/trackback
+ $sub2feed = $sub2 . $feedregex; //feeds, /attachment/feed/(atom|...)
+ $sub2feed2 = $sub2 . $feedregex2; //and feeds again on to this /attachment/(feed|atom...)
+ $sub2comment = $sub2 . $commentregex; //and /comment-page-xx
+
+ //create queries for these extra tag-ons we've just dealt with
+ $subquery = $index . '?attachment=' . $this->preg_index(1);
+ $subtbquery = $subquery . '&tb=1';
+ $subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
+ $subcommentquery = $subquery . '&cpage=' . $this->preg_index(2);
+
+ //do endpoints for attachments
+ if ( !empty($endpoint) ) { foreach ( (array) $ep_query_append as $regex => $ep ) {
+ if ($ep[0] & EP_ATTACHMENT) {
+ $rewrite[$sub1 . $regex] = $subquery . '?' . $ep[1] . $this->preg_index(2);
+ $rewrite[$sub2 . $regex] = $subquery . '?' . $ep[1] . $this->preg_index(2);
+ }
+ } }
+
+ //now we've finished with endpoints, finish off the $sub1 and $sub2 matches
+ $sub1 .= '?$';
+ $sub2 .= '?$';
+
+ //allow URLs like /2 for /page/2
+ $match = $match . '(/[0-9]+)?/?$';
+ $query = $index . '?' . $query . '&page=' . $this->preg_index($num_toks + 1);
+ } else { //not matching a permalink so this is a lot simpler
+ //close the match and finalise the query
+ $match .= '?$';
+ $query = $index . '?' . $query;
+ }
+
+ //create the final array for this dir by joining the $rewrite array (which currently
+ //only contains rules/queries for trackback, pages etc) to the main regex/query for
+ //this dir
+ $rewrite = array_merge($rewrite, array($match => $query));
+
+ //if we're matching a permalink, add those extras (attachments etc) on
+ if ($post) {
+ //add trackback
+ $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
+
+ //add regexes/queries for attachments, attachment trackbacks and so on
+ if ( ! $page ) //require /attachment/stuff form for pages because of confusion with subpages
+ $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery));
+ $rewrite = array_merge(array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery), $rewrite);
+ }
+ } //if($num_toks)
+ //add the rules for this dir to the accumulating $post_rewrite
+ $post_rewrite = array_merge($rewrite, $post_rewrite);
+ } //foreach ($dir)
+ return $post_rewrite; //the finished rules. phew!
+ }
+
+ /**
+ * Generate Rewrite rules with permalink structure and walking directory only.
+ *
+ * Shorten version of {@link WP_Rewrite::generate_rewrite_rules()} that
+ * allows for shorter list of parameters. See the method for longer
+ * description of what generating rewrite rules does.
+ *
+ * @uses WP_Rewrite::generate_rewrite_rules() See for long description and rest of parameters.
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $permalink_structure The permalink structure to generate rules.
+ * @param bool $walk_dirs Optional, default is false. Whether to create list of directories to walk over.
+ * @return array
+ */
+ function generate_rewrite_rule($permalink_structure, $walk_dirs = false) {
+ return $this->generate_rewrite_rules($permalink_structure, EP_NONE, false, false, false, $walk_dirs);
+ }
+
+ /**
+ * Construct rewrite matches and queries from permalink structure.
+ *
+ * Runs the action 'generate_rewrite_rules' with the parameter that is an
+ * reference to the current WP_Rewrite instance to further manipulate the
+ * permalink structures and rewrite rules. Runs the 'rewrite_rules_array'
+ * filter on the full rewrite rule array.
+ *
+ * There are two ways to manipulate the rewrite rules, one by hooking into
+ * the 'generate_rewrite_rules' action and gaining full control of the
+ * object or just manipulating the rewrite rule array before it is passed
+ * from the function.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return array An associate array of matches and queries.
+ */
+ function rewrite_rules() {
+ $rewrite = array();
+
+ if (empty($this->permalink_structure)) {
+ return $rewrite;
+ }
+
+ // robots.txt
+ $robots_rewrite = array('robots\.txt$' => $this->index . '?robots=1');
+
+ //Default Feed rules - These are require to allow for the direct access files to work with permalink structure starting with %category%
+ $default_feeds = array( '.*wp-atom.php$' => $this->index .'?feed=atom',
+ '.*wp-rdf.php$' => $this->index .'?feed=rdf',
+ '.*wp-rss.php$' => $this->index .'?feed=rss',
+ '.*wp-rss2.php$' => $this->index .'?feed=rss2',
+ '.*wp-feed.php$' => $this->index .'?feed=feed',
+ '.*wp-commentsrss2.php$' => $this->index . '?feed=rss2&withcomments=1');
+
+ // Post
+ $post_rewrite = $this->generate_rewrite_rules($this->permalink_structure, EP_PERMALINK);
+ $post_rewrite = apply_filters('post_rewrite_rules', $post_rewrite);
+
+ // Date
+ $date_rewrite = $this->generate_rewrite_rules($this->get_date_permastruct(), EP_DATE);
+ $date_rewrite = apply_filters('date_rewrite_rules', $date_rewrite);
+
+ // Root
+ $root_rewrite = $this->generate_rewrite_rules($this->root . '/', EP_ROOT);
+ $root_rewrite = apply_filters('root_rewrite_rules', $root_rewrite);
+
+ // Comments
+ $comments_rewrite = $this->generate_rewrite_rules($this->root . $this->comments_base, EP_COMMENTS, true, true, true, false);
+ $comments_rewrite = apply_filters('comments_rewrite_rules', $comments_rewrite);
+
+ // Search
+ $search_structure = $this->get_search_permastruct();
+ $search_rewrite = $this->generate_rewrite_rules($search_structure, EP_SEARCH);
+ $search_rewrite = apply_filters('search_rewrite_rules', $search_rewrite);
+
+ // Categories
+ $category_rewrite = $this->generate_rewrite_rules($this->get_category_permastruct(), EP_CATEGORIES);
+ $category_rewrite = apply_filters('category_rewrite_rules', $category_rewrite);
+
+ // Tags
+ $tag_rewrite = $this->generate_rewrite_rules($this->get_tag_permastruct(), EP_TAGS);
+ $tag_rewrite = apply_filters('tag_rewrite_rules', $tag_rewrite);
+
+ // Authors
+ $author_rewrite = $this->generate_rewrite_rules($this->get_author_permastruct(), EP_AUTHORS);
+ $author_rewrite = apply_filters('author_rewrite_rules', $author_rewrite);
+
+ // Pages
+ $page_rewrite = $this->page_rewrite_rules();
+ $page_rewrite = apply_filters('page_rewrite_rules', $page_rewrite);
+
+ // Extra permastructs
+ foreach ( $this->extra_permastructs as $permastruct )
+ $this->extra_rules_top = array_merge($this->extra_rules_top, $this->generate_rewrite_rules($permastruct, EP_NONE));
+
+ // Put them together.
+ if ( $this->use_verbose_page_rules )
+ $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $page_rewrite, $root_rewrite, $comments_rewrite, $search_rewrite, $category_rewrite, $tag_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $this->extra_rules);
+ else
+ $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $default_feeds, $root_rewrite, $comments_rewrite, $search_rewrite, $category_rewrite, $tag_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules);
+
+ do_action_ref_array('generate_rewrite_rules', array(&$this));
+ $this->rules = apply_filters('rewrite_rules_array', $this->rules);
+
+ return $this->rules;
+ }
+
+ /**
+ * Retrieve the rewrite rules.
+ *
+ * The difference between this method and {@link
+ * WP_Rewrite::rewrite_rules()} is that this method stores the rewrite rules
+ * in the 'rewrite_rules' option and retrieves it. This prevents having to
+ * process all of the permalinks to get the rewrite rules in the form of
+ * caching.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return array Rewrite rules.
+ */
+ function wp_rewrite_rules() {
+ $this->rules = get_option('rewrite_rules');
+ if ( empty($this->rules) ) {
+ $this->matches = 'matches';
+ $this->rewrite_rules();
+ update_option('rewrite_rules', $this->rules);
+ }
+
+ return $this->rules;
+ }
+
+ /**
+ * Retrieve mod_rewrite formatted rewrite rules to write to .htaccess.
+ *
+ * Does not actually write to the .htaccess file, but creates the rules for
+ * the process that will.
+ *
+ * Will add the non_wp_rules property rules to the .htaccess file before
+ * the WordPress rewrite rules one.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string
+ */
+ function mod_rewrite_rules() {
+ if ( ! $this->using_permalinks()) {
+ return '';
+ }
+
+ $site_root = parse_url(get_option('siteurl'));
+ if ( isset( $site_root['path'] ) ) {
+ $site_root = trailingslashit($site_root['path']);
+ }
+
+ $home_root = parse_url(get_option('home'));
+ if ( isset( $home_root['path'] ) ) {
+ $home_root = trailingslashit($home_root['path']);
+ } else {
+ $home_root = '/';
+ }
+
+ $rules = "\n";
+ $rules .= "RewriteEngine On\n";
+ $rules .= "RewriteBase $home_root\n";
+
+ //add in the rules that don't redirect to WP's index.php (and thus shouldn't be handled by WP at all)
+ foreach ( (array) $this->non_wp_rules as $match => $query) {
+ // Apache 1.3 does not support the reluctant (non-greedy) modifier.
+ $match = str_replace('.+?', '.+', $match);
+
+ // If the match is unanchored and greedy, prepend rewrite conditions
+ // to avoid infinite redirects and eclipsing of real files.
+ if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
+ //nada.
+ }
+
+ $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
+ }
+
+ if ($this->use_verbose_rules) {
+ $this->matches = '';
+ $rewrite = $this->rewrite_rules();
+ $num_rules = count($rewrite);
+ $rules .= "RewriteCond %{REQUEST_FILENAME} -f [OR]\n" .
+ "RewriteCond %{REQUEST_FILENAME} -d\n" .
+ "RewriteRule ^.*$ - [S=$num_rules]\n";
+
+ foreach ( (array) $rewrite as $match => $query) {
+ // Apache 1.3 does not support the reluctant (non-greedy) modifier.
+ $match = str_replace('.+?', '.+', $match);
+
+ // If the match is unanchored and greedy, prepend rewrite conditions
+ // to avoid infinite redirects and eclipsing of real files.
+ if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
+ //nada.
+ }
+
+ if (strpos($query, $this->index) !== false) {
+ $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
+ } else {
+ $rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n";
+ }
+ }
+ } else {
+ $rules .= "RewriteCond %{REQUEST_FILENAME} !-f\n" .
+ "RewriteCond %{REQUEST_FILENAME} !-d\n" .
+ "RewriteRule . {$home_root}{$this->index} [L]\n";
+ }
+
+ $rules .= " \n";
+
+ $rules = apply_filters('mod_rewrite_rules', $rules);
+ $rules = apply_filters('rewrite_rules', $rules); // Deprecated
+
+ return $rules;
+ }
+
+ /**
+ * Add a straight rewrite rule.
+ *
+ * Any value in the $after parameter that isn't 'bottom' will be placed at
+ * the top of the rules.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $regex Regular expression to match against request.
+ * @param string $redirect URL regex redirects to when regex matches request.
+ * @param string $after Optional, default is bottom. Location to place rule.
+ */
+ function add_rule($regex, $redirect, $after = 'bottom') {
+ //get everything up to the first ?
+ $index = (strpos($redirect, '?') == false ? strlen($redirect) : strpos($redirect, '?'));
+ $front = substr($redirect, 0, $index);
+ if ($front != $this->index) { //it doesn't redirect to WP's index.php
+ $this->add_external_rule($regex, $redirect);
+ } else {
+ if ( 'bottom' == $after)
+ $this->extra_rules = array_merge($this->extra_rules, array($regex => $redirect));
+ else
+ $this->extra_rules_top = array_merge($this->extra_rules_top, array($regex => $redirect));
+ //$this->extra_rules[$regex] = $redirect;
+ }
+ }
+
+ /**
+ * Add a rule that doesn't redirect to index.php.
+ *
+ * Can redirect to any place.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $regex Regular expression to match against request.
+ * @param string $redirect URL regex redirects to when regex matches request.
+ */
+ function add_external_rule($regex, $redirect) {
+ $this->non_wp_rules[$regex] = $redirect;
+ }
+
+ /**
+ * Add an endpoint, like /trackback/.
+ *
+ * To be inserted after certain URL types (specified in $places).
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $name Name of endpoint.
+ * @param array $places URL types that endpoint can be used.
+ */
+ function add_endpoint($name, $places) {
+ global $wp;
+ $this->endpoints[] = array ( $places, $name );
+ $wp->add_query_var($name);
+ }
+
+ /**
+ * Add permalink structure.
+ *
+ * These are added along with the extra rewrite rules that are merged to the
+ * top.
+ *
+ * @since unknown
+ * @access public
+ *
+ * @param string $name Name for permalink structure.
+ * @param string $struct Permalink structure.
+ * @param bool $with_front Prepend front base to permalink structure.
+ */
+ function add_permastruct($name, $struct, $with_front = true) {
+ if ( $with_front )
+ $struct = $this->front . $struct;
+ $this->extra_permastructs[$name] = $struct;
+ }
+
+ /**
+ * Remove rewrite rules and then recreate rewrite rules.
+ *
+ * Calls {@link WP_Rewrite::wp_rewrite_rules()} after removing the
+ * 'rewrite_rules' option. If the function named 'save_mod_rewrite_rules'
+ * exists, it will be called.
+ *
+ * @since 2.0.1
+ * @access public
+ */
+ function flush_rules() {
+ delete_option('rewrite_rules');
+ $this->wp_rewrite_rules();
+ if ( function_exists('save_mod_rewrite_rules') )
+ save_mod_rewrite_rules();
+ }
+
+ /**
+ * Sets up the object's properties.
+ *
+ * The 'use_verbose_page_rules' object property will be turned on, if the
+ * permalink structure includes the following: '%postname%', '%category%',
+ * '%tag%', or '%author%'.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function init() {
+ $this->extra_rules = $this->non_wp_rules = $this->endpoints = array();
+ $this->permalink_structure = get_option('permalink_structure');
+ $this->front = substr($this->permalink_structure, 0, strpos($this->permalink_structure, '%'));
+ $this->root = '';
+ if ($this->using_index_permalinks()) {
+ $this->root = $this->index . '/';
+ }
+ $this->category_base = get_option( 'category_base' );
+ $this->tag_base = get_option( 'tag_base' );
+ unset($this->category_structure);
+ unset($this->author_structure);
+ unset($this->date_structure);
+ unset($this->page_structure);
+ unset($this->search_structure);
+ unset($this->feed_structure);
+ unset($this->comment_feed_structure);
+ $this->use_trailing_slashes = ( substr($this->permalink_structure, -1, 1) == '/' ) ? true : false;
+
+ // Enable generic rules for pages if permalink structure doesn't begin with a wildcard.
+ $structure = ltrim($this->permalink_structure, '/');
+ if ( $this->using_index_permalinks() )
+ $structure = ltrim($this->permalink_structure, $this->index . '/');
+ if ( 0 === strpos($structure, '%postname%') ||
+ 0 === strpos($structure, '%category%') ||
+ 0 === strpos($structure, '%tag%') ||
+ 0 === strpos($structure, '%author%') )
+ $this->use_verbose_page_rules = true;
+ else
+ $this->use_verbose_page_rules = false;
+ }
+
+ /**
+ * Set the main permalink structure for the blog.
+ *
+ * Will update the 'permalink_structure' option, if there is a difference
+ * between the current permalink structure and the parameter value. Calls
+ * {@link WP_Rewrite::init()} after the option is updated.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $permalink_structure Permalink structure.
+ */
+ function set_permalink_structure($permalink_structure) {
+ if ($permalink_structure != $this->permalink_structure) {
+ update_option('permalink_structure', $permalink_structure);
+ $this->init();
+ }
+ }
+
+ /**
+ * Set the category base for the category permalink.
+ *
+ * Will update the 'category_base' option, if there is a difference between
+ * the current category base and the parameter value. Calls
+ * {@link WP_Rewrite::init()} after the option is updated.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $category_base Category permalink structure base.
+ */
+ function set_category_base($category_base) {
+ if ($category_base != $this->category_base) {
+ update_option('category_base', $category_base);
+ $this->init();
+ }
+ }
+
+ /**
+ * Set the tag base for the tag permalink.
+ *
+ * Will update the 'tag_base' option, if there is a difference between the
+ * current tag base and the parameter value. Calls
+ * {@link WP_Rewrite::init()} after the option is updated.
+ *
+ * @since 2.3.0
+ * @access public
+ *
+ * @param string $tag_base Tag permalink structure base.
+ */
+ function set_tag_base( $tag_base ) {
+ if ( $tag_base != $this->tag_base ) {
+ update_option( 'tag_base', $tag_base );
+ $this->init();
+ }
+ }
+
+ /**
+ * PHP4 Constructor - Calls init(), which runs setup.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return WP_Rewrite
+ */
+ function WP_Rewrite() {
+ $this->init();
+ }
+}
+
+?>
diff -uNr a/blog/wp-includes/rss-functions.php b/blog/wp-includes/rss-functions.php
--- a/blog/wp-includes/rss-functions.php false
+++ b/blog/wp-includes/rss-functions.php e5c1a45c42273fcb3b22076b7df7fa27ec661eb8d58c61ac65505894dd19a5e2e796a4061e0842c86b41e5b45084fdaca6413e07ff579fcffc406e40fdc8539d
@@ -0,0 +1,10 @@
+
diff -uNr a/blog/wp-includes/rss.php b/blog/wp-includes/rss.php
--- a/blog/wp-includes/rss.php false
+++ b/blog/wp-includes/rss.php 6443165c6de7dc5844355f978c0d276c8ed2f741ac617a135cd976bb00ffe104d49f3c2480c6b159b050840666c755ee6d90f10ee18e3b85f12463cfa20154e4
@@ -0,0 +1,943 @@
+
+ * @version 0.51
+ * @license GPL
+ *
+ * @package External
+ * @subpackage MagpieRSS
+ */
+
+/*
+ * Hook to use another RSS object instead of MagpieRSS
+ */
+do_action('load_feed_engine');
+
+/** RSS feed constant. */
+define('RSS', 'RSS');
+define('ATOM', 'Atom');
+define('MAGPIE_USER_AGENT', 'WordPress/' . $GLOBALS['wp_version']);
+
+class MagpieRSS {
+ var $parser;
+ var $current_item = array(); // item currently being parsed
+ var $items = array(); // collection of parsed items
+ var $channel = array(); // hash of channel fields
+ var $textinput = array();
+ var $image = array();
+ var $feed_type;
+ var $feed_version;
+
+ // parser variables
+ var $stack = array(); // parser stack
+ var $inchannel = false;
+ var $initem = false;
+ var $incontent = false; // if in Atom field
+ var $intextinput = false;
+ var $inimage = false;
+ var $current_field = '';
+ var $current_namespace = false;
+
+ //var $ERROR = "";
+
+ var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright');
+
+ function MagpieRSS ($source) {
+
+ # if PHP xml isn't compiled in, die
+ #
+ if ( !function_exists('xml_parser_create') )
+ trigger_error( "Failed to load PHP's XML Extension. http://www.php.net/manual/en/ref.xml.php" );
+
+ $parser = @xml_parser_create();
+
+ if ( !is_resource($parser) )
+ trigger_error( "Failed to create an instance of PHP's XML parser. http://www.php.net/manual/en/ref.xml.php");
+
+
+ $this->parser = $parser;
+
+ # pass in parser, and a reference to this object
+ # setup handlers
+ #
+ xml_set_object( $this->parser, $this );
+ xml_set_element_handler($this->parser,
+ 'feed_start_element', 'feed_end_element' );
+
+ xml_set_character_data_handler( $this->parser, 'feed_cdata' );
+
+ $status = xml_parse( $this->parser, $source );
+
+ if (! $status ) {
+ $errorcode = xml_get_error_code( $this->parser );
+ if ( $errorcode != XML_ERROR_NONE ) {
+ $xml_error = xml_error_string( $errorcode );
+ $error_line = xml_get_current_line_number($this->parser);
+ $error_col = xml_get_current_column_number($this->parser);
+ $errormsg = "$xml_error at line $error_line, column $error_col";
+
+ $this->error( $errormsg );
+ }
+ }
+
+ xml_parser_free( $this->parser );
+
+ $this->normalize();
+ }
+
+ function feed_start_element($p, $element, &$attrs) {
+ $el = $element = strtolower($element);
+ $attrs = array_change_key_case($attrs, CASE_LOWER);
+
+ // check for a namespace, and split if found
+ $ns = false;
+ if ( strpos( $element, ':' ) ) {
+ list($ns, $el) = split( ':', $element, 2);
+ }
+ if ( $ns and $ns != 'rdf' ) {
+ $this->current_namespace = $ns;
+ }
+
+ # if feed type isn't set, then this is first element of feed
+ # identify feed from root element
+ #
+ if (!isset($this->feed_type) ) {
+ if ( $el == 'rdf' ) {
+ $this->feed_type = RSS;
+ $this->feed_version = '1.0';
+ }
+ elseif ( $el == 'rss' ) {
+ $this->feed_type = RSS;
+ $this->feed_version = $attrs['version'];
+ }
+ elseif ( $el == 'feed' ) {
+ $this->feed_type = ATOM;
+ $this->feed_version = $attrs['version'];
+ $this->inchannel = true;
+ }
+ return;
+ }
+
+ if ( $el == 'channel' )
+ {
+ $this->inchannel = true;
+ }
+ elseif ($el == 'item' or $el == 'entry' )
+ {
+ $this->initem = true;
+ if ( isset($attrs['rdf:about']) ) {
+ $this->current_item['about'] = $attrs['rdf:about'];
+ }
+ }
+
+ // if we're in the default namespace of an RSS feed,
+ // record textinput or image fields
+ elseif (
+ $this->feed_type == RSS and
+ $this->current_namespace == '' and
+ $el == 'textinput' )
+ {
+ $this->intextinput = true;
+ }
+
+ elseif (
+ $this->feed_type == RSS and
+ $this->current_namespace == '' and
+ $el == 'image' )
+ {
+ $this->inimage = true;
+ }
+
+ # handle atom content constructs
+ elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
+ {
+ // avoid clashing w/ RSS mod_content
+ if ($el == 'content' ) {
+ $el = 'atom_content';
+ }
+
+ $this->incontent = $el;
+
+
+ }
+
+ // if inside an Atom content construct (e.g. content or summary) field treat tags as text
+ elseif ($this->feed_type == ATOM and $this->incontent )
+ {
+ // if tags are inlined, then flatten
+ $attrs_str = join(' ',
+ array_map('map_attrs',
+ array_keys($attrs),
+ array_values($attrs) ) );
+
+ $this->append_content( "<$element $attrs_str>" );
+
+ array_unshift( $this->stack, $el );
+ }
+
+ // Atom support many links per containging element.
+ // Magpie treats link elements of type rel='alternate'
+ // as being equivalent to RSS's simple link element.
+ //
+ elseif ($this->feed_type == ATOM and $el == 'link' )
+ {
+ if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' )
+ {
+ $link_el = 'link';
+ }
+ else {
+ $link_el = 'link_' . $attrs['rel'];
+ }
+
+ $this->append($link_el, $attrs['href']);
+ }
+ // set stack[0] to current element
+ else {
+ array_unshift($this->stack, $el);
+ }
+ }
+
+
+
+ function feed_cdata ($p, $text) {
+
+ if ($this->feed_type == ATOM and $this->incontent)
+ {
+ $this->append_content( $text );
+ }
+ else {
+ $current_el = join('_', array_reverse($this->stack));
+ $this->append($current_el, $text);
+ }
+ }
+
+ function feed_end_element ($p, $el) {
+ $el = strtolower($el);
+
+ if ( $el == 'item' or $el == 'entry' )
+ {
+ $this->items[] = $this->current_item;
+ $this->current_item = array();
+ $this->initem = false;
+ }
+ elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
+ {
+ $this->intextinput = false;
+ }
+ elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' )
+ {
+ $this->inimage = false;
+ }
+ elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
+ {
+ $this->incontent = false;
+ }
+ elseif ($el == 'channel' or $el == 'feed' )
+ {
+ $this->inchannel = false;
+ }
+ elseif ($this->feed_type == ATOM and $this->incontent ) {
+ // balance tags properly
+ // note: i don't think this is actually neccessary
+ if ( $this->stack[0] == $el )
+ {
+ $this->append_content("");
+ }
+ else {
+ $this->append_content("<$el />");
+ }
+
+ array_shift( $this->stack );
+ }
+ else {
+ array_shift( $this->stack );
+ }
+
+ $this->current_namespace = false;
+ }
+
+ function concat (&$str1, $str2="") {
+ if (!isset($str1) ) {
+ $str1="";
+ }
+ $str1 .= $str2;
+ }
+
+ function append_content($text) {
+ if ( $this->initem ) {
+ $this->concat( $this->current_item[ $this->incontent ], $text );
+ }
+ elseif ( $this->inchannel ) {
+ $this->concat( $this->channel[ $this->incontent ], $text );
+ }
+ }
+
+ // smart append - field and namespace aware
+ function append($el, $text) {
+ if (!$el) {
+ return;
+ }
+ if ( $this->current_namespace )
+ {
+ if ( $this->initem ) {
+ $this->concat(
+ $this->current_item[ $this->current_namespace ][ $el ], $text);
+ }
+ elseif ($this->inchannel) {
+ $this->concat(
+ $this->channel[ $this->current_namespace][ $el ], $text );
+ }
+ elseif ($this->intextinput) {
+ $this->concat(
+ $this->textinput[ $this->current_namespace][ $el ], $text );
+ }
+ elseif ($this->inimage) {
+ $this->concat(
+ $this->image[ $this->current_namespace ][ $el ], $text );
+ }
+ }
+ else {
+ if ( $this->initem ) {
+ $this->concat(
+ $this->current_item[ $el ], $text);
+ }
+ elseif ($this->intextinput) {
+ $this->concat(
+ $this->textinput[ $el ], $text );
+ }
+ elseif ($this->inimage) {
+ $this->concat(
+ $this->image[ $el ], $text );
+ }
+ elseif ($this->inchannel) {
+ $this->concat(
+ $this->channel[ $el ], $text );
+ }
+
+ }
+ }
+
+ function normalize () {
+ // if atom populate rss fields
+ if ( $this->is_atom() ) {
+ $this->channel['descripton'] = $this->channel['tagline'];
+ for ( $i = 0; $i < count($this->items); $i++) {
+ $item = $this->items[$i];
+ if ( isset($item['summary']) )
+ $item['description'] = $item['summary'];
+ if ( isset($item['atom_content']))
+ $item['content']['encoded'] = $item['atom_content'];
+
+ $this->items[$i] = $item;
+ }
+ }
+ elseif ( $this->is_rss() ) {
+ $this->channel['tagline'] = $this->channel['description'];
+ for ( $i = 0; $i < count($this->items); $i++) {
+ $item = $this->items[$i];
+ if ( isset($item['description']))
+ $item['summary'] = $item['description'];
+ if ( isset($item['content']['encoded'] ) )
+ $item['atom_content'] = $item['content']['encoded'];
+
+ $this->items[$i] = $item;
+ }
+ }
+ }
+
+ function is_rss () {
+ if ( $this->feed_type == RSS ) {
+ return $this->feed_version;
+ }
+ else {
+ return false;
+ }
+ }
+
+ function is_atom() {
+ if ( $this->feed_type == ATOM ) {
+ return $this->feed_version;
+ }
+ else {
+ return false;
+ }
+ }
+
+ function map_attrs($k, $v) {
+ return "$k=\"$v\"";
+ }
+
+ function error( $errormsg, $lvl = E_USER_WARNING ) {
+ // append PHP's error message if track_errors enabled
+ if ( isset($php_errormsg) ) {
+ $errormsg .= " ($php_errormsg)";
+ }
+ if ( MAGPIE_DEBUG ) {
+ trigger_error( $errormsg, $lvl);
+ } else {
+ error_log( $errormsg, 0);
+ }
+ }
+
+}
+
+if ( !function_exists('fetch_rss') ) :
+/**
+ * Build Magpie object based on RSS from URL.
+ *
+ * @since unknown
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL to retrieve feed
+ * @return bool|MagpieRSS false on failure or MagpieRSS object on success.
+ */
+function fetch_rss ($url) {
+ // initialize constants
+ init();
+
+ if ( !isset($url) ) {
+ // error("fetch_rss called without a url");
+ return false;
+ }
+
+ // if cache is disabled
+ if ( !MAGPIE_CACHE_ON ) {
+ // fetch file, and parse it
+ $resp = _fetch_remote_file( $url );
+ if ( is_success( $resp->status ) ) {
+ return _response_to_rss( $resp );
+ }
+ else {
+ // error("Failed to fetch $url and cache is off");
+ return false;
+ }
+ }
+ // else cache is ON
+ else {
+ // Flow
+ // 1. check cache
+ // 2. if there is a hit, make sure its fresh
+ // 3. if cached obj fails freshness check, fetch remote
+ // 4. if remote fails, return stale object, or error
+
+ $cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE );
+
+ if (MAGPIE_DEBUG and $cache->ERROR) {
+ debug($cache->ERROR, E_USER_WARNING);
+ }
+
+
+ $cache_status = 0; // response of check_cache
+ $request_headers = array(); // HTTP headers to send with fetch
+ $rss = 0; // parsed RSS object
+ $errormsg = 0; // errors, if any
+
+ if (!$cache->ERROR) {
+ // return cache HIT, MISS, or STALE
+ $cache_status = $cache->check_cache( $url );
+ }
+
+ // if object cached, and cache is fresh, return cached obj
+ if ( $cache_status == 'HIT' ) {
+ $rss = $cache->get( $url );
+ if ( isset($rss) and $rss ) {
+ $rss->from_cache = 1;
+ if ( MAGPIE_DEBUG > 1) {
+ debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
+ }
+ return $rss;
+ }
+ }
+
+ // else attempt a conditional get
+
+ // setup headers
+ if ( $cache_status == 'STALE' ) {
+ $rss = $cache->get( $url );
+ if ( isset($rss->etag) and $rss->last_modified ) {
+ $request_headers['If-None-Match'] = $rss->etag;
+ $request_headers['If-Last-Modified'] = $rss->last_modified;
+ }
+ }
+
+ $resp = _fetch_remote_file( $url, $request_headers );
+
+ if (isset($resp) and $resp) {
+ if ($resp->status == '304' ) {
+ // we have the most current copy
+ if ( MAGPIE_DEBUG > 1) {
+ debug("Got 304 for $url");
+ }
+ // reset cache on 304 (at minutillo insistent prodding)
+ $cache->set($url, $rss);
+ return $rss;
+ }
+ elseif ( is_success( $resp->status ) ) {
+ $rss = _response_to_rss( $resp );
+ if ( $rss ) {
+ if (MAGPIE_DEBUG > 1) {
+ debug("Fetch successful");
+ }
+ // add object to cache
+ $cache->set( $url, $rss );
+ return $rss;
+ }
+ }
+ else {
+ $errormsg = "Failed to fetch $url. ";
+ if ( $resp->error ) {
+ # compensate for Snoopy's annoying habbit to tacking
+ # on '\n'
+ $http_error = substr($resp->error, 0, -2);
+ $errormsg .= "(HTTP Error: $http_error)";
+ }
+ else {
+ $errormsg .= "(HTTP Response: " . $resp->response_code .')';
+ }
+ }
+ }
+ else {
+ $errormsg = "Unable to retrieve RSS file for unknown reasons.";
+ }
+
+ // else fetch failed
+
+ // attempt to return cached object
+ if ($rss) {
+ if ( MAGPIE_DEBUG ) {
+ debug("Returning STALE object for $url");
+ }
+ return $rss;
+ }
+
+ // else we totally failed
+ // error( $errormsg );
+
+ return false;
+
+ } // end if ( !MAGPIE_CACHE_ON ) {
+} // end fetch_rss()
+endif;
+
+/**
+ * Retrieve URL headers and content using WP HTTP Request API.
+ *
+ * @since unknown
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL to retrieve
+ * @param array $headers Optional. Headers to send to the URL.
+ * @return Snoopy style response
+ */
+function _fetch_remote_file ($url, $headers = "" ) {
+ $resp = wp_remote_request($url, array('headers' => $headers, 'timeout' => MAGPIE_FETCH_TIME_OUT));
+ if ( is_wp_error($resp) ) {
+ $error = array_shift($resp->errors);
+
+ $resp = new stdClass;
+ $resp->status = 500;
+ $resp->response_code = 500;
+ $resp->error = $error[0] . "\n"; //\n = Snoopy compatibility
+ return $resp;
+ }
+ $response = new stdClass;
+ $response->status = $resp['response']['code'];
+ $response->response_code = $resp['response']['code'];
+ $response->headers = $resp['headers'];
+ $response->results = $resp['body'];
+
+ return $response;
+}
+
+/**
+ * Retrieve
+ *
+ * @since unknown
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param unknown_type $resp
+ * @return unknown
+ */
+function _response_to_rss ($resp) {
+ $rss = new MagpieRSS( $resp->results );
+
+ // if RSS parsed successfully
+ if ( $rss && (!isset($rss->ERROR) || !$rss->ERROR) ) {
+
+ // find Etag, and Last-Modified
+ foreach( (array) $resp->headers as $h) {
+ // 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1"
+ if (strpos($h, ": ")) {
+ list($field, $val) = explode(": ", $h, 2);
+ }
+ else {
+ $field = $h;
+ $val = "";
+ }
+
+ if ( $field == 'ETag' ) {
+ $rss->etag = $val;
+ }
+
+ if ( $field == 'Last-Modified' ) {
+ $rss->last_modified = $val;
+ }
+ }
+
+ return $rss;
+ } // else construct error message
+ else {
+ $errormsg = "Failed to parse RSS file.";
+
+ if ($rss) {
+ $errormsg .= " (" . $rss->ERROR . ")";
+ }
+ // error($errormsg);
+
+ return false;
+ } // end if ($rss and !$rss->error)
+}
+
+/**
+ * Setup constants with default values, unless user overrides.
+ *
+ * @since unknown
+ * @package External
+ * @subpackage MagpieRSS
+ */
+function init () {
+ if ( defined('MAGPIE_INITALIZED') ) {
+ return;
+ }
+ else {
+ define('MAGPIE_INITALIZED', 1);
+ }
+
+ if ( !defined('MAGPIE_CACHE_ON') ) {
+ define('MAGPIE_CACHE_ON', 1);
+ }
+
+ if ( !defined('MAGPIE_CACHE_DIR') ) {
+ define('MAGPIE_CACHE_DIR', './cache');
+ }
+
+ if ( !defined('MAGPIE_CACHE_AGE') ) {
+ define('MAGPIE_CACHE_AGE', 60*60); // one hour
+ }
+
+ if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) {
+ define('MAGPIE_CACHE_FRESH_ONLY', 0);
+ }
+
+ if ( !defined('MAGPIE_DEBUG') ) {
+ define('MAGPIE_DEBUG', 0);
+ }
+
+ if ( !defined('MAGPIE_USER_AGENT') ) {
+ $ua = 'WordPress/' . $GLOBALS['wp_version'];
+
+ if ( MAGPIE_CACHE_ON ) {
+ $ua = $ua . ')';
+ }
+ else {
+ $ua = $ua . '; No cache)';
+ }
+
+ define('MAGPIE_USER_AGENT', $ua);
+ }
+
+ if ( !defined('MAGPIE_FETCH_TIME_OUT') ) {
+ define('MAGPIE_FETCH_TIME_OUT', 2); // 2 second timeout
+ }
+
+ // use gzip encoding to fetch rss files if supported?
+ if ( !defined('MAGPIE_USE_GZIP') ) {
+ define('MAGPIE_USE_GZIP', true);
+ }
+}
+
+function is_info ($sc) {
+ return $sc >= 100 && $sc < 200;
+}
+
+function is_success ($sc) {
+ return $sc >= 200 && $sc < 300;
+}
+
+function is_redirect ($sc) {
+ return $sc >= 300 && $sc < 400;
+}
+
+function is_error ($sc) {
+ return $sc >= 400 && $sc < 600;
+}
+
+function is_client_error ($sc) {
+ return $sc >= 400 && $sc < 500;
+}
+
+function is_server_error ($sc) {
+ return $sc >= 500 && $sc < 600;
+}
+
+class RSSCache {
+ var $BASE_CACHE; // where the cache files are stored
+ var $MAX_AGE = 43200; // when are files stale, default twelve hours
+ var $ERROR = ''; // accumulate error messages
+
+ function RSSCache ($base='', $age='') {
+ $this->BASE_CACHE = WP_CONTENT_DIR . '/cache';
+ if ( $base ) {
+ $this->BASE_CACHE = $base;
+ }
+ if ( $age ) {
+ $this->MAX_AGE = $age;
+ }
+
+ }
+
+/*=======================================================================*\
+ Function: set
+ Purpose: add an item to the cache, keyed on url
+ Input: url from wich the rss file was fetched
+ Output: true on sucess
+\*=======================================================================*/
+ function set ($url, $rss) {
+ global $wpdb;
+ $cache_option = 'rss_' . $this->file_name( $url );
+ $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
+
+ // shouldn't these be using get_option() ?
+ if ( !$wpdb->get_var( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name = %s", $cache_option ) ) )
+ add_option($cache_option, '', '', 'no');
+ if ( !$wpdb->get_var( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name = %s", $cache_timestamp ) ) )
+ add_option($cache_timestamp, '', '', 'no');
+
+ update_option($cache_option, $rss);
+ update_option($cache_timestamp, time() );
+
+ return $cache_option;
+ }
+
+/*=======================================================================*\
+ Function: get
+ Purpose: fetch an item from the cache
+ Input: url from wich the rss file was fetched
+ Output: cached object on HIT, false on MISS
+\*=======================================================================*/
+ function get ($url) {
+ $this->ERROR = "";
+ $cache_option = 'rss_' . $this->file_name( $url );
+
+ if ( ! get_option( $cache_option ) ) {
+ $this->debug(
+ "Cache doesn't contain: $url (cache option: $cache_option)"
+ );
+ return 0;
+ }
+
+ $rss = get_option( $cache_option );
+
+ return $rss;
+ }
+
+/*=======================================================================*\
+ Function: check_cache
+ Purpose: check a url for membership in the cache
+ and whether the object is older then MAX_AGE (ie. STALE)
+ Input: url from wich the rss file was fetched
+ Output: cached object on HIT, false on MISS
+\*=======================================================================*/
+ function check_cache ( $url ) {
+ $this->ERROR = "";
+ $cache_option = $this->file_name( $url );
+ $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
+
+ if ( $mtime = get_option($cache_timestamp) ) {
+ // find how long ago the file was added to the cache
+ // and whether that is longer then MAX_AGE
+ $age = time() - $mtime;
+ if ( $this->MAX_AGE > $age ) {
+ // object exists and is current
+ return 'HIT';
+ }
+ else {
+ // object exists but is old
+ return 'STALE';
+ }
+ }
+ else {
+ // object does not exist
+ return 'MISS';
+ }
+ }
+
+/*=======================================================================*\
+ Function: serialize
+\*=======================================================================*/
+ function serialize ( $rss ) {
+ return serialize( $rss );
+ }
+
+/*=======================================================================*\
+ Function: unserialize
+\*=======================================================================*/
+ function unserialize ( $data ) {
+ return unserialize( $data );
+ }
+
+/*=======================================================================*\
+ Function: file_name
+ Purpose: map url to location in cache
+ Input: url from wich the rss file was fetched
+ Output: a file name
+\*=======================================================================*/
+ function file_name ($url) {
+ return md5( $url );
+ }
+
+/*=======================================================================*\
+ Function: error
+ Purpose: register error
+\*=======================================================================*/
+ function error ($errormsg, $lvl=E_USER_WARNING) {
+ // append PHP's error message if track_errors enabled
+ if ( isset($php_errormsg) ) {
+ $errormsg .= " ($php_errormsg)";
+ }
+ $this->ERROR = $errormsg;
+ if ( MAGPIE_DEBUG ) {
+ trigger_error( $errormsg, $lvl);
+ }
+ else {
+ error_log( $errormsg, 0);
+ }
+ }
+ function debug ($debugmsg, $lvl=E_USER_NOTICE) {
+ if ( MAGPIE_DEBUG ) {
+ $this->error("MagpieRSS [debug] $debugmsg", $lvl);
+ }
+ }
+}
+
+if ( !function_exists('parse_w3cdtf') ) :
+function parse_w3cdtf ( $date_str ) {
+
+ # regex to match wc3dtf
+ $pat = "/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/";
+
+ if ( preg_match( $pat, $date_str, $match ) ) {
+ list( $year, $month, $day, $hours, $minutes, $seconds) =
+ array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[7]);
+
+ # calc epoch for current date assuming GMT
+ $epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
+
+ $offset = 0;
+ if ( $match[11] == 'Z' ) {
+ # zulu time, aka GMT
+ }
+ else {
+ list( $tz_mod, $tz_hour, $tz_min ) =
+ array( $match[8], $match[9], $match[10]);
+
+ # zero out the variables
+ if ( ! $tz_hour ) { $tz_hour = 0; }
+ if ( ! $tz_min ) { $tz_min = 0; }
+
+ $offset_secs = (($tz_hour*60)+$tz_min)*60;
+
+ # is timezone ahead of GMT? then subtract offset
+ #
+ if ( $tz_mod == '+' ) {
+ $offset_secs = $offset_secs * -1;
+ }
+
+ $offset = $offset_secs;
+ }
+ $epoch = $epoch + $offset;
+ return $epoch;
+ }
+ else {
+ return -1;
+ }
+}
+endif;
+
+if ( !function_exists('wp_rss') ) :
+/**
+ * Display all RSS items in a HTML ordered list.
+ *
+ * @since unknown
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL of feed to display. Will not auto sense feed URL.
+ * @param int $num_items Optional. Number of items to display, default is all.
+ */
+function wp_rss( $url, $num_items = -1 ) {
+ if ( $rss = fetch_rss( $url ) ) {
+ echo '';
+
+ if ( $num_items !== -1 ) {
+ $rss->items = array_slice( $rss->items, 0, $num_items );
+ }
+
+ foreach ( (array) $rss->items as $item ) {
+ printf(
+ '%3$s ',
+ clean_url( $item['link'] ),
+ attribute_escape( strip_tags( $item['description'] ) ),
+ htmlentities( $item['title'] )
+ );
+ }
+
+ echo ' ';
+ } else {
+ _e( 'An error has occurred, which probably means the feed is down. Try again later.' );
+ }
+}
+endif;
+
+if ( !function_exists('get_rss') ) :
+/**
+ * Display RSS items in HTML list items.
+ *
+ * You have to specify which HTML list you want, either ordered or unordered
+ * before using the function. You also have to specify how many items you wish
+ * to display. You can't display all of them like you can with wp_rss()
+ * function.
+ *
+ * @since unknown
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL of feed to display. Will not auto sense feed URL.
+ * @param int $num_items Optional. Number of items to display, default is all.
+ * @return bool False on failure.
+ */
+function get_rss ($url, $num_items = 5) { // Like get posts, but for RSS
+ $rss = fetch_rss($url);
+ if ( $rss ) {
+ $rss->items = array_slice($rss->items, 0, $num_items);
+ foreach ( (array) $rss->items as $item ) {
+ echo "\n";
+ echo "";
+ echo htmlentities($item['title']);
+ echo " \n";
+ echo " \n";
+ }
+ } else {
+ return false;
+ }
+}
+endif;
+
+?>
diff -uNr a/blog/wp-includes/script-loader.php b/blog/wp-includes/script-loader.php
--- a/blog/wp-includes/script-loader.php false
+++ b/blog/wp-includes/script-loader.php 4faca77744507d71cfd83eb76122019f64adf9fa6350a52ae15c9d7817c267769002d28ce622b2b1a8ff0aa34d7639b9d1ebed676a8958275cedc7b3ac827839
@@ -0,0 +1,447 @@
+base_url = $guessurl;
+ $scripts->default_version = get_bloginfo( 'version' );
+
+ $scripts->add( 'common', '/wp-admin/js/common.js', array('jquery', 'hoverIntent'), '20081210' );
+ $scripts->add( 'sack', '/wp-includes/js/tw-sack.js', false, '1.6.1' );
+
+ $scripts->add( 'quicktags', '/wp-includes/js/quicktags.js', false, '20081210' );
+ $scripts->localize( 'quicktags', 'quicktagsL10n', array(
+ 'quickLinks' => __('(Quick Links)'),
+ 'wordLookup' => __('Enter a word to look up:'),
+ 'dictionaryLookup' => attribute_escape(__('Dictionary lookup')),
+ 'lookup' => attribute_escape(__('lookup')),
+ 'closeAllOpenTags' => attribute_escape(__('Close all open tags')),
+ 'closeTags' => attribute_escape(__('close tags')),
+ 'enterURL' => __('Enter the URL'),
+ 'enterImageURL' => __('Enter the URL of the image'),
+ 'enterImageDescription' => __('Enter a description of the image'),
+ 'l10n_print_after' => 'try{convertEntities(quicktagsL10n);}catch(e){};'
+ ) );
+
+ $scripts->add( 'colorpicker', '/wp-includes/js/colorpicker.js', array('prototype'), '3517' );
+
+ // Modify this version when tinyMCE plugins are changed.
+ function mce_version() {
+ return '20081129';
+ }
+ add_filter( 'tiny_mce_version', 'mce_version' );
+
+ $scripts->add( 'editor', '/wp-admin/js/editor.js', false, mce_version() );
+
+ $scripts->add( 'prototype', '/wp-includes/js/prototype.js', false, '1.6');
+
+ $scripts->add( 'wp-ajax-response', '/wp-includes/js/wp-ajax-response.js', array('jquery'), '20081210' );
+ $scripts->localize( 'wp-ajax-response', 'wpAjax', array(
+ 'noPerm' => __('You do not have permission to do that.'),
+ 'broken' => __('An unidentified error has occurred.'),
+ 'l10n_print_after' => 'try{convertEntities(wpAjax);}catch(e){};'
+ ) );
+
+ $scripts->add( 'autosave', '/wp-includes/js/autosave.js', array('schedule', 'wp-ajax-response'), '20081210' );
+
+ $scripts->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('wp-ajax-response'), '20081210' );
+ $scripts->localize( 'wp-lists', 'wpListL10n', array(
+ 'url' => admin_url('admin-ajax.php')
+ ) );
+
+ $scripts->add( 'scriptaculous-root', '/wp-includes/js/scriptaculous/wp-scriptaculous.js', array('prototype'), '1.8.0');
+ $scripts->add( 'scriptaculous-builder', '/wp-includes/js/scriptaculous/builder.js', array('scriptaculous-root'), '1.8.0');
+ $scripts->add( 'scriptaculous-dragdrop', '/wp-includes/js/scriptaculous/dragdrop.js', array('scriptaculous-builder', 'scriptaculous-effects'), '1.8.0');
+ $scripts->add( 'scriptaculous-effects', '/wp-includes/js/scriptaculous/effects.js', array('scriptaculous-root'), '1.8.0');
+ $scripts->add( 'scriptaculous-slider', '/wp-includes/js/scriptaculous/slider.js', array('scriptaculous-effects'), '1.8.0');
+ $scripts->add( 'scriptaculous-sound', '/wp-includes/js/scriptaculous/sound.js', array( 'scriptaculous-root' ), '1.8.0' );
+ $scripts->add( 'scriptaculous-controls', '/wp-includes/js/scriptaculous/controls.js', array('scriptaculous-root'), '1.8.0');
+ $scripts->add( 'scriptaculous', '', array('scriptaculous-dragdrop', 'scriptaculous-slider', 'scriptaculous-controls'), '1.8.0');
+
+ $scripts->add( 'cropper', '/wp-includes/js/crop/cropper.js', array('scriptaculous-dragdrop'), '20070118');
+
+ $scripts->add( 'jquery', '/wp-includes/js/jquery/jquery.js', false, '1.2.6');
+ $scripts->add( 'jquery-form', '/wp-includes/js/jquery/jquery.form.js', array('jquery'), '2.02');
+ $scripts->add( 'jquery-color', '/wp-includes/js/jquery/jquery.color.js', array('jquery'), '2.0-4561');
+ $scripts->add( 'interface', '/wp-includes/js/jquery/interface.js', array('jquery'), '1.2' );
+ $scripts->add( 'suggest', '/wp-includes/js/jquery/suggest.js', array('jquery'), '1.1b');
+ $scripts->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array('jquery'), '20');
+ $scripts->add( 'jquery-hotkeys', '/wp-includes/js/jquery/jquery.hotkeys.js', array('jquery'), '0.0.2' );
+ $scripts->add( 'jquery-table-hotkeys', '/wp-includes/js/jquery/jquery.table-hotkeys.js', array('jquery', 'jquery-hotkeys'), '20081128' );
+ $scripts->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.js', array('jquery'), '3.1-20080430');
+ $scripts->add( 'swfupload', '/wp-includes/js/swfupload/swfupload.js', false, '2.2.0-20081031');
+ $scripts->add( 'swfupload-degrade', '/wp-includes/js/swfupload/plugins/swfupload.graceful_degradation.js', array('swfupload'), '2.2.0-20081031');
+ $scripts->add( 'swfupload-swfobject', '/wp-includes/js/swfupload/plugins/swfupload.swfobject.js', array('swfupload'), '2.2.0-20081031');
+ $scripts->localize( 'swfupload-degrade', 'uploadDegradeOptions', array(
+ 'is_lighttpd_before_150' => is_lighttpd_before_150(),
+ ) );
+ $scripts->add( 'swfupload-queue', '/wp-includes/js/swfupload/plugins/swfupload.queue.js', array('swfupload'), '2.2.0-20081031');
+ $scripts->add( 'swfupload-handlers', '/wp-includes/js/swfupload/handlers.js', array('swfupload'), '2.2.0-20081201');
+ // these error messages came from the sample swfupload js, they might need changing.
+ $scripts->localize( 'swfupload-handlers', 'swfuploadL10n', array(
+ 'queue_limit_exceeded' => __('You have attempted to queue too many files.'),
+ 'file_exceeds_size_limit' => sprintf(__('This file is too big. Your php.ini upload_max_filesize is %s.'), @ini_get('upload_max_filesize')),
+ 'zero_byte_file' => __('This file is empty. Please try another.'),
+ 'invalid_filetype' => __('This file type is not allowed. Please try another.'),
+ 'default_error' => __('An error occurred in the upload. Please try again later.'),
+ 'missing_upload_url' => __('There was a configuration error. Please contact the server administrator.'),
+ 'upload_limit_exceeded' => __('You may only upload 1 file.'),
+ 'http_error' => __('HTTP error.'),
+ 'upload_failed' => __('Upload failed.'),
+ 'io_error' => __('IO error.'),
+ 'security_error' => __('Security error.'),
+ 'file_cancelled' => __('File cancelled.'),
+ 'upload_stopped' => __('Upload stopped.'),
+ 'dismiss' => __('Dismiss'),
+ 'crunching' => __('Crunching…'),
+ 'deleted' => __('Deleted'),
+ 'l10n_print_after' => 'try{convertEntities(swfuploadL10n);}catch(e){};'
+ ) );
+
+ $scripts->add( 'jquery-ui-core', '/wp-includes/js/jquery/ui.core.js', array('jquery'), '1.5.2' );
+ $scripts->add( 'jquery-ui-tabs', '/wp-includes/js/jquery/ui.tabs.js', array('jquery-ui-core'), '1.5.2' );
+ $scripts->add( 'jquery-ui-sortable', '/wp-includes/js/jquery/ui.sortable.js', array('jquery-ui-core'), '1.5.2c' );
+ $scripts->add( 'jquery-ui-draggable', '/wp-includes/js/jquery/ui.draggable.js', array('jquery-ui-core'), '1.5.2' );
+ $scripts->add( 'jquery-ui-resizable', '/wp-includes/js/jquery/ui.resizable.js', array('jquery-ui-core'), '1.5.2' );
+ $scripts->add( 'jquery-ui-dialog', '/wp-includes/js/jquery/ui.dialog.js', array('jquery-ui-resizable', 'jquery-ui-draggable'), '1.5.2' );
+
+ $scripts->add( 'comment-reply', '/wp-includes/js/comment-reply.js', false, '20081210');
+
+ if ( is_admin() ) {
+ $scripts->add( 'ajaxcat', '/wp-admin/js/cat.js', array( 'wp-lists' ), '20081210' );
+ $scripts->localize( 'ajaxcat', 'catL10n', array(
+ 'add' => attribute_escape(__('Add')),
+ 'how' => __('Separate multiple categories with commas.'),
+ 'l10n_print_after' => 'try{convertEntities(catL10n);}catch(e){};'
+ ) );
+ $scripts->add( 'admin-categories', '/wp-admin/js/categories.js', array('wp-lists'), '20081210' );
+ $scripts->add( 'admin-tags', '/wp-admin/js/tags.js', array('wp-lists'), '20081210' );
+ $scripts->add( 'admin-custom-fields', '/wp-admin/js/custom-fields.js', array('wp-lists'), '20081210' );
+ $scripts->add( 'password-strength-meter', '/wp-admin/js/password-strength-meter.js', array('jquery'), '20081210' );
+ $scripts->localize( 'password-strength-meter', 'pwsL10n', array(
+ 'empty' => __('Strength indicator'),
+ 'short' => __('Very weak'),
+ 'bad' => __('Weak'),
+ 'good' => _c('Medium|password strength'),
+ 'strong' => __('Strong'),
+ 'l10n_print_after' => 'try{convertEntities(pwsL10n);}catch(e){};'
+ ) );
+ $scripts->add( 'admin-comments', '/wp-admin/js/edit-comments.js', array('wp-lists', 'jquery-ui-resizable', 'quicktags'), '20081210' );
+ $scripts->localize( 'admin-comments', 'adminCommentsL10n', array(
+ 'hotkeys_highlight_first' => isset($_GET['hotkeys_highlight_first']),
+ 'hotkeys_highlight_last' => isset($_GET['hotkeys_highlight_last'])
+ ) );
+ $scripts->add( 'admin-users', '/wp-admin/js/users.js', array('wp-lists'), '20081210' );
+ $scripts->add( 'xfn', '/wp-admin/js/xfn.js', false, '3517' );
+ $scripts->add( 'postbox', '/wp-admin/js/postbox.js', array('jquery-ui-sortable'), '20081210' );
+ $scripts->localize( 'postbox', 'postboxL10n', array(
+ 'requestFile' => admin_url('admin-ajax.php')
+ ) );
+ $scripts->add( 'slug', '/wp-admin/js/slug.js', array('jquery'), '20081210' );
+ $scripts->localize( 'slug', 'slugL10n', array(
+ 'requestFile' => admin_url('admin-ajax.php'),
+ 'save' => __('Save'),
+ 'cancel' => __('Cancel'),
+ 'l10n_print_after' => 'try{convertEntities(slugL10n);}catch(e){};'
+ ) );
+ $scripts->add( 'post', '/wp-admin/js/post.js', array('suggest', 'jquery-ui-tabs', 'wp-lists', 'postbox', 'slug'), '20081210' );
+ $scripts->localize( 'post', 'postL10n', array(
+ 'tagsUsed' => __('Tags used on this post:'),
+ 'add' => attribute_escape(__('Add')),
+ 'addTag' => attribute_escape(__('Add new tag')),
+ 'separate' => __('Separate tags with commas'),
+ 'cancel' => __('Cancel'),
+ 'edit' => __('Edit'),
+ 'publishOn' => __('Publish on:'),
+ 'publishOnFuture' => __('Schedule for:'),
+ 'publishOnPast' => __('Published on:'),
+ 'showcomm' => __('Show more comments'),
+ 'endcomm' => __('No more comments found.'),
+ 'publish' => __('Publish'),
+ 'schedule' => __('Schedule'),
+ 'update' => __('Update Post'),
+ 'savePending' => __('Save as Pending'),
+ 'saveDraft' => __('Save Draft'),
+ 'private' => __('Private'),
+ 'public' => __('Public'),
+ 'publicSticky' => __('Public, Sticky'),
+ 'password' => __('Password Protected'),
+ 'privatelyPublished' => __('Privately Published'),
+ 'published' => __('Published'),
+ 'l10n_print_after' => 'try{convertEntities(postL10n);}catch(e){};'
+ ) );
+ $scripts->add( 'page', '/wp-admin/js/page.js', array('jquery', 'slug', 'wp-lists', 'postbox'), '20081210' );
+ $scripts->localize( 'page', 'postL10n', array(
+ 'cancel' => __('Cancel'),
+ 'edit' => __('Edit'),
+ 'publishOn' => __('Publish on:'),
+ 'publishOnFuture' => __('Schedule for:'),
+ 'publishOnPast' => __('Published on:'),
+ 'showcomm' => __('Show more comments'),
+ 'endcomm' => __('No more comments found.'),
+ 'publish' => __('Publish'),
+ 'schedule' => __('Schedule'),
+ 'update' => __('Update Page'),
+ 'savePending' => __('Save as Pending'),
+ 'saveDraft' => __('Save Draft'),
+ 'private' => __('Private'),
+ 'public' => __('Public'),
+ 'password' => __('Password Protected'),
+ 'privatelyPublished' => __('Privately Published'),
+ 'published' => __('Published'),
+ 'l10n_print_after' => 'try{convertEntities(postL10n);}catch(e){};'
+ ) );
+ $scripts->add( 'link', '/wp-admin/js/link.js', array('jquery-ui-tabs', 'wp-lists', 'postbox'), '20081210' );
+ $scripts->add( 'comment', '/wp-admin/js/comment.js', array('jquery'), '20081210' );
+ $scripts->localize( 'comment', 'commentL10n', array(
+ 'cancel' => __('Cancel'),
+ 'edit' => __('Edit'),
+ 'submittedOn' => __('Submitted on:'),
+ 'l10n_print_after' => 'try{convertEntities(commentL10n);}catch(e){};'
+ ) );
+ $scripts->add( 'admin-gallery', '/wp-admin/js/gallery.js', array( 'jquery-ui-sortable' ), '20081210' );
+ $scripts->add( 'media-upload', '/wp-admin/js/media-upload.js', array( 'thickbox' ), '20081210' );
+
+ $scripts->add( 'admin-widgets', '/wp-admin/js/widgets.js', array( 'interface' ), '20081210' );
+ $scripts->localize( 'admin-widgets', 'widgetsL10n', array(
+ 'add' => __('Add'),
+ 'edit' => __('Edit'),
+ 'cancel' => __('Cancel'),
+ 'lameReminder' => __('Remember to click the "Save Changes" button at the bottom of the Current Widgets column after you\'re all done!'),
+ 'lamerReminder' => __("You're about to leave without having saved your changes!"),
+ 'l10n_print_after' => 'try{convertEntities(widgetsL10n);}catch(e){};'
+ ));
+
+ $scripts->add( 'word-count', '/wp-admin/js/word-count.js', array( 'jquery' ), '20081210' );
+ $scripts->localize( 'word-count', 'wordCountL10n', array(
+ 'count' => __('Word count: %d'),
+ 'l10n_print_after' => 'try{convertEntities(wordCountL10n);}catch(e){};'
+ ));
+
+ $scripts->add( 'wp-gears', '/wp-admin/js/wp-gears.js', false, '20081210' );
+ $scripts->localize( 'wp-gears', 'wpGearsL10n', array(
+ 'updateCompleted' => __('Update completed.'),
+ 'error' => __('Error:'),
+ 'l10n_print_after' => 'try{convertEntities(wpGearsL10n);}catch(e){};'
+ ));
+
+ $scripts->add( 'theme-preview', '/wp-admin/js/theme-preview.js', array( 'thickbox', 'jquery' ), '20081210' );
+
+ $scripts->add( 'inline-edit-post', '/wp-admin/js/inline-edit-post.js', array( 'jquery', 'jquery-form', 'suggest' ), '20081210' );
+ $scripts->localize( 'inline-edit-post', 'inlineEditL10n', array(
+ 'error' => __('Error while saving the changes.'),
+ 'ntdeltitle' => __('Remove From Bulk Edit'),
+ 'notitle' => __('(no title)'),
+ 'l10n_print_after' => 'try{convertEntities(inlineEditL10n);}catch(e){};'
+ ) );
+
+ $scripts->add( 'inline-edit-tax', '/wp-admin/js/inline-edit-tax.js', array( 'jquery', 'jquery-form' ), '20081210' );
+ $scripts->localize( 'inline-edit-tax', 'inlineEditL10n', array(
+ 'error' => __('Error while saving the changes.'),
+ 'l10n_print_after' => 'try{convertEntities(inlineEditL10n);}catch(e){};'
+ ) );
+
+ $scripts->add( 'plugin-install', '/wp-admin/js/plugin-install.js', array( 'thickbox', 'jquery' ), '20081210' );
+ $scripts->localize( 'plugin-install', 'plugininstallL10n', array(
+ 'plugin_information' => __('Plugin Information:'),
+ 'l10n_print_after' => 'try{convertEntities(plugininstallL10n);}catch(e){};'
+ ) );
+
+ $scripts->add( 'farbtastic', '/wp-admin/js/farbtastic.js', array('jquery'), '1.2' );
+
+ $scripts->add( 'dashboard', '/wp-admin/js/dashboard.js', array( 'jquery', 'admin-comments', 'postbox' ), '20081210' );
+
+ $scripts->add( 'hoverIntent', '/wp-includes/js/hoverIntent.js', array('jquery'), '20081210' );
+
+ }
+}
+
+/**
+ * Assign default styles to $styles object.
+ *
+ * Nothing is returned, because the $styles parameter is passed by reference.
+ * Meaning that whatever object is passed will be updated without having to
+ * reassign the variable that was passed back to the same value. This saves
+ * memory.
+ *
+ * Adding default styles is not the only task, it also assigns the base_url
+ * property, the default version, and text direction for the object.
+ *
+ * @since 2.6.0
+ *
+ * @param object $styles
+ */
+function wp_default_styles( &$styles ) {
+ // This checks to see if site_url() returns something and if it does not
+ // then it assigns $guess_url to wp_guess_url(). Strange format, but it works.
+ if ( ! $guessurl = site_url() )
+ $guessurl = wp_guess_url();
+ $styles->base_url = $guessurl;
+ $styles->default_version = get_bloginfo( 'version' );
+ $styles->text_direction = 'rtl' == get_bloginfo( 'text_direction' ) ? 'rtl' : 'ltr';
+
+ $rtl_styles = array( 'global', 'colors', 'dashboard', 'ie', 'install', 'login', 'media', 'theme-editor', 'upload', 'widgets', 'press-this', 'plugin-install', 'farbtastic' );
+
+ $styles->add( 'wp-admin', '/wp-admin/wp-admin.css', array(), '20081210' );
+ $styles->add_data( 'wp-admin', 'rtl', '/wp-admin/rtl.css' );
+
+ $styles->add( 'ie', '/wp-admin/css/ie.css', array(), '20081210' );
+ $styles->add_data( 'ie', 'conditional', 'gte IE 6' );
+
+ $styles->add( 'colors', true, array(), '20081210' ); // Register "meta" stylesheet for admin colors
+ $styles->add( 'colors-fresh', '/wp-admin/css/colors-fresh.css', array(), '20081210'); // for login.php. Is there a better way?
+ $styles->add_data( 'colors-fresh', 'rtl', true );
+ $styles->add( 'colors-classic', '/wp-admin/css/colors-classic.css', array(), '20081210');
+ $styles->add_data( 'colors-classic', 'rtl', true );
+
+ $styles->add( 'global', '/wp-admin/css/global.css', array(), '20081210' );
+ $styles->add( 'media', '/wp-admin/css/media.css', array(), '20081210' );
+ $styles->add( 'widgets', '/wp-admin/css/widgets.css', array(), '20081210' );
+ $styles->add( 'dashboard', '/wp-admin/css/dashboard.css', array(), '20081210' );
+ $styles->add( 'install', '/wp-admin/css/install.css', array(), '20081210' );
+ $styles->add( 'theme-editor', '/wp-admin/css/theme-editor.css', array(), '20081210' );
+ $styles->add( 'press-this', '/wp-admin/css/press-this.css', array(), '20081210' );
+ $styles->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.css', array(), '20081210' );
+ $styles->add( 'login', '/wp-admin/css/login.css', array(), '20081210' );
+ $styles->add( 'plugin-install', '/wp-admin/css/plugin-install.css', array(), '20081210' );
+ $styles->add( 'farbtastic', '/wp-admin/css/farbtastic.css', array(), '1.2' );
+
+ foreach ( $rtl_styles as $rtl_style )
+ $styles->add_data( $rtl_style, 'rtl', true );
+}
+
+/**
+ * Reorder JavaScript scripts array to place prototype before jQuery.
+ *
+ * @since 2.3.1
+ *
+ * @param array $js_array JavaScript scripst array
+ * @return array Reordered array, if needed.
+ */
+function wp_prototype_before_jquery( $js_array ) {
+ if ( false === $jquery = array_search( 'jquery', $js_array ) )
+ return $js_array;
+
+ if ( false === $prototype = array_search( 'prototype', $js_array ) )
+ return $js_array;
+
+ if ( $prototype < $jquery )
+ return $js_array;
+
+ unset($js_array[$prototype]);
+
+ array_splice( $js_array, $jquery, 0, 'prototype' );
+
+ return $js_array;
+}
+
+/**
+ * Load localized script just in time for MCE.
+ *
+ * These localizations require information that may not be loaded even by init.
+ *
+ * @since 2.5.0
+ */
+function wp_just_in_time_script_localization() {
+ global $current_user;
+
+ wp_localize_script( 'autosave', 'autosaveL10n', array(
+ 'autosaveInterval' => AUTOSAVE_INTERVAL,
+ 'previewPageText' => __('Preview this Page'),
+ 'previewPostText' => __('Preview this Post'),
+ 'requestFile' => admin_url('admin-ajax.php'),
+ 'savingText' => __('Saving Draft…'),
+ 'l10n_print_after' => 'try{convertEntities(autosaveL10n);}catch(e){};'
+ ) );
+
+ $userid = isset($current_user) ? $current_user->ID : 0;
+ wp_localize_script( 'common', 'userSettings', array(
+ 'url' => SITECOOKIEPATH,
+ 'uid' => $userid,
+ 'time' => time()
+ ) );
+}
+
+/**
+ * Administration Panel CSS for changing the styles.
+ *
+ * If installing the 'wp-admin/' directory will be replaced with './'.
+ *
+ * The $_wp_admin_css_colors global manages the Administration Panels CSS
+ * stylesheet that is loaded. The option that is set is 'admin_color' and is the
+ * color and key for the array. The value for the color key is an object with
+ * a 'url' parameter that has the URL path to the CSS file.
+ *
+ * The query from $src parameter will be appended to the URL that is given from
+ * the $_wp_admin_css_colors array value URL.
+ *
+ * @since 2.6.0
+ * @uses $_wp_admin_css_colors
+ *
+ * @param string $src Source URL.
+ * @param string $handle Either 'colors' or 'colors-rtl'.
+ * @return string URL path to CSS stylesheet for Administration Panels.
+ */
+function wp_style_loader_src( $src, $handle ) {
+ if ( defined('WP_INSTALLING') )
+ return preg_replace( '#^wp-admin/#', './', $src );
+
+ if ( 'colors' == $handle || 'colors-rtl' == $handle ) {
+ global $_wp_admin_css_colors;
+ $color = get_user_option('admin_color');
+ if ( empty($color) || !isset($_wp_admin_css_colors[$color]) )
+ $color = 'fresh';
+ $color = $_wp_admin_css_colors[$color];
+ $parsed = parse_url( $src );
+ $url = $color->url;
+ if ( isset($parsed['query']) && $parsed['query'] ) {
+ wp_parse_str( $parsed['query'], $qv );
+ $url = add_query_arg( $qv, $url );
+ }
+ return $url;
+ }
+
+ return $src;
+}
+
+add_action( 'wp_default_scripts', 'wp_default_scripts' );
+add_filter( 'wp_print_scripts', 'wp_just_in_time_script_localization' );
+add_filter( 'print_scripts_array', 'wp_prototype_before_jquery' );
+
+add_action( 'wp_default_styles', 'wp_default_styles' );
+add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );
diff -uNr a/blog/wp-includes/shortcodes.php b/blog/wp-includes/shortcodes.php
--- a/blog/wp-includes/shortcodes.php false
+++ b/blog/wp-includes/shortcodes.php 6e196e8707fb785d9c6ccaf944eb7d4defd4fa9e340d28521bad5338cc31fcf36d40b5c857c69878783d9b18a4043fe28b3bed398909e6978eef24a6ea43e59a
@@ -0,0 +1,283 @@
+
+ * $out = do_shortcode($content);
+ *
+ *
+ * @link http://codex.wordpress.org/Shortcode_API
+ *
+ * @package WordPress
+ * @subpackage Shortcodes
+ * @since 2.5
+ */
+
+/**
+ * Container for storing shortcode tags and their hook to call for the shortcode
+ *
+ * @since 2.5
+ * @name $shortcode_tags
+ * @var array
+ * @global array $shortcode_tags
+ */
+$shortcode_tags = array();
+
+/**
+ * Add hook for shortcode tag.
+ *
+ * There can only be one hook for each shortcode. Which means that if another
+ * plugin has a similar shortcode, it will override yours or yours will override
+ * theirs depending on which order the plugins are included and/or ran.
+ *
+ * Simplest example of a shortcode tag using the API:
+ *
+ *
+ * // [footag foo="bar"]
+ * function footag_func($atts) {
+ * return "foo = {$atts[foo]}";
+ * }
+ * add_shortcode('footag', 'footag_func');
+ *
+ *
+ * Example with nice attribute defaults:
+ *
+ *
+ * // [bartag foo="bar"]
+ * function bartag_func($atts) {
+ * extract(shortcode_atts(array(
+ * 'foo' => 'no foo',
+ * 'baz' => 'default baz',
+ * ), $atts));
+ *
+ * return "foo = {$foo}";
+ * }
+ * add_shortcode('bartag', 'bartag_func');
+ *
+ *
+ * Example with enclosed content:
+ *
+ *
+ * // [baztag]content[/baztag]
+ * function baztag_func($atts, $content='') {
+ * return "content = $content";
+ * }
+ * add_shortcode('baztag', 'baztag_func');
+ *
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @param string $tag Shortcode tag to be searched in post content.
+ * @param callable $func Hook to run when shortcode is found.
+ */
+function add_shortcode($tag, $func) {
+ global $shortcode_tags;
+
+ if ( is_callable($func) )
+ $shortcode_tags[$tag] = $func;
+}
+
+/**
+ * Removes hook for shortcode.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @param string $tag shortcode tag to remove hook for.
+ */
+function remove_shortcode($tag) {
+ global $shortcode_tags;
+
+ unset($shortcode_tags[$tag]);
+}
+
+/**
+ * Clear all shortcodes.
+ *
+ * This function is simple, it clears all of the shortcode tags by replacing the
+ * shortcodes global by a empty array. This is actually a very efficient method
+ * for removing all shortcodes.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ */
+function remove_all_shortcodes() {
+ global $shortcode_tags;
+
+ $shortcode_tags = array();
+}
+
+/**
+ * Search content for shortcodes and filter shortcodes through their hooks.
+ *
+ * If there are no shortcode tags defined, then the content will be returned
+ * without any filtering. This might cause issues when plugins are disabled but
+ * the shortcode will still show up in the post or content.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ * @uses get_shortcode_regex() Gets the search pattern for searching shortcodes.
+ *
+ * @param string $content Content to search for shortcodes
+ * @return string Content with shortcodes filtered out.
+ */
+function do_shortcode($content) {
+ global $shortcode_tags;
+
+ if (empty($shortcode_tags) || !is_array($shortcode_tags))
+ return $content;
+
+ $pattern = get_shortcode_regex();
+ return preg_replace_callback('/'.$pattern.'/s', 'do_shortcode_tag', $content);
+}
+
+/**
+ * Retrieve the shortcode regular expression for searching.
+ *
+ * The regular expression combines the shortcode tags in the regular expression
+ * in a regex class.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @return string The shortcode search regular expression
+ */
+function get_shortcode_regex() {
+ global $shortcode_tags;
+ $tagnames = array_keys($shortcode_tags);
+ $tagregexp = join( '|', array_map('preg_quote', $tagnames) );
+
+ return '\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\1\])?';
+}
+
+/**
+ * Regular Expression callable for do_shortcode() for calling shortcode hook.
+ *
+ * @since 2.5
+ * @access private
+ * @uses $shortcode_tags
+ *
+ * @param array $m Regular expression match array
+ * @return mixed False on failure.
+ */
+function do_shortcode_tag($m) {
+ global $shortcode_tags;
+
+ $tag = $m[1];
+ $attr = shortcode_parse_atts($m[2]);
+
+ if ( isset($m[4]) ) {
+ // enclosing tag - extra parameter
+ return call_user_func($shortcode_tags[$tag], $attr, $m[4], $tag);
+ } else {
+ // self-closing tag
+ return call_user_func($shortcode_tags[$tag], $attr, NULL, $tag);
+ }
+}
+
+/**
+ * Retrieve all attributes from the shortcodes tag.
+ *
+ * The attributes list has the attribute name as the key and the value of the
+ * attribute as the value in the key/value pair. This allows for easier
+ * retrieval of the attributes, since all attributes have to be known.
+ *
+ * @since 2.5
+ *
+ * @param string $text
+ * @return array List of attributes and their value.
+ */
+function shortcode_parse_atts($text) {
+ $atts = array();
+ $pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
+ $text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text);
+ if ( preg_match_all($pattern, $text, $match, PREG_SET_ORDER) ) {
+ foreach ($match as $m) {
+ if (!empty($m[1]))
+ $atts[strtolower($m[1])] = stripcslashes($m[2]);
+ elseif (!empty($m[3]))
+ $atts[strtolower($m[3])] = stripcslashes($m[4]);
+ elseif (!empty($m[5]))
+ $atts[strtolower($m[5])] = stripcslashes($m[6]);
+ elseif (isset($m[7]) and strlen($m[7]))
+ $atts[] = stripcslashes($m[7]);
+ elseif (isset($m[8]))
+ $atts[] = stripcslashes($m[8]);
+ }
+ } else {
+ $atts = ltrim($text);
+ }
+ return $atts;
+}
+
+/**
+ * Combine user attributes with known attributes and fill in defaults when needed.
+ *
+ * The pairs should be considered to be all of the attributes which are
+ * supported by the caller and given as a list. The returned attributes will
+ * only contain the attributes in the $pairs list.
+ *
+ * If the $atts list has unsupported attributes, then they will be ignored and
+ * removed from the final returned list.
+ *
+ * @since 2.5
+ *
+ * @param array $pairs Entire list of supported attributes and their defaults.
+ * @param array $atts User defined attributes in shortcode tag.
+ * @return array Combined and filtered attribute list.
+ */
+function shortcode_atts($pairs, $atts) {
+ $atts = (array)$atts;
+ $out = array();
+ foreach($pairs as $name => $default) {
+ if ( array_key_exists($name, $atts) )
+ $out[$name] = $atts[$name];
+ else
+ $out[$name] = $default;
+ }
+ return $out;
+}
+
+/**
+ * Remove all shortcode tags from the given content.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @param string $content Content to remove shortcode tags.
+ * @return string Content without shortcode tags.
+ */
+function strip_shortcodes( $content ) {
+ global $shortcode_tags;
+
+ if (empty($shortcode_tags) || !is_array($shortcode_tags))
+ return $content;
+
+ $pattern = get_shortcode_regex();
+
+ return preg_replace('/'.$pattern.'/s', '', $content);
+}
+
+add_filter('the_content', 'do_shortcode', 11); // AFTER wpautop()
+
+?>
\ No newline at end of file
diff -uNr a/blog/wp-includes/streams.php b/blog/wp-includes/streams.php
--- a/blog/wp-includes/streams.php false
+++ b/blog/wp-includes/streams.php 122c76f75df2c716be544bb16e0ab49955cd5c39c0304557f0e62362201022ebac5af6a351b48c86892917802d644c49d314296544ccb5e040b94e3cade73d15
@@ -0,0 +1,191 @@
+.
+
+ This file is part of PHP-gettext.
+
+ PHP-gettext is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ PHP-gettext is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with PHP-gettext; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+
+// Simple class to wrap file streams, string streams, etc.
+// seek is essential, and it should be byte stream
+class StreamReader {
+ // should return a string [FIXME: perhaps return array of bytes?]
+ function read($bytes) {
+ return false;
+ }
+
+ // should return new position
+ function seekto($position) {
+ return false;
+ }
+
+ // returns current position
+ function currentpos() {
+ return false;
+ }
+
+ // returns length of entire stream (limit for seekto()s)
+ function length() {
+ return false;
+ }
+}
+
+class StringReader {
+ var $_pos;
+ var $_str;
+
+ function StringReader($str='') {
+ $this->_str = $str;
+ $this->_pos = 0;
+ // If string functions are overloaded, we need to use the mb versions
+ $this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
+ }
+
+ function _substr($string, $start, $length) {
+ if ($this->is_overloaded) {
+ return mb_substr($string,$start,$length,'ascii');
+ } else {
+ return substr($string,$start,$length);
+ }
+ }
+
+ function _strlen($string) {
+ if ($this->is_overloaded) {
+ return mb_strlen($string,'ascii');
+ } else {
+ return strlen($string);
+ }
+ }
+
+ function read($bytes) {
+ $data = $this->_substr($this->_str, $this->_pos, $bytes);
+ $this->_pos += $bytes;
+ if ($this->_strlen($this->_str)<$this->_pos)
+ $this->_pos = $this->_strlen($this->_str);
+
+ return $data;
+ }
+
+ function seekto($pos) {
+ $this->_pos = $pos;
+ if ($this->_strlen($this->_str)<$this->_pos)
+ $this->_pos = $this->_strlen($this->_str);
+ return $this->_pos;
+ }
+
+ function currentpos() {
+ return $this->_pos;
+ }
+
+ function length() {
+ return $this->_strlen($this->_str);
+ }
+}
+
+
+class FileReader {
+ var $_pos;
+ var $_fd;
+ var $_length;
+
+ function FileReader($filename) {
+ if (file_exists($filename)) {
+
+ $this->_length=filesize($filename);
+ $this->_pos = 0;
+ $this->_fd = fopen($filename,'rb');
+ if (!$this->_fd) {
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
+ }
+ } else {
+ $this->error = 2; // File doesn't exist
+ return false;
+ }
+ }
+
+ function read($bytes) {
+ if ($bytes) {
+ fseek($this->_fd, $this->_pos);
+
+ // PHP 5.1.1 does not read more than 8192 bytes in one fread()
+ // the discussions at PHP Bugs suggest it's the intended behaviour
+ while ($bytes > 0) {
+ $chunk = fread($this->_fd, $bytes);
+ $data .= $chunk;
+ $bytes -= strlen($chunk);
+ }
+ $this->_pos = ftell($this->_fd);
+
+ return $data;
+ } else return '';
+ }
+
+ function seekto($pos) {
+ fseek($this->_fd, $pos);
+ $this->_pos = ftell($this->_fd);
+ return $this->_pos;
+ }
+
+ function currentpos() {
+ return $this->_pos;
+ }
+
+ function length() {
+ return $this->_length;
+ }
+
+ function close() {
+ fclose($this->_fd);
+ }
+
+}
+
+// Preloads entire file in memory first, then creates a StringReader
+// over it (it assumes knowledge of StringReader internals)
+class CachedFileReader extends StringReader {
+ function CachedFileReader($filename) {
+ parent::StringReader();
+
+ if (file_exists($filename)) {
+
+ $length=filesize($filename);
+ $fd = fopen($filename,'rb');
+
+ if (!$fd) {
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
+ }
+ $this->_str = fread($fd, $length);
+ fclose($fd);
+
+ } else {
+ $this->error = 2; // File doesn't exist
+ return false;
+ }
+ }
+}
+
+
+?>
diff -uNr a/blog/wp-includes/taxonomy.php b/blog/wp-includes/taxonomy.php
--- a/blog/wp-includes/taxonomy.php false
+++ b/blog/wp-includes/taxonomy.php 2cb861cf724840cfec8050cf45f7a2a8936a66796a70d05b43fad08cf565390c7f25f8e2a3a97dab37abe1c5306608a968ac4d769748d170c241c132b3092c6d
@@ -0,0 +1,2277 @@
+ 'category', 'object_type' => 'post', 'hierarchical' => true, 'update_count_callback' => '_update_post_term_count');
+$wp_taxonomies['post_tag'] = (object) array('name' => 'post_tag', 'object_type' => 'post', 'hierarchical' => false, 'update_count_callback' => '_update_post_term_count');
+$wp_taxonomies['link_category'] = (object) array('name' => 'link_category', 'object_type' => 'link', 'hierarchical' => false);
+
+/**
+ * Return all of the taxonomy names that are of $object_type.
+ *
+ * It appears that this function can be used to find all of the names inside of
+ * $wp_taxonomies global variable.
+ *
+ *
Should
+ * result in Array('category', 'post_tag')
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wp_taxonomies
+ *
+ * @param array|string|object $object Name of the type of taxonomy object, or an object (row from posts)
+ * @return array The names of all taxonomy of $object_type.
+ */
+function get_object_taxonomies($object) {
+ global $wp_taxonomies;
+
+ if ( is_object($object) ) {
+ if ( $object->post_type == 'attachment' )
+ return get_attachment_taxonomies($object);
+ $object = $object->post_type;
+ }
+
+ $object = (array) $object;
+
+ $taxonomies = array();
+ foreach ( (array) $wp_taxonomies as $taxonomy ) {
+ if ( array_intersect($object, (array) $taxonomy->object_type) )
+ $taxonomies[] = $taxonomy->name;
+ }
+
+ return $taxonomies;
+}
+
+/**
+ * Retrieves the taxonomy object of $taxonomy.
+ *
+ * The get_taxonomy function will first check that the parameter string given
+ * is a taxonomy object and if it is, it will return it.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wp_taxonomies
+ * @uses is_taxonomy() Checks whether taxonomy exists
+ *
+ * @param string $taxonomy Name of taxonomy object to return
+ * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
+ */
+function get_taxonomy( $taxonomy ) {
+ global $wp_taxonomies;
+
+ if ( ! is_taxonomy($taxonomy) )
+ return false;
+
+ return $wp_taxonomies[$taxonomy];
+}
+
+/**
+ * Checks that the taxonomy name exists.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wp_taxonomies
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @return bool Whether the taxonomy exists or not.
+ */
+function is_taxonomy( $taxonomy ) {
+ global $wp_taxonomies;
+
+ return isset($wp_taxonomies[$taxonomy]);
+}
+
+/**
+ * Whether the taxonomy object is hierarchical.
+ *
+ * Checks to make sure that the taxonomy is an object first. Then Gets the
+ * object, and finally returns the hierarchical value in the object.
+ *
+ * A false return value might also mean that the taxonomy does not exist.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses is_taxonomy() Checks whether taxonomy exists
+ * @uses get_taxonomy() Used to get the taxonomy object
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @return bool Whether the taxonomy is hierarchical
+ */
+function is_taxonomy_hierarchical($taxonomy) {
+ if ( ! is_taxonomy($taxonomy) )
+ return false;
+
+ $taxonomy = get_taxonomy($taxonomy);
+ return $taxonomy->hierarchical;
+}
+
+/**
+ * Create or modify a taxonomy object. Do not use before init.
+ *
+ * A simple function for creating or modifying a taxonomy object based on the
+ * parameters given. The function will accept an array (third optional
+ * parameter), along with strings for the taxonomy name and another string for
+ * the object type.
+ *
+ * Nothing is returned, so expect error maybe or use is_taxonomy() to check
+ * whether taxonomy exists.
+ *
+ * Optional $args contents:
+ *
+ * hierarachical - has some defined purpose at other parts of the API and is a
+ * boolean value.
+ *
+ * update_count_callback - works much like a hook, in that it will be called
+ * when the count is updated.
+ *
+ * rewrite - false to prevent rewrite, or array('slug'=>$slug) to customize
+ * permastruct; default will use $taxonomy as slug.
+ *
+ * query_var - false to prevent queries, or string to customize query var
+ * (?$query_var=$term); default will use $taxonomy as query var.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wp_taxonomies Inserts new taxonomy object into the list
+ * @uses $wp_rewrite Adds rewrite tags and permastructs
+ * @uses $wp Adds query vars
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @param array|string $object_type Name of the object type for the taxonomy object.
+ * @param array|string $args See above description for the two keys values.
+ */
+function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
+ global $wp_taxonomies, $wp_rewrite, $wp;
+
+ $defaults = array('hierarchical' => false, 'update_count_callback' => '', 'rewrite' => true, 'query_var' => true);
+ $args = wp_parse_args($args, $defaults);
+
+ if ( false !== $args['query_var'] && !empty($wp) ) {
+ if ( true === $args['query_var'] )
+ $args['query_var'] = $taxonomy;
+ $args['query_var'] = sanitize_title_with_dashes($args['query_var']);
+ $wp->add_query_var($args['query_var']);
+ }
+
+ if ( false !== $args['rewrite'] && !empty($wp_rewrite) ) {
+ if ( !is_array($args['rewrite']) )
+ $args['rewrite'] = array();
+ if ( !isset($args['rewrite']['slug']) )
+ $args['rewrite']['slug'] = sanitize_title_with_dashes($taxonomy);
+ $wp_rewrite->add_rewrite_tag("%$taxonomy%", '([^/]+)', $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=$term");
+ $wp_rewrite->add_permastruct($taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%");
+ }
+
+ $args['name'] = $taxonomy;
+ $args['object_type'] = $object_type;
+ $wp_taxonomies[$taxonomy] = (object) $args;
+}
+
+//
+// Term API
+//
+
+/**
+ * Retrieve object_ids of valid taxonomy and term.
+ *
+ * The strings of $taxonomies must exist before this function will continue. On
+ * failure of finding a valid taxonomy, it will return an WP_Error class, kind
+ * of like Exceptions in PHP 5, except you can't catch them. Even so, you can
+ * still test for the WP_Error class and get the error message.
+ *
+ * The $terms aren't checked the same as $taxonomies, but still need to exist
+ * for $object_ids to be returned.
+ *
+ * It is possible to change the order that object_ids is returned by either
+ * using PHP sort family functions or using the database by using $args with
+ * either ASC or DESC array. The value should be in the key named 'order'.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses wp_parse_args() Creates an array from string $args.
+ *
+ * @param string|array $terms String of term or array of string values of terms that will be used
+ * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
+ * @param array|string $args Change the order of the object_ids, either ASC or DESC
+ * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
+ * the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
+ */
+function get_objects_in_term( $terms, $taxonomies, $args = array() ) {
+ global $wpdb;
+
+ if ( !is_array( $terms) )
+ $terms = array($terms);
+
+ if ( !is_array($taxonomies) )
+ $taxonomies = array($taxonomies);
+
+ foreach ( (array) $taxonomies as $taxonomy ) {
+ if ( ! is_taxonomy($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
+ }
+
+ $defaults = array('order' => 'ASC');
+ $args = wp_parse_args( $args, $defaults );
+ extract($args, EXTR_SKIP);
+
+ $order = ( 'desc' == strtolower($order) ) ? 'DESC' : 'ASC';
+
+ $terms = array_map('intval', $terms);
+
+ $taxonomies = "'" . implode("', '", $taxonomies) . "'";
+ $terms = "'" . implode("', '", $terms) . "'";
+
+ $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($terms) ORDER BY tr.object_id $order");
+
+ if ( ! $object_ids )
+ return array();
+
+ return $object_ids;
+}
+
+/**
+ * Get all Term data from database by Term ID.
+ *
+ * The usage of the get_term function is to apply filters to a term object. It
+ * is possible to get a term object from the database before applying the
+ * filters.
+ *
+ * $term ID must be part of $taxonomy, to get from the database. Failure, might
+ * be able to be captured by the hooks. Failure would be the same value as $wpdb
+ * returns for the get_row method.
+ *
+ * There are two hooks, one is specifically for each term, named 'get_term', and
+ * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the
+ * term object, and the taxonomy name as parameters. Both hooks are expected to
+ * return a Term object.
+ *
+ * 'get_term' hook - Takes two parameters the term Object and the taxonomy name.
+ * Must return term object. Used in get_term() as a catch-all filter for every
+ * $term.
+ *
+ * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
+ * name. Must return term object. $taxonomy will be the taxonomy name, so for
+ * example, if 'category', it would be 'get_category' as the filter name. Useful
+ * for custom taxonomies or plugging into default taxonomies.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses sanitize_term() Cleanses the term based on $filter context before returning.
+ * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
+ *
+ * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
+ * @param string $taxonomy Taxonomy name that $term is part of.
+ * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
+ * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
+ * exist then WP_Error will be returned.
+ */
+function &get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
+ global $wpdb;
+
+ if ( empty($term) ) {
+ $error = new WP_Error('invalid_term', __('Empty Term'));
+ return $error;
+ }
+
+ if ( ! is_taxonomy($taxonomy) ) {
+ $error = new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
+ return $error;
+ }
+
+ if ( is_object($term) && empty($term->filter) ) {
+ wp_cache_add($term->term_id, $term, $taxonomy);
+ $_term = $term;
+ } else {
+ if ( is_object($term) )
+ $term = $term->term_id;
+ $term = (int) $term;
+ if ( ! $_term = wp_cache_get($term, $taxonomy) ) {
+ $_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %s LIMIT 1", $taxonomy, $term) );
+ wp_cache_add($term, $_term, $taxonomy);
+ }
+ }
+
+ $_term = apply_filters('get_term', $_term, $taxonomy);
+ $_term = apply_filters("get_$taxonomy", $_term, $taxonomy);
+ $_term = sanitize_term($_term, $taxonomy, $filter);
+
+ if ( $output == OBJECT ) {
+ return $_term;
+ } elseif ( $output == ARRAY_A ) {
+ $__term = get_object_vars($_term);
+ return $__term;
+ } elseif ( $output == ARRAY_N ) {
+ $__term = array_values(get_object_vars($_term));
+ return $__term;
+ } else {
+ return $_term;
+ }
+}
+
+/**
+ * Get all Term data from database by Term field and data.
+ *
+ * Warning: $value is not escaped for 'name' $field. You must do it yourself, if
+ * required.
+ *
+ * The default $field is 'id', therefore it is possible to also use null for
+ * field, but not recommended that you do so.
+ *
+ * If $value does not exist, the return value will be false. If $taxonomy exists
+ * and $field and $value combinations exist, the Term will be returned.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses sanitize_term() Cleanses the term based on $filter context before returning.
+ * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
+ *
+ * @param string $field Either 'slug', 'name', or 'id'
+ * @param string|int $value Search for this term value
+ * @param string $taxonomy Taxonomy Name
+ * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
+ * @return mixed Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
+ */
+function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
+ global $wpdb;
+
+ if ( ! is_taxonomy($taxonomy) )
+ return false;
+
+ if ( 'slug' == $field ) {
+ $field = 't.slug';
+ $value = sanitize_title($value);
+ if ( empty($value) )
+ return false;
+ } else if ( 'name' == $field ) {
+ // Assume already escaped
+ $value = stripslashes($value);
+ $field = 't.name';
+ } else {
+ $field = 't.term_id';
+ $value = (int) $value;
+ }
+
+ $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
+ if ( !$term )
+ return false;
+
+ wp_cache_add($term->term_id, $term, $taxonomy);
+
+ $term = sanitize_term($term, $taxonomy, $filter);
+
+ if ( $output == OBJECT ) {
+ return $term;
+ } elseif ( $output == ARRAY_A ) {
+ return get_object_vars($term);
+ } elseif ( $output == ARRAY_N ) {
+ return array_values(get_object_vars($term));
+ } else {
+ return $term;
+ }
+}
+
+/**
+ * Merge all term children into a single array.
+ *
+ * This recursive function will merge all of the children of $term into the same
+ * array. Only useful for taxonomies which are hierarchical.
+ *
+ * Will return an empty array if $term does not exist in $taxonomy.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses _get_term_hierarchy()
+ * @uses get_term_children() Used to get the children of both $taxonomy and the parent $term
+ *
+ * @param string $term Name of Term to get children
+ * @param string $taxonomy Taxonomy Name
+ * @return array|WP_Error List of Term Objects. WP_Error returned if $taxonomy does not exist
+ */
+function get_term_children( $term, $taxonomy ) {
+ if ( ! is_taxonomy($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
+
+ $terms = _get_term_hierarchy($taxonomy);
+
+ if ( ! isset($terms[$term]) )
+ return array();
+
+ $children = $terms[$term];
+
+ foreach ( (array) $terms[$term] as $child ) {
+ if ( isset($terms[$child]) )
+ $children = array_merge($children, get_term_children($child, $taxonomy));
+ }
+
+ return $children;
+}
+
+/**
+ * Get sanitized Term field.
+ *
+ * Does checks for $term, based on the $taxonomy. The function is for contextual
+ * reasons and for simplicity of usage. See sanitize_term_field() for more
+ * information.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses sanitize_term_field() Passes the return value in sanitize_term_field on success.
+ *
+ * @param string $field Term field to fetch
+ * @param int $term Term ID
+ * @param string $taxonomy Taxonomy Name
+ * @param string $context Optional, default is display. Look at sanitize_term_field() for available options.
+ * @return mixed Will return an empty string if $term is not an object or if $field is not set in $term.
+ */
+function get_term_field( $field, $term, $taxonomy, $context = 'display' ) {
+ $term = (int) $term;
+ $term = get_term( $term, $taxonomy );
+ if ( is_wp_error($term) )
+ return $term;
+
+ if ( !is_object($term) )
+ return '';
+
+ if ( !isset($term->$field) )
+ return '';
+
+ return sanitize_term_field($field, $term->$field, $term->term_id, $taxonomy, $context);
+}
+
+/**
+ * Sanitizes Term for editing.
+ *
+ * Return value is sanitize_term() and usage is for sanitizing the term for
+ * editing. Function is for contextual and simplicity.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses sanitize_term() Passes the return value on success
+ *
+ * @param int|object $id Term ID or Object
+ * @param string $taxonomy Taxonomy Name
+ * @return mixed|null|WP_Error Will return empty string if $term is not an object.
+ */
+function get_term_to_edit( $id, $taxonomy ) {
+ $term = get_term( $id, $taxonomy );
+
+ if ( is_wp_error($term) )
+ return $term;
+
+ if ( !is_object($term) )
+ return '';
+
+ return sanitize_term($term, $taxonomy, 'edit');
+}
+
+/**
+ * Retrieve the terms in a given taxonomy or list of taxonomies.
+ *
+ * You can fully inject any customizations to the query before it is sent, as
+ * well as control the output with a filter.
+ *
+ * The 'get_terms' filter will be called when the cache has the term and will
+ * pass the found term along with the array of $taxonomies and array of $args.
+ * This filter is also called before the array of terms is passed and will pass
+ * the array of terms, along with the $taxonomies and $args.
+ *
+ * The 'list_terms_exclusions' filter passes the compiled exclusions along with
+ * the $args.
+ *
+ * The list of arguments that $args can contain, which will overwrite the defaults:
+ *
+ * orderby - Default is 'name'. Can be name, count, or nothing (will use
+ * term_id).
+ *
+ * order - Default is ASC. Can use DESC.
+ *
+ * hide_empty - Default is true. Will not return empty terms, which means
+ * terms whose count is 0 according to the given taxonomy.
+ *
+ * exclude - Default is an empty string. A comma- or space-delimited string
+ * of term ids to exclude from the return array. If 'include' is non-empty,
+ * 'exclude' is ignored.
+ *
+ * include - Default is an empty string. A comma- or space-delimited string
+ * of term ids to include in the return array.
+ *
+ * number - The maximum number of terms to return. Default is empty.
+ *
+ * offset - The number by which to offset the terms query.
+ *
+ * fields - Default is 'all', which returns an array of term objects.
+ * If 'fields' is 'ids' or 'names', returns an array of
+ * integers or strings, respectively.
+ *
+ * slug - Returns terms whose "slug" matches this value. Default is empty string.
+ *
+ * hierarchical - Whether to include terms that have non-empty descendants
+ * (even if 'hide_empty' is set to true).
+ *
+ * search - Returned terms' names will contain the value of 'search',
+ * case-insensitive. Default is an empty string.
+ *
+ * name__like - Returned terms' names will begin with the value of 'name__like',
+ * case-insensitive. Default is empty string.
+ *
+ * The argument 'pad_counts', if set to true will include the quantity of a term's
+ * children in the quantity of each term's "count" object variable.
+ *
+ * The 'get' argument, if set to 'all' instead of its default empty string,
+ * returns terms regardless of ancestry or whether the terms are empty.
+ *
+ * The 'child_of' argument, when used, should be set to the integer of a term ID. Its default
+ * is 0. If set to a non-zero value, all returned terms will be descendants
+ * of that term according to the given taxonomy. Hence 'child_of' is set to 0
+ * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies
+ * make term ancestry ambiguous.
+ *
+ * The 'parent' argument, when used, should be set to the integer of a term ID. Its default is
+ * the empty string '', which has a different meaning from the integer 0.
+ * If set to an integer value, all returned terms will have as an immediate
+ * ancestor the term whose ID is specified by that integer according to the given taxonomy.
+ * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent'
+ * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings.
+ *
+ * @param string|array Taxonomy name or list of Taxonomy names
+ * @param string|array $args The values of what to search for when returning terms
+ * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist.
+ */
+function &get_terms($taxonomies, $args = '') {
+ global $wpdb;
+ $empty_array = array();
+
+ $single_taxonomy = false;
+ if ( !is_array($taxonomies) ) {
+ $single_taxonomy = true;
+ $taxonomies = array($taxonomies);
+ }
+
+ foreach ( (array) $taxonomies as $taxonomy ) {
+ if ( ! is_taxonomy($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
+ }
+
+ $in_taxonomies = "'" . implode("', '", $taxonomies) . "'";
+
+ $defaults = array('orderby' => 'name', 'order' => 'ASC',
+ 'hide_empty' => true, 'exclude' => '', 'include' => '',
+ 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '',
+ 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '',
+ 'pad_counts' => false, 'offset' => '', 'search' => '');
+ $args = wp_parse_args( $args, $defaults );
+ $args['number'] = absint( $args['number'] );
+ $args['offset'] = absint( $args['offset'] );
+ if ( !$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) ||
+ '' != $args['parent'] ) {
+ $args['child_of'] = 0;
+ $args['hierarchical'] = false;
+ $args['pad_counts'] = false;
+ }
+
+ if ( 'all' == $args['get'] ) {
+ $args['child_of'] = 0;
+ $args['hide_empty'] = 0;
+ $args['hierarchical'] = false;
+ $args['pad_counts'] = false;
+ }
+ extract($args, EXTR_SKIP);
+
+ if ( $child_of ) {
+ $hierarchy = _get_term_hierarchy($taxonomies[0]);
+ if ( !isset($hierarchy[$child_of]) )
+ return $empty_array;
+ }
+
+ if ( $parent ) {
+ $hierarchy = _get_term_hierarchy($taxonomies[0]);
+ if ( !isset($hierarchy[$parent]) )
+ return $empty_array;
+ }
+
+ // $args can be whatever, only use the args defined in defaults to compute the key
+ $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
+ $key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key );
+ $last_changed = wp_cache_get('last_changed', 'terms');
+ if ( !$last_changed ) {
+ $last_changed = time();
+ wp_cache_set('last_changed', $last_changed, 'terms');
+ }
+ $cache_key = "get_terms:$key:$last_changed";
+
+ if ( $cache = wp_cache_get( $cache_key, 'terms' ) ) {
+ $terms = apply_filters('get_terms', $cache, $taxonomies, $args);
+ return $terms;
+ }
+
+ if ( 'count' == $orderby )
+ $orderby = 'tt.count';
+ else if ( 'name' == $orderby )
+ $orderby = 't.name';
+ else if ( 'slug' == $orderby )
+ $orderby = 't.slug';
+ else if ( 'term_group' == $orderby )
+ $orderby = 't.term_group';
+ else
+ $orderby = 't.term_id';
+
+ $where = '';
+ $inclusions = '';
+ if ( !empty($include) ) {
+ $exclude = '';
+ $interms = preg_split('/[\s,]+/',$include);
+ if ( count($interms) ) {
+ foreach ( (array) $interms as $interm ) {
+ if (empty($inclusions))
+ $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' ';
+ else
+ $inclusions .= ' OR t.term_id = ' . intval($interm) . ' ';
+ }
+ }
+ }
+
+ if ( !empty($inclusions) )
+ $inclusions .= ')';
+ $where .= $inclusions;
+
+ $exclusions = '';
+ if ( !empty($exclude) ) {
+ $exterms = preg_split('/[\s,]+/',$exclude);
+ if ( count($exterms) ) {
+ foreach ( (array) $exterms as $exterm ) {
+ if (empty($exclusions))
+ $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
+ else
+ $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
+ }
+ }
+ }
+
+ if ( !empty($exclusions) )
+ $exclusions .= ')';
+ $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args );
+ $where .= $exclusions;
+
+ if ( !empty($slug) ) {
+ $slug = sanitize_title($slug);
+ $where .= " AND t.slug = '$slug'";
+ }
+
+ if ( !empty($name__like) )
+ $where .= " AND t.name LIKE '{$name__like}%'";
+
+ if ( '' != $parent ) {
+ $parent = (int) $parent;
+ $where .= " AND tt.parent = '$parent'";
+ }
+
+ if ( $hide_empty && !$hierarchical )
+ $where .= ' AND tt.count > 0';
+
+ if ( !empty($number) ) {
+ if( $offset )
+ $number = 'LIMIT ' . $offset . ',' . $number;
+ else
+ $number = 'LIMIT ' . $number;
+
+ } else
+ $number = '';
+
+ if ( !empty($search) ) {
+ $search = like_escape($search);
+ $where .= " AND (t.name LIKE '%$search%')";
+ }
+
+ $select_this = '';
+ if ( 'all' == $fields )
+ $select_this = 't.*, tt.*';
+ else if ( 'ids' == $fields )
+ $select_this = 't.term_id, tt.parent, tt.count';
+ else if ( 'names' == $fields )
+ $select_this = 't.term_id, tt.parent, tt.count, t.name';
+
+ $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ($in_taxonomies) $where ORDER BY $orderby $order $number";
+
+ if ( 'all' == $fields ) {
+ $terms = $wpdb->get_results($query);
+ update_term_cache($terms);
+ } else if ( ('ids' == $fields) || ('names' == $fields) ) {
+ $terms = $wpdb->get_results($query);
+ }
+
+ if ( empty($terms) ) {
+ $cache[ $key ] = array();
+ wp_cache_set( 'get_terms', $cache, 'terms' );
+ $terms = apply_filters('get_terms', array(), $taxonomies, $args);
+ return $terms;
+ }
+
+ if ( $child_of ) {
+ $children = _get_term_hierarchy($taxonomies[0]);
+ if ( ! empty($children) )
+ $terms = & _get_term_children($child_of, $terms, $taxonomies[0]);
+ }
+
+ // Update term counts to include children.
+ if ( $pad_counts && 'all' == $fields )
+ _pad_term_counts($terms, $taxonomies[0]);
+
+ // Make sure we show empty categories that have children.
+ if ( $hierarchical && $hide_empty && is_array($terms) ) {
+ foreach ( $terms as $k => $term ) {
+ if ( ! $term->count ) {
+ $children = _get_term_children($term->term_id, $terms, $taxonomies[0]);
+ if( is_array($children) )
+ foreach ( $children as $child )
+ if ( $child->count )
+ continue 2;
+
+ // It really is empty
+ unset($terms[$k]);
+ }
+ }
+ }
+ reset ( $terms );
+
+ $_terms = array();
+ if ( 'ids' == $fields ) {
+ while ( $term = array_shift($terms) )
+ $_terms[] = $term->term_id;
+ $terms = $_terms;
+ } elseif ( 'names' == $fields ) {
+ while ( $term = array_shift($terms) )
+ $_terms[] = $term->name;
+ $terms = $_terms;
+ }
+
+ wp_cache_add( $cache_key, $terms, 'terms' );
+
+ $terms = apply_filters('get_terms', $terms, $taxonomies, $args);
+ return $terms;
+}
+
+/**
+ * Check if Term exists.
+ *
+ * Returns the index of a defined term, or 0 (false) if the term doesn't exist.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ *
+ * @param int|string $term The term to check
+ * @param string $taxonomy The taxonomy name to use
+ * @return mixed Get the term id or Term Object, if exists.
+ */
+function is_term($term, $taxonomy = '') {
+ global $wpdb;
+
+ $select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
+ $tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE ";
+
+ if ( is_int($term) ) {
+ if ( 0 == $term )
+ return 0;
+ $where = 't.term_id = %d';
+ if ( !empty($taxonomy) )
+ return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . " AND tt.taxonomy = %s", $term, $taxonomy ), ARRAY_A );
+ else
+ return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
+ }
+
+ if ( '' === $slug = sanitize_title($term) )
+ return 0;
+
+ $where = 't.slug = %s';
+ $else_where = 't.name = %s';
+
+ if ( !empty($taxonomy) ) {
+ if ( $result = $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $where AND tt.taxonomy = %s", $slug, $taxonomy), ARRAY_A) )
+ return $result;
+
+ return $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $else_where AND tt.taxonomy = %s", $term, $taxonomy), ARRAY_A);
+ }
+
+ if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where", $slug) ) )
+ return $result;
+
+ return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where", $term) );
+}
+
+/**
+ * Sanitize Term all fields.
+ *
+ * Relys on sanitize_term_field() to sanitize the term. The difference is that
+ * this function will sanitize all fields. The context is based
+ * on sanitize_term_field().
+ *
+ * The $term is expected to be either an array or an object.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses sanitize_term_field Used to sanitize all fields in a term
+ *
+ * @param array|object $term The term to check
+ * @param string $taxonomy The taxonomy name to use
+ * @param string $context Default is 'display'.
+ * @return array|object Term with all fields sanitized
+ */
+function sanitize_term($term, $taxonomy, $context = 'display') {
+
+ if ( 'raw' == $context )
+ return $term;
+
+ $fields = array('term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group');
+
+ $do_object = false;
+ if ( is_object($term) )
+ $do_object = true;
+
+ $term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
+
+ foreach ( (array) $fields as $field ) {
+ if ( $do_object ) {
+ if ( isset($term->$field) )
+ $term->$field = sanitize_term_field($field, $term->$field, $term_id, $taxonomy, $context);
+ } else {
+ if ( isset($term[$field]) )
+ $term[$field] = sanitize_term_field($field, $term[$field], $term_id, $taxonomy, $context);
+ }
+ }
+
+ if ( $do_object )
+ $term->filter = $context;
+ else
+ $term['filter'] = $context;
+
+ return $term;
+}
+
+/**
+ * Cleanse the field value in the term based on the context.
+ *
+ * Passing a term field value through the function should be assumed to have
+ * cleansed the value for whatever context the term field is going to be used.
+ *
+ * If no context or an unsupported context is given, then default filters will
+ * be applied.
+ *
+ * There are enough filters for each context to support a custom filtering
+ * without creating your own filter function. Simply create a function that
+ * hooks into the filter you need.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ *
+ * @param string $field Term field to sanitize
+ * @param string $value Search for this term value
+ * @param int $term_id Term ID
+ * @param string $taxonomy Taxonomy Name
+ * @param string $context Either edit, db, display, attribute, or js.
+ * @return mixed sanitized field
+ */
+function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
+ if ( 'parent' == $field || 'term_id' == $field || 'count' == $field || 'term_group' == $field ) {
+ $value = (int) $value;
+ if ( $value < 0 )
+ $value = 0;
+ }
+
+ if ( 'raw' == $context )
+ return $value;
+
+ if ( 'edit' == $context ) {
+ $value = apply_filters("edit_term_$field", $value, $term_id, $taxonomy);
+ $value = apply_filters("edit_${taxonomy}_$field", $value, $term_id);
+ if ( 'description' == $field )
+ $value = format_to_edit($value);
+ else
+ $value = attribute_escape($value);
+ } else if ( 'db' == $context ) {
+ $value = apply_filters("pre_term_$field", $value, $taxonomy);
+ $value = apply_filters("pre_${taxonomy}_$field", $value);
+ // Back compat filters
+ if ( 'slug' == $field )
+ $value = apply_filters('pre_category_nicename', $value);
+
+ } else if ( 'rss' == $context ) {
+ $value = apply_filters("term_${field}_rss", $value, $taxonomy);
+ $value = apply_filters("${taxonomy}_${field}_rss", $value);
+ } else {
+ // Use display filters by default.
+ $value = apply_filters("term_$field", $value, $term_id, $taxonomy, $context);
+ $value = apply_filters("${taxonomy}_$field", $value, $term_id, $context);
+ }
+
+ if ( 'attribute' == $context )
+ $value = attribute_escape($value);
+ else if ( 'js' == $context )
+ $value = js_escape($value);
+
+ return $value;
+}
+
+/**
+ * Count how many terms are in Taxonomy.
+ *
+ * Default $args is 'ignore_empty' which can be 'ignore_empty=true'
+ * or array('ignore_empty' => true);
.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses wp_parse_args() Turns strings into arrays and merges defaults into an array.
+ *
+ * @param string $taxonomy Taxonomy name
+ * @param array|string $args Overwrite defaults
+ * @return int How many terms are in $taxonomy
+ */
+function wp_count_terms( $taxonomy, $args = array() ) {
+ global $wpdb;
+
+ $defaults = array('ignore_empty' => false);
+ $args = wp_parse_args($args, $defaults);
+ extract($args, EXTR_SKIP);
+
+ $where = '';
+ if ( $ignore_empty )
+ $where = 'AND count > 0';
+
+ return $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE taxonomy = %s $where", $taxonomy) );
+}
+
+/**
+ * Will unlink the term from the taxonomy.
+ *
+ * Will remove the term's relationship to the taxonomy, not the term or taxonomy
+ * itself. The term and taxonomy will still exist. Will require the term's
+ * object ID to perform the operation.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int $object_id The term Object Id that refers to the term
+ * @param string|array $taxonomy List of Taxonomy Names or single Taxonomy name.
+ */
+function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
+ global $wpdb;
+
+ $object_id = (int) $object_id;
+
+ if ( !is_array($taxonomies) )
+ $taxonomies = array($taxonomies);
+
+ foreach ( (array) $taxonomies as $taxonomy ) {
+ $tt_ids = wp_get_object_terms($object_id, $taxonomy, 'fields=tt_ids');
+ $in_tt_ids = "'" . implode("', '", $tt_ids) . "'";
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id) );
+ wp_update_term_count($tt_ids, $taxonomy);
+ }
+}
+
+/**
+ * Removes a term from the database.
+ *
+ * If the term is a parent of other terms, then the children will be updated to
+ * that term's parent.
+ *
+ * The $args 'default' will only override the terms found, if there is only one
+ * term found. Any other and the found terms are used.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses do_action() Calls both 'delete_term' and 'delete_$taxonomy' action
+ * hooks, passing term object, term id. 'delete_term' gets an additional
+ * parameter with the $taxonomy parameter.
+ *
+ * @param int $term Term ID
+ * @param string $taxonomy Taxonomy Name
+ * @param array|string $args Optional. Change 'default' term id and override found term ids.
+ * @return bool|WP_Error Returns false if not term; true if completes delete action.
+ */
+function wp_delete_term( $term, $taxonomy, $args = array() ) {
+ global $wpdb;
+
+ $term = (int) $term;
+
+ if ( ! $ids = is_term($term, $taxonomy) )
+ return false;
+ if ( is_wp_error( $ids ) )
+ return $ids;
+
+ $tt_id = $ids['term_taxonomy_id'];
+
+ $defaults = array();
+ $args = wp_parse_args($args, $defaults);
+ extract($args, EXTR_SKIP);
+
+ if ( isset($default) ) {
+ $default = (int) $default;
+ if ( ! is_term($default, $taxonomy) )
+ unset($default);
+ }
+
+ // Update children to point to new parent
+ if ( is_taxonomy_hierarchical($taxonomy) ) {
+ $term_obj = get_term($term, $taxonomy);
+ if ( is_wp_error( $term_obj ) )
+ return $term_obj;
+ $parent = $term_obj->parent;
+
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
+ }
+
+ $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
+
+ foreach ( (array) $objects as $object ) {
+ $terms = wp_get_object_terms($object, $taxonomy, 'fields=ids');
+ if ( 1 == count($terms) && isset($default) )
+ $terms = array($default);
+ else
+ $terms = array_diff($terms, array($term));
+ $terms = array_map('intval', $terms);
+ wp_set_object_terms($object, $terms, $taxonomy);
+ }
+
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $tt_id ) );
+
+ // Delete the term if no taxonomies use it.
+ if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term) ) )
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->terms WHERE term_id = %d", $term) );
+
+ clean_term_cache($term, $taxonomy);
+
+ do_action('delete_term', $term, $tt_id, $taxonomy);
+ do_action("delete_$taxonomy", $term, $tt_id);
+
+ return true;
+}
+
+/**
+ * Retrieves the terms associated with the given object(s), in the supplied taxonomies.
+ *
+ * The following information has to do the $args parameter and for what can be
+ * contained in the string or array of that parameter, if it exists.
+ *
+ * The first argument is called, 'orderby' and has the default value of 'name'.
+ * The other value that is supported is 'count'.
+ *
+ * The second argument is called, 'order' and has the default value of 'ASC'.
+ * The only other value that will be acceptable is 'DESC'.
+ *
+ * The final argument supported is called, 'fields' and has the default value of
+ * 'all'. There are multiple other options that can be used instead. Supported
+ * values are as follows: 'all', 'ids', 'names', and finally
+ * 'all_with_object_id'.
+ *
+ * The fields argument also decides what will be returned. If 'all' or
+ * 'all_with_object_id' is choosen or the default kept intact, then all matching
+ * terms objects will be returned. If either 'ids' or 'names' is used, then an
+ * array of all matching term ids or term names will be returned respectively.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int|array $object_id The id of the object(s) to retrieve.
+ * @param string|array $taxonomies The taxonomies to retrieve terms from.
+ * @param array|string $args Change what is returned
+ * @return array|WP_Error The requested term data or empty array if no terms found. WP_Error if $taxonomy does not exist.
+ */
+function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
+ global $wpdb;
+
+ if ( !is_array($taxonomies) )
+ $taxonomies = array($taxonomies);
+
+ foreach ( (array) $taxonomies as $taxonomy ) {
+ if ( ! is_taxonomy($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
+ }
+
+ if ( !is_array($object_ids) )
+ $object_ids = array($object_ids);
+ $object_ids = array_map('intval', $object_ids);
+
+ $defaults = array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'all');
+ $args = wp_parse_args( $args, $defaults );
+
+ $terms = array();
+ if ( count($taxonomies) > 1 ) {
+ foreach ( $taxonomies as $index => $taxonomy ) {
+ $t = get_taxonomy($taxonomy);
+ if ( isset($t->args) && is_array($t->args) && $args != array_merge($args, $t->args) ) {
+ unset($taxonomies[$index]);
+ $terms = array_merge($terms, wp_get_object_terms($object_ids, $taxonomy, array_merge($args, $t->args)));
+ }
+ }
+ } else {
+ $t = get_taxonomy($taxonomies[0]);
+ if ( isset($t->args) && is_array($t->args) )
+ $args = array_merge($args, $t->args);
+ }
+
+ extract($args, EXTR_SKIP);
+
+ if ( 'count' == $orderby )
+ $orderby = 'tt.count';
+ else if ( 'name' == $orderby )
+ $orderby = 't.name';
+ else if ( 'slug' == $orderby )
+ $orderby = 't.slug';
+ else if ( 'term_group' == $orderby )
+ $orderby = 't.term_group';
+ else if ( 'term_order' == $orderby )
+ $orderby = 'tr.term_order';
+ else
+ $orderby = 't.term_id';
+
+ $taxonomies = "'" . implode("', '", $taxonomies) . "'";
+ $object_ids = implode(', ', $object_ids);
+
+ $select_this = '';
+ if ( 'all' == $fields )
+ $select_this = 't.*, tt.*';
+ else if ( 'ids' == $fields )
+ $select_this = 't.term_id';
+ else if ( 'names' == $fields )
+ $select_this = 't.name';
+ else if ( 'all_with_object_id' == $fields )
+ $select_this = 't.*, tt.*, tr.object_id';
+
+ $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tr.object_id IN ($object_ids) ORDER BY $orderby $order";
+
+ if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
+ $terms = array_merge($terms, $wpdb->get_results($query));
+ update_term_cache($terms);
+ } else if ( 'ids' == $fields || 'names' == $fields ) {
+ $terms = array_merge($terms, $wpdb->get_col($query));
+ } else if ( 'tt_ids' == $fields ) {
+ $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) ORDER BY tr.term_taxonomy_id $order");
+ }
+
+ if ( ! $terms )
+ return array();
+
+ return $terms;
+}
+
+/**
+ * Adds a new term to the database. Optionally marks it as an alias of an existing term.
+ *
+ * Error handling is assigned for the nonexistance of the $taxonomy and $term
+ * parameters before inserting. If both the term id and taxonomy exist
+ * previously, then an array will be returned that contains the term id and the
+ * contents of what is returned. The keys of the array are 'term_id' and
+ * 'term_taxonomy_id' containing numeric values.
+ *
+ * It is assumed that the term does not yet exist or the above will apply. The
+ * term will be first added to the term table and then related to the taxonomy
+ * if everything is well. If everything is correct, then several actions will be
+ * run prior to a filter and then several actions will be run after the filter
+ * is run.
+ *
+ * The arguments decide how the term is handled based on the $args parameter.
+ * The following is a list of the available overrides and the defaults.
+ *
+ * 'alias_of'. There is no default, but if added, expected is the slug that the
+ * term will be an alias of. Expected to be a string.
+ *
+ * 'description'. There is no default. If exists, will be added to the database
+ * along with the term. Expected to be a string.
+ *
+ * 'parent'. Expected to be numeric and default is 0 (zero). Will assign value
+ * of 'parent' to the term.
+ *
+ * 'slug'. Expected to be a string. There is no default.
+ *
+ * If 'slug' argument exists then the slug will be checked to see if it is not
+ * a valid term. If that check succeeds (it is not a valid term), then it is
+ * added and the term id is given. If it fails, then a check is made to whether
+ * the taxonomy is hierarchical and the parent argument is not empty. If the
+ * second check succeeds, the term will be inserted and the term id will be
+ * given.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @uses do_action() Calls 'create_term' hook with the term id and taxonomy id as parameters.
+ * @uses do_action() Calls 'create_$taxonomy' hook with term id and taxonomy id as parameters.
+ * @uses apply_filters() Calls 'term_id_filter' hook with term id and taxonomy id as parameters.
+ * @uses do_action() Calls 'created_term' hook with the term id and taxonomy id as parameters.
+ * @uses do_action() Calls 'created_$taxonomy' hook with term id and taxonomy id as parameters.
+ *
+ * @param int|string $term The term to add or update.
+ * @param string $taxonomy The taxonomy to which to add the term
+ * @param array|string $args Change the values of the inserted term
+ * @return array|WP_Error The Term ID and Term Taxonomy ID
+ */
+function wp_insert_term( $term, $taxonomy, $args = array() ) {
+ global $wpdb;
+
+ if ( ! is_taxonomy($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+ if ( is_int($term) && 0 == $term )
+ return new WP_Error('invalid_term_id', __('Invalid term ID'));
+
+ if ( '' == trim($term) )
+ return new WP_Error('empty_term_name', __('A name is required for this term'));
+
+ $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
+ $args = wp_parse_args($args, $defaults);
+ $args['name'] = $term;
+ $args['taxonomy'] = $taxonomy;
+ $args = sanitize_term($args, $taxonomy, 'db');
+ extract($args, EXTR_SKIP);
+
+ // expected_slashed ($name)
+ $name = stripslashes($name);
+ $description = stripslashes($description);
+
+ if ( empty($slug) )
+ $slug = sanitize_title($name);
+
+ $term_group = 0;
+ if ( $alias_of ) {
+ $alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) );
+ if ( $alias->term_group ) {
+ // The alias we want is already in a group, so let's use that one.
+ $term_group = $alias->term_group;
+ } else {
+ // The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
+ $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->terms SET term_group = %d WHERE term_id = %d", $term_group, $alias->term_id ) );
+ }
+ }
+
+ if ( ! $term_id = is_term($slug) ) {
+ if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
+ return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
+ $term_id = (int) $wpdb->insert_id;
+ } else if ( is_taxonomy_hierarchical($taxonomy) && !empty($parent) ) {
+ // If the taxonomy supports hierarchy and the term has a parent, make the slug unique
+ // by incorporating parent slugs.
+ $slug = wp_unique_term_slug($slug, (object) $args);
+ if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
+ return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
+ $term_id = (int) $wpdb->insert_id;
+ }
+
+ if ( empty($slug) ) {
+ $slug = sanitize_title($slug, $term_id);
+ $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
+ }
+
+ $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );
+
+ if ( !empty($tt_id) )
+ return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+
+ $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
+ $tt_id = (int) $wpdb->insert_id;
+
+ do_action("create_term", $term_id, $tt_id);
+ do_action("create_$taxonomy", $term_id, $tt_id);
+
+ $term_id = apply_filters('term_id_filter', $term_id, $tt_id);
+
+ clean_term_cache($term_id, $taxonomy);
+
+ do_action("created_term", $term_id, $tt_id);
+ do_action("created_$taxonomy", $term_id, $tt_id);
+
+ return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+}
+
+/**
+ * Create Term and Taxonomy Relationships.
+ *
+ * Relates an object (post, link etc) to a term and taxonomy type. Creates the
+ * term and taxonomy relationship if it doesn't already exist. Creates a term if
+ * it doesn't exist (using the slug).
+ *
+ * A relationship means that the term is grouped in or belongs to the taxonomy.
+ * A term has no meaning until it is given context by defining which taxonomy it
+ * exists under.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int $object_id The object to relate to.
+ * @param array|int|string $term The slug or id of the term.
+ * @param array|string $taxonomy The context in which to relate the term to the object.
+ * @param bool $append If false will delete difference of terms.
+ * @return array|WP_Error Affected Term IDs
+ */
+function wp_set_object_terms($object_id, $terms, $taxonomy, $append = false) {
+ global $wpdb;
+
+ $object_id = (int) $object_id;
+
+ if ( ! is_taxonomy($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
+
+ if ( !is_array($terms) )
+ $terms = array($terms);
+
+ if ( ! $append )
+ $old_tt_ids = wp_get_object_terms($object_id, $taxonomy, 'fields=tt_ids');
+
+ $tt_ids = array();
+ $term_ids = array();
+
+ foreach ( (array) $terms as $term) {
+ if ( !strlen(trim($term)) )
+ continue;
+
+ if ( !$term_info = is_term($term, $taxonomy) )
+ $term_info = wp_insert_term($term, $taxonomy);
+ if ( is_wp_error($term_info) )
+ return $term_info;
+ $term_ids[] = $term_info['term_id'];
+ $tt_id = $term_info['term_taxonomy_id'];
+ $tt_ids[] = $tt_id;
+
+ if ( $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id = %d", $object_id, $tt_id ) ) )
+ continue;
+ $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );
+ }
+
+ wp_update_term_count($tt_ids, $taxonomy);
+
+ if ( ! $append ) {
+ $delete_terms = array_diff($old_tt_ids, $tt_ids);
+ if ( $delete_terms ) {
+ $in_delete_terms = "'" . implode("', '", $delete_terms) . "'";
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_delete_terms)", $object_id) );
+ wp_update_term_count($delete_terms, $taxonomy);
+ }
+ }
+
+ $t = get_taxonomy($taxonomy);
+ if ( ! $append && isset($t->sort) && $t->sort ) {
+ $values = array();
+ $term_order = 0;
+ $final_tt_ids = wp_get_object_terms($object_id, $taxonomy, 'fields=tt_ids');
+ foreach ( $tt_ids as $tt_id )
+ if ( in_array($tt_id, $final_tt_ids) )
+ $values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order);
+ if ( $values )
+ $wpdb->query("INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join(',', $values) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)");
+ }
+
+ return $tt_ids;
+}
+
+/**
+ * Will make slug unique, if it isn't already.
+ *
+ * The $slug has to be unique global to every taxonomy, meaning that one
+ * taxonomy term can't have a matching slug with another taxonomy term. Each
+ * slug has to be globally unique for every taxonomy.
+ *
+ * The way this works is that if the taxonomy that the term belongs to is
+ * heirarchical and has a parent, it will append that parent to the $slug.
+ *
+ * If that still doesn't return an unique slug, then it try to append a number
+ * until it finds a number that is truely unique.
+ *
+ * The only purpose for $term is for appending a parent, if one exists.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param string $slug The string that will be tried for a unique slug
+ * @param object $term The term object that the $slug will belong too
+ * @return string Will return a true unique slug.
+ */
+function wp_unique_term_slug($slug, $term) {
+ global $wpdb;
+
+ // If the taxonomy supports hierarchy and the term has a parent, make the slug unique
+ // by incorporating parent slugs.
+ if ( is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) {
+ $the_parent = $term->parent;
+ while ( ! empty($the_parent) ) {
+ $parent_term = get_term($the_parent, $term->taxonomy);
+ if ( is_wp_error($parent_term) || empty($parent_term) )
+ break;
+ $slug .= '-' . $parent_term->slug;
+ if ( empty($parent_term->parent) )
+ break;
+ $the_parent = $parent_term->parent;
+ }
+ }
+
+ // If we didn't get a unique slug, try appending a number to make it unique.
+ if ( !empty($args['term_id']) )
+ $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $args['term_id'] );
+ else
+ $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
+
+ if ( $wpdb->get_var( $query ) ) {
+ $num = 2;
+ do {
+ $alt_slug = $slug . "-$num";
+ $num++;
+ $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
+ } while ( $slug_check );
+ $slug = $alt_slug;
+ }
+
+ return $slug;
+}
+
+/**
+ * Update term based on arguments provided.
+ *
+ * The $args will indiscriminately override all values with the same field name.
+ * Care must be taken to not override important information need to update or
+ * update will fail (or perhaps create a new term, neither would be acceptable).
+ *
+ * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not
+ * defined in $args already.
+ *
+ * 'alias_of' will create a term group, if it doesn't already exist, and update
+ * it for the $term.
+ *
+ * If the 'slug' argument in $args is missing, then the 'name' in $args will be
+ * used. It should also be noted that if you set 'slug' and it isn't unique then
+ * a WP_Error will be passed back. If you don't pass any slug, then a unique one
+ * will be created for you.
+ *
+ * For what can be overrode in $args, check the term scheme can contain and stay
+ * away from the term keys.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses do_action() Will call both 'edit_term' and 'edit_$taxonomy' twice.
+ * @uses apply_filters() Will call the 'term_id_filter' filter and pass the term
+ * id and taxonomy id.
+ *
+ * @param int $term The ID of the term
+ * @param string $taxonomy The context in which to relate the term to the object.
+ * @param array|string $args Overwrite term field values
+ * @return array|WP_Error Returns Term ID and Taxonomy Term ID
+ */
+function wp_update_term( $term, $taxonomy, $args = array() ) {
+ global $wpdb;
+
+ if ( ! is_taxonomy($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+ $term_id = (int) $term;
+
+ // First, get all of the original args
+ $term = get_term ($term_id, $taxonomy, ARRAY_A);
+
+ // Escape data pulled from DB.
+ $term = add_magic_quotes($term);
+
+ // Merge old and new args with new args overwriting old ones.
+ $args = array_merge($term, $args);
+
+ $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
+ $args = wp_parse_args($args, $defaults);
+ $args = sanitize_term($args, $taxonomy, 'db');
+ extract($args, EXTR_SKIP);
+
+ // expected_slashed ($name)
+ $name = stripslashes($name);
+ $description = stripslashes($description);
+
+ if ( '' == trim($name) )
+ return new WP_Error('empty_term_name', __('A name is required for this term'));
+
+ $empty_slug = false;
+ if ( empty($slug) ) {
+ $empty_slug = true;
+ $slug = sanitize_title($name);
+ }
+
+ if ( $alias_of ) {
+ $alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) );
+ if ( $alias->term_group ) {
+ // The alias we want is already in a group, so let's use that one.
+ $term_group = $alias->term_group;
+ } else {
+ // The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
+ $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
+ $wpdb->update( $wpdb->terms, compact('term_group'), array( 'term_id' => $alias->term_id ) );
+ }
+ }
+
+ // Check for duplicate slug
+ $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $slug ) );
+ if ( $id && ($id != $term_id) ) {
+ // If an empty slug was passed or the parent changed, reset the slug to something unique.
+ // Otherwise, bail.
+ if ( $empty_slug || ( $parent != $term->parent) )
+ $slug = wp_unique_term_slug($slug, (object) $args);
+ else
+ return new WP_Error('duplicate_term_slug', sprintf(__('The slug "%s" is already in use by another term'), $slug));
+ }
+
+ $wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) );
+
+ if ( empty($slug) ) {
+ $slug = sanitize_title($name, $term_id);
+ $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
+ }
+
+ $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) );
+
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
+
+ do_action("edit_term", $term_id, $tt_id);
+ do_action("edit_$taxonomy", $term_id, $tt_id);
+
+ $term_id = apply_filters('term_id_filter', $term_id, $tt_id);
+
+ clean_term_cache($term_id, $taxonomy);
+
+ do_action("edited_term", $term_id, $tt_id);
+ do_action("edited_$taxonomy", $term_id, $tt_id);
+
+ return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+}
+
+/**
+ * Enable or disable term counting.
+ *
+ * @since 2.5.0
+ *
+ * @param bool $defer Optional. Enable if true, disable if false.
+ * @return bool Whether term counting is enabled or disabled.
+ */
+function wp_defer_term_counting($defer=null) {
+ static $_defer = false;
+
+ if ( is_bool($defer) ) {
+ $_defer = $defer;
+ // flush any deferred counts
+ if ( !$defer )
+ wp_update_term_count( null, null, true );
+ }
+
+ return $_defer;
+}
+
+/**
+ * Updates the amount of terms in taxonomy.
+ *
+ * If there is a taxonomy callback applyed, then it will be called for updating
+ * the count.
+ *
+ * The default action is to count what the amount of terms have the relationship
+ * of term ID. Once that is done, then update the database.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int|array $terms The term_taxonomy_id of the terms
+ * @param string $taxonomy The context of the term.
+ * @return bool If no terms will return false, and if successful will return true.
+ */
+function wp_update_term_count( $terms, $taxonomy, $do_deferred=false ) {
+ static $_deferred = array();
+
+ if ( $do_deferred ) {
+ foreach ( (array) array_keys($_deferred) as $tax ) {
+ wp_update_term_count_now( $_deferred[$tax], $tax );
+ unset( $_deferred[$tax] );
+ }
+ }
+
+ if ( empty($terms) )
+ return false;
+
+ if ( !is_array($terms) )
+ $terms = array($terms);
+
+ if ( wp_defer_term_counting() ) {
+ if ( !isset($_deferred[$taxonomy]) )
+ $_deferred[$taxonomy] = array();
+ $_deferred[$taxonomy] = array_unique( array_merge($_deferred[$taxonomy], $terms) );
+ return true;
+ }
+
+ return wp_update_term_count_now( $terms, $taxonomy );
+}
+
+/**
+ * Perform term count update immediately.
+ *
+ * @since 2.5.0
+ *
+ * @param array $terms The term_taxonomy_id of terms to update.
+ * @param string $taxonomy The context of the term.
+ * @return bool Always true when complete.
+ */
+function wp_update_term_count_now( $terms, $taxonomy ) {
+ global $wpdb;
+
+ $terms = array_map('intval', $terms);
+
+ $taxonomy = get_taxonomy($taxonomy);
+ if ( !empty($taxonomy->update_count_callback) ) {
+ call_user_func($taxonomy->update_count_callback, $terms);
+ } else {
+ // Default count updater
+ foreach ( (array) $terms as $term) {
+ $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term) );
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
+ }
+
+ }
+
+ clean_term_cache($terms);
+
+ return true;
+}
+
+//
+// Cache
+//
+
+
+/**
+ * Removes the taxonomy relationship to terms from the cache.
+ *
+ * Will remove the entire taxonomy relationship containing term $object_id. The
+ * term IDs have to exist within the taxonomy $object_type for the deletion to
+ * take place.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @see get_object_taxonomies() for more on $object_type
+ * @uses do_action() Will call action hook named, 'clean_object_term_cache' after completion.
+ * Passes, function params in same order.
+ *
+ * @param int|array $object_ids Single or list of term object ID(s)
+ * @param array|string $object_type The taxonomy object type
+ */
+function clean_object_term_cache($object_ids, $object_type) {
+ if ( !is_array($object_ids) )
+ $object_ids = array($object_ids);
+
+ foreach ( $object_ids as $id )
+ foreach ( get_object_taxonomies($object_type) as $taxonomy )
+ wp_cache_delete($id, "{$taxonomy}_relationships");
+
+ do_action('clean_object_term_cache', $object_ids, $object_type);
+}
+
+
+/**
+ * Will remove all of the term ids from the cache.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int|array $ids Single or list of Term IDs
+ * @param string $taxonomy Can be empty and will assume tt_ids, else will use for context.
+ */
+function clean_term_cache($ids, $taxonomy = '') {
+ global $wpdb;
+ static $cleaned = array();
+
+ if ( !is_array($ids) )
+ $ids = array($ids);
+
+ $taxonomies = array();
+ // If no taxonomy, assume tt_ids.
+ if ( empty($taxonomy) ) {
+ $tt_ids = implode(', ', $ids);
+ $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)");
+ foreach ( (array) $terms as $term ) {
+ $taxonomies[] = $term->taxonomy;
+ wp_cache_delete($term->term_id, $term->taxonomy);
+ }
+ $taxonomies = array_unique($taxonomies);
+ } else {
+ foreach ( $ids as $id ) {
+ wp_cache_delete($id, $taxonomy);
+ }
+ $taxonomies = array($taxonomy);
+ }
+
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( isset($cleaned[$taxonomy]) )
+ continue;
+ $cleaned[$taxonomy] = true;
+ wp_cache_delete('all_ids', $taxonomy);
+ wp_cache_delete('get', $taxonomy);
+ delete_option("{$taxonomy}_children");
+ }
+
+ wp_cache_set('last_changed', time(), 'terms');
+
+ do_action('clean_term_cache', $ids, $taxonomy);
+}
+
+
+/**
+ * Retrieves the taxonomy relationship to the term object id.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses wp_cache_get() Retrieves taxonomy relationship from cache
+ *
+ * @param int|array $id Term object ID
+ * @param string $taxonomy Taxonomy Name
+ * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id.
+ */
+function &get_object_term_cache($id, $taxonomy) {
+ $cache = wp_cache_get($id, "{$taxonomy}_relationships");
+ return $cache;
+}
+
+
+/**
+ * Updates the cache for Term ID(s).
+ *
+ * Will only update the cache for terms not already cached.
+ *
+ * The $object_ids expects that the ids be separated by commas, if it is a
+ * string.
+ *
+ * It should be noted that update_object_term_cache() is very time extensive. It
+ * is advised that the function is not called very often or at least not for a
+ * lot of terms that exist in a lot of taxonomies. The amount of time increases
+ * for each term and it also increases for each taxonomy the term belongs to.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses wp_get_object_terms() Used to get terms from the database to update
+ *
+ * @param string|array $object_ids Single or list of term object ID(s)
+ * @param array|string $object_type The taxonomy object type
+ * @return null|bool Null value is given with empty $object_ids. False if
+ */
+function update_object_term_cache($object_ids, $object_type) {
+ if ( empty($object_ids) )
+ return;
+
+ if ( !is_array($object_ids) )
+ $object_ids = explode(',', $object_ids);
+
+ $object_ids = array_map('intval', $object_ids);
+
+ $taxonomies = get_object_taxonomies($object_type);
+
+ $ids = array();
+ foreach ( (array) $object_ids as $id ) {
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( false === wp_cache_get($id, "{$taxonomy}_relationships") ) {
+ $ids[] = $id;
+ break;
+ }
+ }
+ }
+
+ if ( empty( $ids ) )
+ return false;
+
+ $terms = wp_get_object_terms($ids, $taxonomies, 'fields=all_with_object_id');
+
+ $object_terms = array();
+ foreach ( (array) $terms as $term )
+ $object_terms[$term->object_id][$term->taxonomy][$term->term_id] = $term;
+
+ foreach ( $ids as $id ) {
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( ! isset($object_terms[$id][$taxonomy]) ) {
+ if ( !isset($object_terms[$id]) )
+ $object_terms[$id] = array();
+ $object_terms[$id][$taxonomy] = array();
+ }
+ }
+ }
+
+ foreach ( $object_terms as $id => $value ) {
+ foreach ( $value as $taxonomy => $terms ) {
+ wp_cache_set($id, $terms, "{$taxonomy}_relationships");
+ }
+ }
+}
+
+
+/**
+ * Updates Terms to Taxonomy in cache.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @param array $terms List of Term objects to change
+ * @param string $taxonomy Optional. Update Term to this taxonomy in cache
+ */
+function update_term_cache($terms, $taxonomy = '') {
+ foreach ( (array) $terms as $term ) {
+ $term_taxonomy = $taxonomy;
+ if ( empty($term_taxonomy) )
+ $term_taxonomy = $term->taxonomy;
+
+ wp_cache_add($term->term_id, $term, $term_taxonomy);
+ }
+}
+
+//
+// Private
+//
+
+
+/**
+ * Retrieves children of taxonomy.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ *
+ * @uses update_option() Stores all of the children in "$taxonomy_children"
+ * option. That is the name of the taxonomy, immediately followed by '_children'.
+ *
+ * @param string $taxonomy Taxonomy Name
+ * @return array Empty if $taxonomy isn't hierarachical or returns children.
+ */
+function _get_term_hierarchy($taxonomy) {
+ if ( !is_taxonomy_hierarchical($taxonomy) )
+ return array();
+ $children = get_option("{$taxonomy}_children");
+ if ( is_array($children) )
+ return $children;
+
+ $children = array();
+ $terms = get_terms($taxonomy, 'get=all');
+ foreach ( $terms as $term ) {
+ if ( $term->parent > 0 )
+ $children[$term->parent][] = $term->term_id;
+ }
+ update_option("{$taxonomy}_children", $children);
+
+ return $children;
+}
+
+
+/**
+ * Get the subset of $terms that are descendants of $term_id.
+ *
+ * If $terms is an array of objects, then _get_term_children returns an array of objects.
+ * If $terms is an array of IDs, then _get_term_children returns an array of IDs.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ *
+ * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id.
+ * @param array $terms The set of terms---either an array of term objects or term IDs---from which those that are descendants of $term_id will be chosen.
+ * @param string $taxonomy The taxonomy which determines the hierarchy of the terms.
+ * @return array The subset of $terms that are descendants of $term_id.
+ */
+function &_get_term_children($term_id, $terms, $taxonomy) {
+ $empty_array = array();
+ if ( empty($terms) )
+ return $empty_array;
+
+ $term_list = array();
+ $has_children = _get_term_hierarchy($taxonomy);
+
+ if ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
+ return $empty_array;
+
+ foreach ( (array) $terms as $term ) {
+ $use_id = false;
+ if ( !is_object($term) ) {
+ $term = get_term($term, $taxonomy);
+ if ( is_wp_error( $term ) )
+ return $term;
+ $use_id = true;
+ }
+
+ if ( $term->term_id == $term_id )
+ continue;
+
+ if ( $term->parent == $term_id ) {
+ if ( $use_id )
+ $term_list[] = $term->term_id;
+ else
+ $term_list[] = $term;
+
+ if ( !isset($has_children[$term->term_id]) )
+ continue;
+
+ if ( $children = _get_term_children($term->term_id, $terms, $taxonomy) )
+ $term_list = array_merge($term_list, $children);
+ }
+ }
+
+ return $term_list;
+}
+
+
+/**
+ * Add count of children to parent count.
+ *
+ * Recalculates term counts by including items from child terms. Assumes all
+ * relevant children are already in the $terms argument.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param array $terms List of Term IDs
+ * @param string $taxonomy Term Context
+ * @return null Will break from function if conditions are not met.
+ */
+function _pad_term_counts(&$terms, $taxonomy) {
+ global $wpdb;
+
+ // This function only works for post categories.
+ if ( 'category' != $taxonomy )
+ return;
+
+ $term_hier = _get_term_hierarchy($taxonomy);
+
+ if ( empty($term_hier) )
+ return;
+
+ $term_items = array();
+
+ foreach ( (array) $terms as $key => $term ) {
+ $terms_by_id[$term->term_id] = & $terms[$key];
+ $term_ids[$term->term_taxonomy_id] = $term->term_id;
+ }
+
+ // Get the object and term ids and stick them in a lookup table
+ $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (".join(',', array_keys($term_ids)).") AND post_type = 'post' AND post_status = 'publish'");
+ foreach ( $results as $row ) {
+ $id = $term_ids[$row->term_taxonomy_id];
+ $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
+ }
+
+ // Touch every ancestor's lookup row for each post in each term
+ foreach ( $term_ids as $term_id ) {
+ $child = $term_id;
+ while ( $parent = $terms_by_id[$child]->parent ) {
+ if ( !empty($term_items[$term_id]) )
+ foreach ( $term_items[$term_id] as $item_id => $touches ) {
+ $term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id]: 1;
+ }
+ $child = $parent;
+ }
+ }
+
+ // Transfer the touched cells
+ foreach ( (array) $term_items as $id => $items )
+ if ( isset($terms_by_id[$id]) )
+ $terms_by_id[$id]->count = count($items);
+}
+
+//
+// Default callbacks
+//
+
+/**
+ * Will update term count based on posts.
+ *
+ * Private function for the default callback for post_tag and category
+ * taxonomies.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param array $terms List of Term taxonomy IDs
+ */
+function _update_post_term_count( $terms ) {
+ global $wpdb;
+
+ foreach ( (array) $terms as $term ) {
+ $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type = 'post' AND term_taxonomy_id = %d", $term ) );
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
+ }
+}
+
+
+/**
+ * Generates a permalink for a taxonomy term archive.
+ *
+ * @since 2.5.0
+ *
+ * @param object|int|string $term
+ * @param string $taxonomy
+ * @return string HTML link to taxonomy term archive
+ */
+function get_term_link( $term, $taxonomy ) {
+ global $wp_rewrite;
+
+ // use legacy functions for core taxonomies until they are fully plugged in
+ if ( $taxonomy == 'category' )
+ return get_category_link($term);
+ if ( $taxonomy == 'post_tag' )
+ return get_tag_link($term);
+
+ $termlink = $wp_rewrite->get_extra_permastruct($taxonomy);
+
+ if ( !is_object($term) ) {
+ if ( is_int($term) ) {
+ $term = &get_term($term, $taxonomy);
+ } else {
+ $term = &get_term_by('slug', $term, $taxonomy);
+ }
+ }
+ if ( is_wp_error( $term ) )
+ return $term;
+
+ $slug = $term->slug;
+
+ if ( empty($termlink) ) {
+ $file = get_option('home') . '/';
+ $t = get_taxonomy($taxonomy);
+ if ( $t->query_var )
+ $termlink = "$file?$t->query_var=$slug";
+ else
+ $termlink = "$file?taxonomy=$taxonomy&term=$slug";
+ } else {
+ $termlink = str_replace("%$taxonomy%", $slug, $termlink);
+ $termlink = get_option('home') . user_trailingslashit($termlink, 'category');
+ }
+ return apply_filters('term_link', $termlink, $term, $taxonomy);
+}
+
+/**
+ * Display the taxonomies of a post with available options.
+ *
+ * This function can be used within the loop to display the taxonomies for a
+ * post without specifying the Post ID. You can also use it outside the Loop to
+ * display the taxonomies for a specific post.
+ *
+ * The available defaults are:
+ * 'post' : default is 0. The post ID to get taxonomies of.
+ * 'before' : default is empty string. Display before taxonomies list.
+ * 'sep' : default is empty string. Separate every taxonomy with value in this.
+ * 'after' : default is empty string. Display this after the taxonomies list.
+ *
+ * @since 2.5.0
+ * @uses get_the_taxonomies()
+ *
+ * @param array $args Override the defaults.
+ */
+function the_taxonomies($args = array()) {
+ $defaults = array(
+ 'post' => 0,
+ 'before' => '',
+ 'sep' => ' ',
+ 'after' => '',
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ echo $before . join($sep, get_the_taxonomies($post)) . $after;
+}
+
+/**
+ * Retrieve all taxonomies associated with a post.
+ *
+ * This function can be used within the loop. It will also return an array of
+ * the taxonomies with links to the taxonomy and name.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post Optional. Post ID or will use Global Post ID (in loop).
+ * @return array
+ */
+function get_the_taxonomies($post = 0) {
+ if ( is_int($post) )
+ $post =& get_post($post);
+ elseif ( !is_object($post) )
+ $post =& $GLOBALS['post'];
+
+ $taxonomies = array();
+
+ if ( !$post )
+ return $taxonomies;
+
+ $template = apply_filters('taxonomy_template', '%s: %l.');
+
+ foreach ( get_object_taxonomies($post) as $taxonomy ) {
+ $t = (array) get_taxonomy($taxonomy);
+ if ( empty($t['label']) )
+ $t['label'] = $taxonomy;
+ if ( empty($t['args']) )
+ $t['args'] = array();
+ if ( empty($t['template']) )
+ $t['template'] = $template;
+
+ $terms = get_object_term_cache($post->ID, $taxonomy);
+ if ( empty($terms) )
+ $terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']);
+
+ $links = array();
+
+ foreach ( $terms as $term )
+ $links[] = "$term->name ";
+
+ if ( $links )
+ $taxonomies[$taxonomy] = wp_sprintf($t['template'], $t['label'], $links, $terms);
+ }
+ return $taxonomies;
+}
+
+/**
+ * Retrieve all taxonomies of a post with just the names.
+ *
+ * @since 2.5.0
+ * @uses get_object_taxonomies()
+ *
+ * @param int $post Optional. Post ID
+ * @return array
+ */
+function get_post_taxonomies($post = 0) {
+ $post =& get_post($post);
+
+ return get_object_taxonomies($post);
+}
+
+/**
+ * Determine if the given object is associated with any of the given terms.
+ *
+ * The given terms are checked against the object's terms' term_ids, names and slugs.
+ * Terms given as integers will only be checked against the object's terms' term_ids.
+ * If no terms are given, determines if object is associated with any terms in the given taxonomy.
+ *
+ * @since 2.7.0
+ * @uses get_object_term_cache()
+ * @uses wp_get_object_terms()
+ *
+ * @param int $object_id. ID of the object (post ID, link ID, ...)
+ * @param string $taxonomy. Single taxonomy name
+ * @param int|string|array $terms Optional. Term term_id, name, slug or array of said
+ * @return bool|WP_Error. WP_Error on input error.
+ */
+function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
+ if ( !$object_id = (int) $object_id )
+ return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) );
+
+ $object_terms = get_object_term_cache( $object_id, $taxonomy );
+ if ( empty( $object_terms ) )
+ $object_terms = wp_get_object_terms( $object_id, $taxonomy );
+
+ if ( is_wp_error( $object_terms ) )
+ return $object_terms;
+ if ( empty( $object_terms ) )
+ return false;
+ if ( empty( $terms ) )
+ return ( !empty( $object_terms ) );
+
+ $terms = (array) $terms;
+
+ if ( $ints = array_filter( $terms, 'is_int' ) )
+ $strs = array_diff( $terms, $ints );
+ else
+ $strs =& $terms;
+
+ foreach ( $object_terms as $object_term ) {
+ if ( $ints && in_array( $object_term->term_id, $ints ) ) return true; // If int, check against term_id
+ if ( $strs ) {
+ if ( in_array( $object_term->term_id, $strs ) ) return true;
+ if ( in_array( $object_term->name, $strs ) ) return true;
+ if ( in_array( $object_term->slug, $strs ) ) return true;
+ }
+ }
+
+ return false;
+}
+
+?>
diff -uNr a/blog/wp-includes/template-loader.php b/blog/wp-includes/template-loader.php
--- a/blog/wp-includes/template-loader.php false
+++ b/blog/wp-includes/template-loader.php 6d061cc92284502aec2737233b9e1033a9efde829fc5e9982b50ec74019ab87d93fe051770c7dc72c292617bcf6a3615cc67be0031c162bc46cfcfada45935eb
@@ -0,0 +1,78 @@
+
\ No newline at end of file
diff -uNr a/blog/wp-includes/Text/Diff/Engine/index.php b/blog/wp-includes/Text/Diff/Engine/index.php
--- a/blog/wp-includes/Text/Diff/Engine/index.php false
+++ b/blog/wp-includes/Text/Diff/Engine/index.php 099fbcf9478701c433aa576bbcc0cec1987ebf948f13220182da7dc8711b448daddf9ea289b9e8ea4288757f913c64f5f06eb5011e16d4d23592aae16800adb0
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff -uNr a/blog/wp-includes/Text/Diff/Engine/native.php b/blog/wp-includes/Text/Diff/Engine/native.php
--- a/blog/wp-includes/Text/Diff/Engine/native.php false
+++ b/blog/wp-includes/Text/Diff/Engine/native.php 7d21d29aed8ea3e0573c102182575ae8aed3aa4a6d3c2ba4ab4c981946f65b61898152379773e07f2f79a3706364c2595b199670979e7828b6295d024e48f6f4
@@ -0,0 +1,437 @@
+ 2, and some optimizations) are from
+ * Geoffrey T. Dairiki . The original PHP version of this
+ * code was written by him, and is used/adapted with his permission.
+ *
+ * Copyright 2004-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @author Geoffrey T. Dairiki
+ * @package Text_Diff
+ */
+class Text_Diff_Engine_native {
+
+ function diff($from_lines, $to_lines)
+ {
+ array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+ array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+ $n_from = count($from_lines);
+ $n_to = count($to_lines);
+
+ $this->xchanged = $this->ychanged = array();
+ $this->xv = $this->yv = array();
+ $this->xind = $this->yind = array();
+ unset($this->seq);
+ unset($this->in_seq);
+ unset($this->lcs);
+
+ // Skip leading common lines.
+ for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
+ if ($from_lines[$skip] !== $to_lines[$skip]) {
+ break;
+ }
+ $this->xchanged[$skip] = $this->ychanged[$skip] = false;
+ }
+
+ // Skip trailing common lines.
+ $xi = $n_from; $yi = $n_to;
+ for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
+ if ($from_lines[$xi] !== $to_lines[$yi]) {
+ break;
+ }
+ $this->xchanged[$xi] = $this->ychanged[$yi] = false;
+ }
+
+ // Ignore lines which do not exist in both files.
+ for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+ $xhash[$from_lines[$xi]] = 1;
+ }
+ for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
+ $line = $to_lines[$yi];
+ if (($this->ychanged[$yi] = empty($xhash[$line]))) {
+ continue;
+ }
+ $yhash[$line] = 1;
+ $this->yv[] = $line;
+ $this->yind[] = $yi;
+ }
+ for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+ $line = $from_lines[$xi];
+ if (($this->xchanged[$xi] = empty($yhash[$line]))) {
+ continue;
+ }
+ $this->xv[] = $line;
+ $this->xind[] = $xi;
+ }
+
+ // Find the LCS.
+ $this->_compareseq(0, count($this->xv), 0, count($this->yv));
+
+ // Merge edits when possible.
+ $this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
+ $this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
+
+ // Compute the edit operations.
+ $edits = array();
+ $xi = $yi = 0;
+ while ($xi < $n_from || $yi < $n_to) {
+ assert($yi < $n_to || $this->xchanged[$xi]);
+ assert($xi < $n_from || $this->ychanged[$yi]);
+
+ // Skip matching "snake".
+ $copy = array();
+ while ($xi < $n_from && $yi < $n_to
+ && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
+ $copy[] = $from_lines[$xi++];
+ ++$yi;
+ }
+ if ($copy) {
+ $edits[] = &new Text_Diff_Op_copy($copy);
+ }
+
+ // Find deletes & adds.
+ $delete = array();
+ while ($xi < $n_from && $this->xchanged[$xi]) {
+ $delete[] = $from_lines[$xi++];
+ }
+
+ $add = array();
+ while ($yi < $n_to && $this->ychanged[$yi]) {
+ $add[] = $to_lines[$yi++];
+ }
+
+ if ($delete && $add) {
+ $edits[] = &new Text_Diff_Op_change($delete, $add);
+ } elseif ($delete) {
+ $edits[] = &new Text_Diff_Op_delete($delete);
+ } elseif ($add) {
+ $edits[] = &new Text_Diff_Op_add($add);
+ }
+ }
+
+ return $edits;
+ }
+
+ /**
+ * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
+ * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
+ * segments.
+ *
+ * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of
+ * NCHUNKS+1 (X, Y) indexes giving the diving points between sub
+ * sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1),
+ * the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) ==
+ * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
+ *
+ * This function assumes that the first lines of the specified portions of
+ * the two files do not match, and likewise that the last lines do not
+ * match. The caller must trim matching lines from the beginning and end
+ * of the portions it is going to specify.
+ */
+ function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
+ {
+ $flip = false;
+
+ if ($xlim - $xoff > $ylim - $yoff) {
+ /* Things seems faster (I'm not sure I understand why) when the
+ * shortest sequence is in X. */
+ $flip = true;
+ list ($xoff, $xlim, $yoff, $ylim)
+ = array($yoff, $ylim, $xoff, $xlim);
+ }
+
+ if ($flip) {
+ for ($i = $ylim - 1; $i >= $yoff; $i--) {
+ $ymatches[$this->xv[$i]][] = $i;
+ }
+ } else {
+ for ($i = $ylim - 1; $i >= $yoff; $i--) {
+ $ymatches[$this->yv[$i]][] = $i;
+ }
+ }
+
+ $this->lcs = 0;
+ $this->seq[0]= $yoff - 1;
+ $this->in_seq = array();
+ $ymids[0] = array();
+
+ $numer = $xlim - $xoff + $nchunks - 1;
+ $x = $xoff;
+ for ($chunk = 0; $chunk < $nchunks; $chunk++) {
+ if ($chunk > 0) {
+ for ($i = 0; $i <= $this->lcs; $i++) {
+ $ymids[$i][$chunk - 1] = $this->seq[$i];
+ }
+ }
+
+ $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks);
+ for (; $x < $x1; $x++) {
+ $line = $flip ? $this->yv[$x] : $this->xv[$x];
+ if (empty($ymatches[$line])) {
+ continue;
+ }
+ $matches = $ymatches[$line];
+ reset($matches);
+ while (list(, $y) = each($matches)) {
+ if (empty($this->in_seq[$y])) {
+ $k = $this->_lcsPos($y);
+ assert($k > 0);
+ $ymids[$k] = $ymids[$k - 1];
+ break;
+ }
+ }
+ while (list(, $y) = each($matches)) {
+ if ($y > $this->seq[$k - 1]) {
+ assert($y <= $this->seq[$k]);
+ /* Optimization: this is a common case: next match is
+ * just replacing previous match. */
+ $this->in_seq[$this->seq[$k]] = false;
+ $this->seq[$k] = $y;
+ $this->in_seq[$y] = 1;
+ } elseif (empty($this->in_seq[$y])) {
+ $k = $this->_lcsPos($y);
+ assert($k > 0);
+ $ymids[$k] = $ymids[$k - 1];
+ }
+ }
+ }
+ }
+
+ $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
+ $ymid = $ymids[$this->lcs];
+ for ($n = 0; $n < $nchunks - 1; $n++) {
+ $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
+ $y1 = $ymid[$n] + 1;
+ $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
+ }
+ $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
+
+ return array($this->lcs, $seps);
+ }
+
+ function _lcsPos($ypos)
+ {
+ $end = $this->lcs;
+ if ($end == 0 || $ypos > $this->seq[$end]) {
+ $this->seq[++$this->lcs] = $ypos;
+ $this->in_seq[$ypos] = 1;
+ return $this->lcs;
+ }
+
+ $beg = 1;
+ while ($beg < $end) {
+ $mid = (int)(($beg + $end) / 2);
+ if ($ypos > $this->seq[$mid]) {
+ $beg = $mid + 1;
+ } else {
+ $end = $mid;
+ }
+ }
+
+ assert($ypos != $this->seq[$end]);
+
+ $this->in_seq[$this->seq[$end]] = false;
+ $this->seq[$end] = $ypos;
+ $this->in_seq[$ypos] = 1;
+ return $end;
+ }
+
+ /**
+ * Finds LCS of two sequences.
+ *
+ * The results are recorded in the vectors $this->{x,y}changed[], by
+ * storing a 1 in the element for each line that is an insertion or
+ * deletion (ie. is not in the LCS).
+ *
+ * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
+ *
+ * Note that XLIM, YLIM are exclusive bounds. All line numbers are
+ * origin-0 and discarded lines are not counted.
+ */
+ function _compareseq ($xoff, $xlim, $yoff, $ylim)
+ {
+ /* Slide down the bottom initial diagonal. */
+ while ($xoff < $xlim && $yoff < $ylim
+ && $this->xv[$xoff] == $this->yv[$yoff]) {
+ ++$xoff;
+ ++$yoff;
+ }
+
+ /* Slide up the top initial diagonal. */
+ while ($xlim > $xoff && $ylim > $yoff
+ && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
+ --$xlim;
+ --$ylim;
+ }
+
+ if ($xoff == $xlim || $yoff == $ylim) {
+ $lcs = 0;
+ } else {
+ /* This is ad hoc but seems to work well. $nchunks =
+ * sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
+ * max(2,min(8,(int)$nchunks)); */
+ $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
+ list($lcs, $seps)
+ = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
+ }
+
+ if ($lcs == 0) {
+ /* X and Y sequences have no common subsequence: mark all
+ * changed. */
+ while ($yoff < $ylim) {
+ $this->ychanged[$this->yind[$yoff++]] = 1;
+ }
+ while ($xoff < $xlim) {
+ $this->xchanged[$this->xind[$xoff++]] = 1;
+ }
+ } else {
+ /* Use the partitions to split this problem into subproblems. */
+ reset($seps);
+ $pt1 = $seps[0];
+ while ($pt2 = next($seps)) {
+ $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
+ $pt1 = $pt2;
+ }
+ }
+ }
+
+ /**
+ * Adjusts inserts/deletes of identical lines to join changes as much as
+ * possible.
+ *
+ * We do something when a run of changed lines include a line at one end
+ * and has an excluded, identical line at the other. We are free to
+ * choose which identical line is included. `compareseq' usually chooses
+ * the one at the beginning, but usually it is cleaner to consider the
+ * following identical line to be the "change".
+ *
+ * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
+ */
+ function _shiftBoundaries($lines, &$changed, $other_changed)
+ {
+ $i = 0;
+ $j = 0;
+
+ assert('count($lines) == count($changed)');
+ $len = count($lines);
+ $other_len = count($other_changed);
+
+ while (1) {
+ /* Scan forward to find the beginning of another run of
+ * changes. Also keep track of the corresponding point in the
+ * other file.
+ *
+ * Throughout this code, $i and $j are adjusted together so that
+ * the first $i elements of $changed and the first $j elements of
+ * $other_changed both contain the same number of zeros (unchanged
+ * lines).
+ *
+ * Furthermore, $j is always kept so that $j == $other_len or
+ * $other_changed[$j] == false. */
+ while ($j < $other_len && $other_changed[$j]) {
+ $j++;
+ }
+
+ while ($i < $len && ! $changed[$i]) {
+ assert('$j < $other_len && ! $other_changed[$j]');
+ $i++; $j++;
+ while ($j < $other_len && $other_changed[$j]) {
+ $j++;
+ }
+ }
+
+ if ($i == $len) {
+ break;
+ }
+
+ $start = $i;
+
+ /* Find the end of this run of changes. */
+ while (++$i < $len && $changed[$i]) {
+ continue;
+ }
+
+ do {
+ /* Record the length of this run of changes, so that we can
+ * later determine whether the run has grown. */
+ $runlength = $i - $start;
+
+ /* Move the changed region back, so long as the previous
+ * unchanged line matches the last changed one. This merges
+ * with previous changed regions. */
+ while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
+ $changed[--$start] = 1;
+ $changed[--$i] = false;
+ while ($start > 0 && $changed[$start - 1]) {
+ $start--;
+ }
+ assert('$j > 0');
+ while ($other_changed[--$j]) {
+ continue;
+ }
+ assert('$j >= 0 && !$other_changed[$j]');
+ }
+
+ /* Set CORRESPONDING to the end of the changed run, at the
+ * last point where it corresponds to a changed run in the
+ * other file. CORRESPONDING == LEN means no such point has
+ * been found. */
+ $corresponding = $j < $other_len ? $i : $len;
+
+ /* Move the changed region forward, so long as the first
+ * changed line matches the following unchanged one. This
+ * merges with following changed regions. Do this second, so
+ * that if there are no merges, the changed region is moved
+ * forward as far as possible. */
+ while ($i < $len && $lines[$start] == $lines[$i]) {
+ $changed[$start++] = false;
+ $changed[$i++] = 1;
+ while ($i < $len && $changed[$i]) {
+ $i++;
+ }
+
+ assert('$j < $other_len && ! $other_changed[$j]');
+ $j++;
+ if ($j < $other_len && $other_changed[$j]) {
+ $corresponding = $i;
+ while ($j < $other_len && $other_changed[$j]) {
+ $j++;
+ }
+ }
+ }
+ } while ($runlength != $i - $start);
+
+ /* If possible, move the fully-merged run of changes back to a
+ * corresponding run in the other file. */
+ while ($corresponding < $i) {
+ $changed[--$start] = 1;
+ $changed[--$i] = 0;
+ assert('$j > 0');
+ while ($other_changed[--$j]) {
+ continue;
+ }
+ assert('$j >= 0 && !$other_changed[$j]');
+ }
+ }
+ }
+
+}
diff -uNr a/blog/wp-includes/Text/Diff/Engine/shell.php b/blog/wp-includes/Text/Diff/Engine/shell.php
--- a/blog/wp-includes/Text/Diff/Engine/shell.php false
+++ b/blog/wp-includes/Text/Diff/Engine/shell.php 71282251069fdbbb4de5f0abbaf5b4c42dcaaafbb9ad15709f7b662f81ad8fbc6ae8682e7d3234673458bf039ff0f421af84165717804a1245e95ac896d1efc3
@@ -0,0 +1,164 @@
+
+ * @package Text_Diff
+ * @since 0.3.0
+ */
+class Text_Diff_Engine_shell {
+
+ /**
+ * Path to the diff executable
+ *
+ * @var string
+ */
+ var $_diffCommand = 'diff';
+
+ /**
+ * Returns the array of differences.
+ *
+ * @param array $from_lines lines of text from old file
+ * @param array $to_lines lines of text from new file
+ *
+ * @return array all changes made (array with Text_Diff_Op_* objects)
+ */
+ function diff($from_lines, $to_lines)
+ {
+ array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+ array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+ $temp_dir = Text_Diff::_getTempDir();
+
+ // Execute gnu diff or similar to get a standard diff file.
+ $from_file = tempnam($temp_dir, 'Text_Diff');
+ $to_file = tempnam($temp_dir, 'Text_Diff');
+ $fp = fopen($from_file, 'w');
+ fwrite($fp, implode("\n", $from_lines));
+ fclose($fp);
+ $fp = fopen($to_file, 'w');
+ fwrite($fp, implode("\n", $to_lines));
+ fclose($fp);
+ $diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);
+ unlink($from_file);
+ unlink($to_file);
+
+ if (is_null($diff)) {
+ // No changes were made
+ return array(new Text_Diff_Op_copy($from_lines));
+ }
+
+ $from_line_no = 1;
+ $to_line_no = 1;
+ $edits = array();
+
+ // Get changed lines by parsing something like:
+ // 0a1,2
+ // 1,2c4,6
+ // 1,5d6
+ preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,
+ $matches, PREG_SET_ORDER);
+
+ foreach ($matches as $match) {
+ if (!isset($match[5])) {
+ // This paren is not set every time (see regex).
+ $match[5] = false;
+ }
+
+ if ($match[3] == 'a') {
+ $from_line_no--;
+ }
+
+ if ($match[3] == 'd') {
+ $to_line_no--;
+ }
+
+ if ($from_line_no < $match[1] || $to_line_no < $match[4]) {
+ // copied lines
+ assert('$match[1] - $from_line_no == $match[4] - $to_line_no');
+ array_push($edits,
+ new Text_Diff_Op_copy(
+ $this->_getLines($from_lines, $from_line_no, $match[1] - 1),
+ $this->_getLines($to_lines, $to_line_no, $match[4] - 1)));
+ }
+
+ switch ($match[3]) {
+ case 'd':
+ // deleted lines
+ array_push($edits,
+ new Text_Diff_Op_delete(
+ $this->_getLines($from_lines, $from_line_no, $match[2])));
+ $to_line_no++;
+ break;
+
+ case 'c':
+ // changed lines
+ array_push($edits,
+ new Text_Diff_Op_change(
+ $this->_getLines($from_lines, $from_line_no, $match[2]),
+ $this->_getLines($to_lines, $to_line_no, $match[5])));
+ break;
+
+ case 'a':
+ // added lines
+ array_push($edits,
+ new Text_Diff_Op_add(
+ $this->_getLines($to_lines, $to_line_no, $match[5])));
+ $from_line_no++;
+ break;
+ }
+ }
+
+ if (!empty($from_lines)) {
+ // Some lines might still be pending. Add them as copied
+ array_push($edits,
+ new Text_Diff_Op_copy(
+ $this->_getLines($from_lines, $from_line_no,
+ $from_line_no + count($from_lines) - 1),
+ $this->_getLines($to_lines, $to_line_no,
+ $to_line_no + count($to_lines) - 1)));
+ }
+
+ return $edits;
+ }
+
+ /**
+ * Get lines from either the old or new text
+ *
+ * @access private
+ *
+ * @param array &$text_lines Either $from_lines or $to_lines
+ * @param int &$line_no Current line number
+ * @param int $end Optional end line, when we want to chop more
+ * than one line.
+ *
+ * @return array The chopped lines
+ */
+ function _getLines(&$text_lines, &$line_no, $end = false)
+ {
+ if (!empty($end)) {
+ $lines = array();
+ // We can shift even more
+ while ($line_no <= $end) {
+ array_push($lines, array_shift($text_lines));
+ $line_no++;
+ }
+ } else {
+ $lines = array(array_shift($text_lines));
+ $line_no++;
+ }
+
+ return $lines;
+ }
+
+}
diff -uNr a/blog/wp-includes/Text/Diff/Engine/string.php b/blog/wp-includes/Text/Diff/Engine/string.php
--- a/blog/wp-includes/Text/Diff/Engine/string.php false
+++ b/blog/wp-includes/Text/Diff/Engine/string.php 123da2a8096692f8af148ea72159f79ed6fa5181ad7625073c9db70a27ffe076ff392c9f06f79d79e6c72f3c2112a8706bf0ce9057305a8b0af434dbc87a36a4
@@ -0,0 +1,234 @@
+
+ * $patch = file_get_contents('example.patch');
+ * $diff = new Text_Diff('string', array($patch));
+ * $renderer = new Text_Diff_Renderer_inline();
+ * echo $renderer->render($diff);
+ *
+ *
+ * $Horde: framework/Text_Diff/Diff/Engine/string.php,v 1.7 2008/01/04 10:07:50 jan Exp $
+ *
+ * Copyright 2005 Örjan Persson
+ * Copyright 2005-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @author Örjan Persson
+ * @package Text_Diff
+ * @since 0.2.0
+ */
+class Text_Diff_Engine_string {
+
+ /**
+ * Parses a unified or context diff.
+ *
+ * First param contains the whole diff and the second can be used to force
+ * a specific diff type. If the second parameter is 'autodetect', the
+ * diff will be examined to find out which type of diff this is.
+ *
+ * @param string $diff The diff content.
+ * @param string $mode The diff mode of the content in $diff. One of
+ * 'context', 'unified', or 'autodetect'.
+ *
+ * @return array List of all diff operations.
+ */
+ function diff($diff, $mode = 'autodetect')
+ {
+ if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
+ return PEAR::raiseError('Type of diff is unsupported');
+ }
+
+ if ($mode == 'autodetect') {
+ $context = strpos($diff, '***');
+ $unified = strpos($diff, '---');
+ if ($context === $unified) {
+ return PEAR::raiseError('Type of diff could not be detected');
+ } elseif ($context === false || $context === false) {
+ $mode = $context !== false ? 'context' : 'unified';
+ } else {
+ $mode = $context < $unified ? 'context' : 'unified';
+ }
+ }
+
+ // split by new line and remove the diff header
+ $diff = explode("\n", $diff);
+ array_shift($diff);
+ array_shift($diff);
+
+ if ($mode == 'context') {
+ return $this->parseContextDiff($diff);
+ } else {
+ return $this->parseUnifiedDiff($diff);
+ }
+ }
+
+ /**
+ * Parses an array containing the unified diff.
+ *
+ * @param array $diff Array of lines.
+ *
+ * @return array List of all diff operations.
+ */
+ function parseUnifiedDiff($diff)
+ {
+ $edits = array();
+ $end = count($diff) - 1;
+ for ($i = 0; $i < $end;) {
+ $diff1 = array();
+ switch (substr($diff[$i], 0, 1)) {
+ case ' ':
+ do {
+ $diff1[] = substr($diff[$i], 1);
+ } while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
+ $edits[] = &new Text_Diff_Op_copy($diff1);
+ break;
+
+ case '+':
+ // get all new lines
+ do {
+ $diff1[] = substr($diff[$i], 1);
+ } while (++$i < $end && substr($diff[$i], 0, 1) == '+');
+ $edits[] = &new Text_Diff_Op_add($diff1);
+ break;
+
+ case '-':
+ // get changed or removed lines
+ $diff2 = array();
+ do {
+ $diff1[] = substr($diff[$i], 1);
+ } while (++$i < $end && substr($diff[$i], 0, 1) == '-');
+
+ while ($i < $end && substr($diff[$i], 0, 1) == '+') {
+ $diff2[] = substr($diff[$i++], 1);
+ }
+ if (count($diff2) == 0) {
+ $edits[] = &new Text_Diff_Op_delete($diff1);
+ } else {
+ $edits[] = &new Text_Diff_Op_change($diff1, $diff2);
+ }
+ break;
+
+ default:
+ $i++;
+ break;
+ }
+ }
+
+ return $edits;
+ }
+
+ /**
+ * Parses an array containing the context diff.
+ *
+ * @param array $diff Array of lines.
+ *
+ * @return array List of all diff operations.
+ */
+ function parseContextDiff(&$diff)
+ {
+ $edits = array();
+ $i = $max_i = $j = $max_j = 0;
+ $end = count($diff) - 1;
+ while ($i < $end && $j < $end) {
+ while ($i >= $max_i && $j >= $max_j) {
+ // Find the boundaries of the diff output of the two files
+ for ($i = $j;
+ $i < $end && substr($diff[$i], 0, 3) == '***';
+ $i++);
+ for ($max_i = $i;
+ $max_i < $end && substr($diff[$max_i], 0, 3) != '---';
+ $max_i++);
+ for ($j = $max_i;
+ $j < $end && substr($diff[$j], 0, 3) == '---';
+ $j++);
+ for ($max_j = $j;
+ $max_j < $end && substr($diff[$max_j], 0, 3) != '***';
+ $max_j++);
+ }
+
+ // find what hasn't been changed
+ $array = array();
+ while ($i < $max_i &&
+ $j < $max_j &&
+ strcmp($diff[$i], $diff[$j]) == 0) {
+ $array[] = substr($diff[$i], 2);
+ $i++;
+ $j++;
+ }
+
+ while ($i < $max_i && ($max_j-$j) <= 1) {
+ if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
+ break;
+ }
+ $array[] = substr($diff[$i++], 2);
+ }
+
+ while ($j < $max_j && ($max_i-$i) <= 1) {
+ if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
+ break;
+ }
+ $array[] = substr($diff[$j++], 2);
+ }
+ if (count($array) > 0) {
+ $edits[] = &new Text_Diff_Op_copy($array);
+ }
+
+ if ($i < $max_i) {
+ $diff1 = array();
+ switch (substr($diff[$i], 0, 1)) {
+ case '!':
+ $diff2 = array();
+ do {
+ $diff1[] = substr($diff[$i], 2);
+ if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
+ $diff2[] = substr($diff[$j++], 2);
+ }
+ } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
+ $edits[] = &new Text_Diff_Op_change($diff1, $diff2);
+ break;
+
+ case '+':
+ do {
+ $diff1[] = substr($diff[$i], 2);
+ } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
+ $edits[] = &new Text_Diff_Op_add($diff1);
+ break;
+
+ case '-':
+ do {
+ $diff1[] = substr($diff[$i], 2);
+ } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
+ $edits[] = &new Text_Diff_Op_delete($diff1);
+ break;
+ }
+ }
+
+ if ($j < $max_j) {
+ $diff2 = array();
+ switch (substr($diff[$j], 0, 1)) {
+ case '+':
+ do {
+ $diff2[] = substr($diff[$j++], 2);
+ } while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
+ $edits[] = &new Text_Diff_Op_add($diff2);
+ break;
+
+ case '-':
+ do {
+ $diff2[] = substr($diff[$j++], 2);
+ } while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
+ $edits[] = &new Text_Diff_Op_delete($diff2);
+ break;
+ }
+ }
+ }
+
+ return $edits;
+ }
+
+}
diff -uNr a/blog/wp-includes/Text/Diff/Engine/xdiff.php b/blog/wp-includes/Text/Diff/Engine/xdiff.php
--- a/blog/wp-includes/Text/Diff/Engine/xdiff.php false
+++ b/blog/wp-includes/Text/Diff/Engine/xdiff.php 114d30a89c71be07083ad2751b1c11d5d049517bcbe5c8ffeb94b359aa12123da43abe687e7480413fada7ad36701f97b3da4cea6b703d3ff6c39a7ad4397285
@@ -0,0 +1,63 @@
+
+ * @package Text_Diff
+ */
+class Text_Diff_Engine_xdiff {
+
+ /**
+ */
+ function diff($from_lines, $to_lines)
+ {
+ array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+ array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+ /* Convert the two input arrays into strings for xdiff processing. */
+ $from_string = implode("\n", $from_lines);
+ $to_string = implode("\n", $to_lines);
+
+ /* Diff the two strings and convert the result to an array. */
+ $diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
+ $diff = explode("\n", $diff);
+
+ /* Walk through the diff one line at a time. We build the $edits
+ * array of diff operations by reading the first character of the
+ * xdiff output (which is in the "unified diff" format).
+ *
+ * Note that we don't have enough information to detect "changed"
+ * lines using this approach, so we can't add Text_Diff_Op_changed
+ * instances to the $edits array. The result is still perfectly
+ * valid, albeit a little less descriptive and efficient. */
+ $edits = array();
+ foreach ($diff as $line) {
+ switch ($line[0]) {
+ case ' ':
+ $edits[] = &new Text_Diff_Op_copy(array(substr($line, 1)));
+ break;
+
+ case '+':
+ $edits[] = &new Text_Diff_Op_add(array(substr($line, 1)));
+ break;
+
+ case '-':
+ $edits[] = &new Text_Diff_Op_delete(array(substr($line, 1)));
+ break;
+ }
+ }
+
+ return $edits;
+ }
+
+}
diff -uNr a/blog/wp-includes/Text/Diff/index.php b/blog/wp-includes/Text/Diff/index.php
--- a/blog/wp-includes/Text/Diff/index.php false
+++ b/blog/wp-includes/Text/Diff/index.php 099fbcf9478701c433aa576bbcc0cec1987ebf948f13220182da7dc8711b448daddf9ea289b9e8ea4288757f913c64f5f06eb5011e16d4d23592aae16800adb0
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff -uNr a/blog/wp-includes/Text/Diff/Renderer/index.php b/blog/wp-includes/Text/Diff/Renderer/index.php
--- a/blog/wp-includes/Text/Diff/Renderer/index.php false
+++ b/blog/wp-includes/Text/Diff/Renderer/index.php 099fbcf9478701c433aa576bbcc0cec1987ebf948f13220182da7dc8711b448daddf9ea289b9e8ea4288757f913c64f5f06eb5011e16d4d23592aae16800adb0
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff -uNr a/blog/wp-includes/Text/Diff/Renderer/inline.php b/blog/wp-includes/Text/Diff/Renderer/inline.php
--- a/blog/wp-includes/Text/Diff/Renderer/inline.php false
+++ b/blog/wp-includes/Text/Diff/Renderer/inline.php eba60815093eeca5bc4adc4f472417b4aece9beced951f2fe01146e19dc6b295728cd254598a0e611de6df330f2443d7e90d500174a032db6b05667814d2c39a
@@ -0,0 +1,172 @@
+';
+
+ /**
+ * Suffix for inserted text.
+ */
+ var $_ins_suffix = '';
+
+ /**
+ * Prefix for deleted text.
+ */
+ var $_del_prefix = '';
+
+ /**
+ * Suffix for deleted text.
+ */
+ var $_del_suffix = '';
+
+ /**
+ * Header for each change block.
+ */
+ var $_block_header = '';
+
+ /**
+ * What are we currently splitting on? Used to recurse to show word-level
+ * changes.
+ */
+ var $_split_level = 'lines';
+
+ function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+ {
+ return $this->_block_header;
+ }
+
+ function _startBlock($header)
+ {
+ return $header;
+ }
+
+ function _lines($lines, $prefix = ' ', $encode = true)
+ {
+ if ($encode) {
+ array_walk($lines, array(&$this, '_encode'));
+ }
+
+ if ($this->_split_level == 'words') {
+ return implode('', $lines);
+ } else {
+ return implode("\n", $lines) . "\n";
+ }
+ }
+
+ function _added($lines)
+ {
+ array_walk($lines, array(&$this, '_encode'));
+ $lines[0] = $this->_ins_prefix . $lines[0];
+ $lines[count($lines) - 1] .= $this->_ins_suffix;
+ return $this->_lines($lines, ' ', false);
+ }
+
+ function _deleted($lines, $words = false)
+ {
+ array_walk($lines, array(&$this, '_encode'));
+ $lines[0] = $this->_del_prefix . $lines[0];
+ $lines[count($lines) - 1] .= $this->_del_suffix;
+ return $this->_lines($lines, ' ', false);
+ }
+
+ function _changed($orig, $final)
+ {
+ /* If we've already split on words, don't try to do so again - just
+ * display. */
+ if ($this->_split_level == 'words') {
+ $prefix = '';
+ while ($orig[0] !== false && $final[0] !== false &&
+ substr($orig[0], 0, 1) == ' ' &&
+ substr($final[0], 0, 1) == ' ') {
+ $prefix .= substr($orig[0], 0, 1);
+ $orig[0] = substr($orig[0], 1);
+ $final[0] = substr($final[0], 1);
+ }
+ return $prefix . $this->_deleted($orig) . $this->_added($final);
+ }
+
+ $text1 = implode("\n", $orig);
+ $text2 = implode("\n", $final);
+
+ /* Non-printing newline marker. */
+ $nl = "\0";
+
+ /* We want to split on word boundaries, but we need to
+ * preserve whitespace as well. Therefore we split on words,
+ * but include all blocks of whitespace in the wordlist. */
+ $diff = new Text_Diff($this->_splitOnWords($text1, $nl),
+ $this->_splitOnWords($text2, $nl));
+
+ /* Get the diff in inline format. */
+ $renderer = new Text_Diff_Renderer_inline(array_merge($this->getParams(),
+ array('split_level' => 'words')));
+
+ /* Run the diff and get the output. */
+ return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
+ }
+
+ function _splitOnWords($string, $newlineEscape = "\n")
+ {
+ // Ignore \0; otherwise the while loop will never finish.
+ $string = str_replace("\0", '', $string);
+
+ $words = array();
+ $length = strlen($string);
+ $pos = 0;
+
+ while ($pos < $length) {
+ // Eat a word with any preceding whitespace.
+ $spaces = strspn(substr($string, $pos), " \n");
+ $nextpos = strcspn(substr($string, $pos + $spaces), " \n");
+ $words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
+ $pos += $spaces + $nextpos;
+ }
+
+ return $words;
+ }
+
+ function _encode(&$string)
+ {
+ $string = htmlspecialchars($string);
+ }
+
+}
diff -uNr a/blog/wp-includes/Text/Diff/Renderer.php b/blog/wp-includes/Text/Diff/Renderer.php
--- a/blog/wp-includes/Text/Diff/Renderer.php false
+++ b/blog/wp-includes/Text/Diff/Renderer.php d4c2df2669e35a48516974d397646d08a63099982055eb1defe3548b51ac301f11cf3ada1c65c4b438be2e9078cb75126ca9b0cf7c75c5b2d2f8f1ad873245b4
@@ -0,0 +1,237 @@
+ $value) {
+ $v = '_' . $param;
+ if (isset($this->$v)) {
+ $this->$v = $value;
+ }
+ }
+ }
+
+ /**
+ * Get any renderer parameters.
+ *
+ * @return array All parameters of this renderer object.
+ */
+ function getParams()
+ {
+ $params = array();
+ foreach (get_object_vars($this) as $k => $v) {
+ if ($k[0] == '_') {
+ $params[substr($k, 1)] = $v;
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Renders a diff.
+ *
+ * @param Text_Diff $diff A Text_Diff object.
+ *
+ * @return string The formatted output.
+ */
+ function render($diff)
+ {
+ $xi = $yi = 1;
+ $block = false;
+ $context = array();
+
+ $nlead = $this->_leading_context_lines;
+ $ntrail = $this->_trailing_context_lines;
+
+ $output = $this->_startDiff();
+
+ $diffs = $diff->getDiff();
+ foreach ($diffs as $i => $edit) {
+ /* If these are unchanged (copied) lines, and we want to keep
+ * leading or trailing context lines, extract them from the copy
+ * block. */
+ if (is_a($edit, 'Text_Diff_Op_copy')) {
+ /* Do we have any diff blocks yet? */
+ if (is_array($block)) {
+ /* How many lines to keep as context from the copy
+ * block. */
+ $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
+ if (count($edit->orig) <= $keep) {
+ /* We have less lines in the block than we want for
+ * context => keep the whole block. */
+ $block[] = $edit;
+ } else {
+ if ($ntrail) {
+ /* Create a new block with as many lines as we need
+ * for the trailing context. */
+ $context = array_slice($edit->orig, 0, $ntrail);
+ $block[] = &new Text_Diff_Op_copy($context);
+ }
+ /* @todo */
+ $output .= $this->_block($x0, $ntrail + $xi - $x0,
+ $y0, $ntrail + $yi - $y0,
+ $block);
+ $block = false;
+ }
+ }
+ /* Keep the copy block as the context for the next block. */
+ $context = $edit->orig;
+ } else {
+ /* Don't we have any diff blocks yet? */
+ if (!is_array($block)) {
+ /* Extract context lines from the preceding copy block. */
+ $context = array_slice($context, count($context) - $nlead);
+ $x0 = $xi - count($context);
+ $y0 = $yi - count($context);
+ $block = array();
+ if ($context) {
+ $block[] = &new Text_Diff_Op_copy($context);
+ }
+ }
+ $block[] = $edit;
+ }
+
+ if ($edit->orig) {
+ $xi += count($edit->orig);
+ }
+ if ($edit->final) {
+ $yi += count($edit->final);
+ }
+ }
+
+ if (is_array($block)) {
+ $output .= $this->_block($x0, $xi - $x0,
+ $y0, $yi - $y0,
+ $block);
+ }
+
+ return $output . $this->_endDiff();
+ }
+
+ function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
+ {
+ $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
+
+ foreach ($edits as $edit) {
+ switch (strtolower(get_class($edit))) {
+ case 'text_diff_op_copy':
+ $output .= $this->_context($edit->orig);
+ break;
+
+ case 'text_diff_op_add':
+ $output .= $this->_added($edit->final);
+ break;
+
+ case 'text_diff_op_delete':
+ $output .= $this->_deleted($edit->orig);
+ break;
+
+ case 'text_diff_op_change':
+ $output .= $this->_changed($edit->orig, $edit->final);
+ break;
+ }
+ }
+
+ return $output . $this->_endBlock();
+ }
+
+ function _startDiff()
+ {
+ return '';
+ }
+
+ function _endDiff()
+ {
+ return '';
+ }
+
+ function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+ {
+ if ($xlen > 1) {
+ $xbeg .= ',' . ($xbeg + $xlen - 1);
+ }
+ if ($ylen > 1) {
+ $ybeg .= ',' . ($ybeg + $ylen - 1);
+ }
+
+ // this matches the GNU Diff behaviour
+ if ($xlen && !$ylen) {
+ $ybeg--;
+ } elseif (!$xlen) {
+ $xbeg--;
+ }
+
+ return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
+ }
+
+ function _startBlock($header)
+ {
+ return $header . "\n";
+ }
+
+ function _endBlock()
+ {
+ return '';
+ }
+
+ function _lines($lines, $prefix = ' ')
+ {
+ return $prefix . implode("\n$prefix", $lines) . "\n";
+ }
+
+ function _context($lines)
+ {
+ return $this->_lines($lines, ' ');
+ }
+
+ function _added($lines)
+ {
+ return $this->_lines($lines, '> ');
+ }
+
+ function _deleted($lines)
+ {
+ return $this->_lines($lines, '< ');
+ }
+
+ function _changed($orig, $final)
+ {
+ return $this->_deleted($orig) . "---\n" . $this->_added($final);
+ }
+
+}
diff -uNr a/blog/wp-includes/Text/Diff.php b/blog/wp-includes/Text/Diff.php
--- a/blog/wp-includes/Text/Diff.php false
+++ b/blog/wp-includes/Text/Diff.php 04daab7d9b5ec2fe110bf11a5e290f8310e13a24723e8299078eceb84182e4fc24fb658fe7d0b7f80c9c9f6136ac206951e05eef317afa608c197b17767a6398
@@ -0,0 +1,414 @@
+, and is used/adapted with his permission.
+ *
+ * $Horde: framework/Text_Diff/Diff.php,v 1.26 2008/01/04 10:07:49 jan Exp $
+ *
+ * Copyright 2004 Geoffrey T. Dairiki
+ * Copyright 2004-2008 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki
+ */
+class Text_Diff {
+
+ /**
+ * Array of changes.
+ *
+ * @var array
+ */
+ var $_edits;
+
+ /**
+ * Computes diffs between sequences of strings.
+ *
+ * @param string $engine Name of the diffing engine to use. 'auto'
+ * will automatically select the best.
+ * @param array $params Parameters to pass to the diffing engine.
+ * Normally an array of two arrays, each
+ * containing the lines from a file.
+ */
+ function Text_Diff($engine, $params)
+ {
+ // Backward compatibility workaround.
+ if (!is_string($engine)) {
+ $params = array($engine, $params);
+ $engine = 'auto';
+ }
+
+ if ($engine == 'auto') {
+ $engine = extension_loaded('xdiff') ? 'xdiff' : 'native';
+ } else {
+ $engine = basename($engine);
+ }
+
+ // WP #7391
+ require_once dirname(__FILE__).'/Diff/Engine/' . $engine . '.php';
+ $class = 'Text_Diff_Engine_' . $engine;
+ $diff_engine = new $class();
+
+ $this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params);
+ }
+
+ /**
+ * Returns the array of differences.
+ */
+ function getDiff()
+ {
+ return $this->_edits;
+ }
+
+ /**
+ * Computes a reversed diff.
+ *
+ * Example:
+ *
+ * $diff = new Text_Diff($lines1, $lines2);
+ * $rev = $diff->reverse();
+ *
+ *
+ * @return Text_Diff A Diff object representing the inverse of the
+ * original diff. Note that we purposely don't return a
+ * reference here, since this essentially is a clone()
+ * method.
+ */
+ function reverse()
+ {
+ if (version_compare(zend_version(), '2', '>')) {
+ $rev = clone($this);
+ } else {
+ $rev = $this;
+ }
+ $rev->_edits = array();
+ foreach ($this->_edits as $edit) {
+ $rev->_edits[] = $edit->reverse();
+ }
+ return $rev;
+ }
+
+ /**
+ * Checks for an empty diff.
+ *
+ * @return boolean True if two sequences were identical.
+ */
+ function isEmpty()
+ {
+ foreach ($this->_edits as $edit) {
+ if (!is_a($edit, 'Text_Diff_Op_copy')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Computes the length of the Longest Common Subsequence (LCS).
+ *
+ * This is mostly for diagnostic purposes.
+ *
+ * @return integer The length of the LCS.
+ */
+ function lcs()
+ {
+ $lcs = 0;
+ foreach ($this->_edits as $edit) {
+ if (is_a($edit, 'Text_Diff_Op_copy')) {
+ $lcs += count($edit->orig);
+ }
+ }
+ return $lcs;
+ }
+
+ /**
+ * Gets the original set of lines.
+ *
+ * This reconstructs the $from_lines parameter passed to the constructor.
+ *
+ * @return array The original sequence of strings.
+ */
+ function getOriginal()
+ {
+ $lines = array();
+ foreach ($this->_edits as $edit) {
+ if ($edit->orig) {
+ array_splice($lines, count($lines), 0, $edit->orig);
+ }
+ }
+ return $lines;
+ }
+
+ /**
+ * Gets the final set of lines.
+ *
+ * This reconstructs the $to_lines parameter passed to the constructor.
+ *
+ * @return array The sequence of strings.
+ */
+ function getFinal()
+ {
+ $lines = array();
+ foreach ($this->_edits as $edit) {
+ if ($edit->final) {
+ array_splice($lines, count($lines), 0, $edit->final);
+ }
+ }
+ return $lines;
+ }
+
+ /**
+ * Removes trailing newlines from a line of text. This is meant to be used
+ * with array_walk().
+ *
+ * @param string $line The line to trim.
+ * @param integer $key The index of the line in the array. Not used.
+ */
+ function trimNewlines(&$line, $key)
+ {
+ $line = str_replace(array("\n", "\r"), '', $line);
+ }
+
+ /**
+ * Determines the location of the system temporary directory.
+ *
+ * @static
+ *
+ * @access protected
+ *
+ * @return string A directory name which can be used for temp files.
+ * Returns false if one could not be found.
+ */
+ function _getTempDir()
+ {
+ $tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
+ 'c:\windows\temp', 'c:\winnt\temp');
+
+ /* Try PHP's upload_tmp_dir directive. */
+ $tmp = ini_get('upload_tmp_dir');
+
+ /* Otherwise, try to determine the TMPDIR environment variable. */
+ if (!strlen($tmp)) {
+ $tmp = getenv('TMPDIR');
+ }
+
+ /* If we still cannot determine a value, then cycle through a list of
+ * preset possibilities. */
+ while (!strlen($tmp) && count($tmp_locations)) {
+ $tmp_check = array_shift($tmp_locations);
+ if (@is_dir($tmp_check)) {
+ $tmp = $tmp_check;
+ }
+ }
+
+ /* If it is still empty, we have failed, so return false; otherwise
+ * return the directory determined. */
+ return strlen($tmp) ? $tmp : false;
+ }
+
+ /**
+ * Checks a diff for validity.
+ *
+ * This is here only for debugging purposes.
+ */
+ function _check($from_lines, $to_lines)
+ {
+ if (serialize($from_lines) != serialize($this->getOriginal())) {
+ trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
+ }
+ if (serialize($to_lines) != serialize($this->getFinal())) {
+ trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
+ }
+
+ $rev = $this->reverse();
+ if (serialize($to_lines) != serialize($rev->getOriginal())) {
+ trigger_error("Reversed original doesn't match", E_USER_ERROR);
+ }
+ if (serialize($from_lines) != serialize($rev->getFinal())) {
+ trigger_error("Reversed final doesn't match", E_USER_ERROR);
+ }
+
+ $prevtype = null;
+ foreach ($this->_edits as $edit) {
+ if ($prevtype == get_class($edit)) {
+ trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
+ }
+ $prevtype = get_class($edit);
+ }
+
+ return true;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki
+ */
+class Text_MappedDiff extends Text_Diff {
+
+ /**
+ * Computes a diff between sequences of strings.
+ *
+ * This can be used to compute things like case-insensitve diffs, or diffs
+ * which ignore changes in white-space.
+ *
+ * @param array $from_lines An array of strings.
+ * @param array $to_lines An array of strings.
+ * @param array $mapped_from_lines This array should have the same size
+ * number of elements as $from_lines. The
+ * elements in $mapped_from_lines and
+ * $mapped_to_lines are what is actually
+ * compared when computing the diff.
+ * @param array $mapped_to_lines This array should have the same number
+ * of elements as $to_lines.
+ */
+ function Text_MappedDiff($from_lines, $to_lines,
+ $mapped_from_lines, $mapped_to_lines)
+ {
+ assert(count($from_lines) == count($mapped_from_lines));
+ assert(count($to_lines) == count($mapped_to_lines));
+
+ parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
+
+ $xi = $yi = 0;
+ for ($i = 0; $i < count($this->_edits); $i++) {
+ $orig = &$this->_edits[$i]->orig;
+ if (is_array($orig)) {
+ $orig = array_slice($from_lines, $xi, count($orig));
+ $xi += count($orig);
+ }
+
+ $final = &$this->_edits[$i]->final;
+ if (is_array($final)) {
+ $final = array_slice($to_lines, $yi, count($final));
+ $yi += count($final);
+ }
+ }
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki
+ *
+ * @access private
+ */
+class Text_Diff_Op {
+
+ var $orig;
+ var $final;
+
+ function &reverse()
+ {
+ trigger_error('Abstract method', E_USER_ERROR);
+ }
+
+ function norig()
+ {
+ return $this->orig ? count($this->orig) : 0;
+ }
+
+ function nfinal()
+ {
+ return $this->final ? count($this->final) : 0;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki
+ *
+ * @access private
+ */
+class Text_Diff_Op_copy extends Text_Diff_Op {
+
+ function Text_Diff_Op_copy($orig, $final = false)
+ {
+ if (!is_array($final)) {
+ $final = $orig;
+ }
+ $this->orig = $orig;
+ $this->final = $final;
+ }
+
+ function &reverse()
+ {
+ $reverse = &new Text_Diff_Op_copy($this->final, $this->orig);
+ return $reverse;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki
+ *
+ * @access private
+ */
+class Text_Diff_Op_delete extends Text_Diff_Op {
+
+ function Text_Diff_Op_delete($lines)
+ {
+ $this->orig = $lines;
+ $this->final = false;
+ }
+
+ function &reverse()
+ {
+ $reverse = &new Text_Diff_Op_add($this->orig);
+ return $reverse;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki
+ *
+ * @access private
+ */
+class Text_Diff_Op_add extends Text_Diff_Op {
+
+ function Text_Diff_Op_add($lines)
+ {
+ $this->final = $lines;
+ $this->orig = false;
+ }
+
+ function &reverse()
+ {
+ $reverse = &new Text_Diff_Op_delete($this->final);
+ return $reverse;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki
+ *
+ * @access private
+ */
+class Text_Diff_Op_change extends Text_Diff_Op {
+
+ function Text_Diff_Op_change($orig, $final)
+ {
+ $this->orig = $orig;
+ $this->final = $final;
+ }
+
+ function &reverse()
+ {
+ $reverse = &new Text_Diff_Op_change($this->final, $this->orig);
+ return $reverse;
+ }
+
+}
diff -uNr a/blog/wp-includes/Text/index.php b/blog/wp-includes/Text/index.php
--- a/blog/wp-includes/Text/index.php false
+++ b/blog/wp-includes/Text/index.php 099fbcf9478701c433aa576bbcc0cec1987ebf948f13220182da7dc8711b448daddf9ea289b9e8ea4288757f913c64f5f06eb5011e16d4d23592aae16800adb0
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff -uNr a/blog/wp-includes/theme.php b/blog/wp-includes/theme.php
--- a/blog/wp-includes/theme.php false
+++ b/blog/wp-includes/theme.php 93a7ef1694f7167220878da4004aac03b461d44fe01e49ca16fe7a94e25ce97c9e14e3c6c8f01efc023792001c5750dfe9b9ff4310e19e08013378bae80ea9c8
@@ -0,0 +1,1113 @@
+text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
+ $stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
+ else
+ $stylesheet_uri = '';
+ return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
+}
+
+/**
+ * Retrieve name of the current theme.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'template' filter on template option.
+ *
+ * @return string Template name.
+ */
+function get_template() {
+ return apply_filters('template', get_option('template'));
+}
+
+/**
+ * Retrieve current theme directory.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
+ *
+ * @return string Template directory path.
+ */
+function get_template_directory() {
+ $template = get_template();
+ $template_dir = get_theme_root() . "/$template";
+ return apply_filters('template_directory', $template_dir, $template);
+}
+
+/**
+ * Retrieve theme directory URI.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
+ *
+ * @return string Template directory URI.
+ */
+function get_template_directory_uri() {
+ $template = get_template();
+ $template_dir_uri = get_theme_root_uri() . "/$template";
+ return apply_filters('template_directory_uri', $template_dir_uri, $template);
+}
+
+/**
+ * Retrieve theme data from parsed theme file.
+ *
+ * The description will have the tags filtered with the following HTML elements
+ * whitelisted. The 'a' element with the href and title
+ * attributes. The abbr element with the title attribute. The
+ * acronym element with the title attribute allowed. The
+ * code , em , and strong elements also allowed.
+ *
+ * The style.css file must contain theme name, theme URI, and description. The
+ * data can also contain author URI, author, template (parent template),
+ * version, status, and finally tags. Some of these are not used by WordPress
+ * administration panels, but are used by theme directory web sites which list
+ * the theme.
+ *
+ * @since 1.5.0
+ *
+ * @param string $theme_file Theme file path.
+ * @return array Theme data.
+ */
+function get_theme_data( $theme_file ) {
+ $themes_allowed_tags = array(
+ 'a' => array(
+ 'href' => array(),'title' => array()
+ ),
+ 'abbr' => array(
+ 'title' => array()
+ ),
+ 'acronym' => array(
+ 'title' => array()
+ ),
+ 'code' => array(),
+ 'em' => array(),
+ 'strong' => array()
+ );
+
+ $theme_data = implode( '', file( $theme_file ) );
+ $theme_data = str_replace ( '\r', '\n', $theme_data );
+ preg_match( '|Theme Name:(.*)$|mi', $theme_data, $theme_name );
+ preg_match( '|Theme URI:(.*)$|mi', $theme_data, $theme_uri );
+ preg_match( '|Description:(.*)$|mi', $theme_data, $description );
+
+ if ( preg_match( '|Author URI:(.*)$|mi', $theme_data, $author_uri ) )
+ $author_uri = clean_url( trim( $author_uri[1]) );
+ else
+ $author_uri = '';
+
+ if ( preg_match( '|Template:(.*)$|mi', $theme_data, $template ) )
+ $template = wp_kses( trim( $template[1] ), $themes_allowed_tags );
+ else
+ $template = '';
+
+ if ( preg_match( '|Version:(.*)|i', $theme_data, $version ) )
+ $version = wp_kses( trim( $version[1] ), $themes_allowed_tags );
+ else
+ $version = '';
+
+ if ( preg_match('|Status:(.*)|i', $theme_data, $status) )
+ $status = wp_kses( trim( $status[1] ), $themes_allowed_tags );
+ else
+ $status = 'publish';
+
+ if ( preg_match('|Tags:(.*)|i', $theme_data, $tags) )
+ $tags = array_map( 'trim', explode( ',', wp_kses( trim( $tags[1] ), array() ) ) );
+ else
+ $tags = array();
+
+ $name = $theme = wp_kses( trim( $theme_name[1] ), $themes_allowed_tags );
+ $theme_uri = clean_url( trim( $theme_uri[1] ) );
+ $description = wptexturize( wp_kses( trim( $description[1] ), $themes_allowed_tags ) );
+
+ if ( preg_match( '|Author:(.*)$|mi', $theme_data, $author_name ) ) {
+ if ( empty( $author_uri ) ) {
+ $author = wp_kses( trim( $author_name[1] ), $themes_allowed_tags );
+ } else {
+ $author = sprintf( '%3$s ', $author_uri, __( 'Visit author homepage' ), wp_kses( trim( $author_name[1] ), $themes_allowed_tags ) );
+ }
+ } else {
+ $author = __('Anonymous');
+ }
+
+ return array( 'Name' => $name, 'Title' => $theme, 'URI' => $theme_uri, 'Description' => $description, 'Author' => $author, 'Version' => $version, 'Template' => $template, 'Status' => $status, 'Tags' => $tags );
+}
+
+/**
+ * Retrieve list of themes with theme data in theme directory.
+ *
+ * The theme is broken, if it doesn't have a parent theme and is missing either
+ * style.css and, or index.php. If the theme has a parent theme then it is
+ * broken, if it is missing style.css; index.php is optional. The broken theme
+ * list is saved in the {@link $wp_broken_themes} global, which is displayed on
+ * the theme list in the administration panels.
+ *
+ * @since 1.5.0
+ * @global array $wp_broken_themes Stores the broken themes.
+ * @global array $wp_themes Stores the working themes.
+ *
+ * @return array Theme list with theme data.
+ */
+function get_themes() {
+ global $wp_themes, $wp_broken_themes;
+
+ if ( isset($wp_themes) )
+ return $wp_themes;
+
+ $themes = array();
+ $wp_broken_themes = array();
+ $theme_loc = $theme_root = get_theme_root();
+ if ( '/' != WP_CONTENT_DIR ) // don't want to replace all forward slashes, see Trac #4541
+ $theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
+
+ // Files in wp-content/themes directory and one subdir down
+ $themes_dir = @ opendir($theme_root);
+ if ( !$themes_dir )
+ return false;
+
+ while ( ($theme_dir = readdir($themes_dir)) !== false ) {
+ if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
+ if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
+ continue;
+ $stylish_dir = @ opendir($theme_root . '/' . $theme_dir);
+ $found_stylesheet = false;
+ while ( ($theme_file = readdir($stylish_dir)) !== false ) {
+ if ( $theme_file == 'style.css' ) {
+ $theme_files[] = $theme_dir . '/' . $theme_file;
+ $found_stylesheet = true;
+ break;
+ }
+ }
+ @closedir($stylish_dir);
+ if ( !$found_stylesheet ) { // look for themes in that dir
+ $subdir = "$theme_root/$theme_dir";
+ $subdir_name = $theme_dir;
+ $theme_subdir = @ opendir( $subdir );
+ while ( ($theme_dir = readdir($theme_subdir)) !== false ) {
+ if ( is_dir( $subdir . '/' . $theme_dir) && is_readable($subdir . '/' . $theme_dir) ) {
+ if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
+ continue;
+ $stylish_dir = @ opendir($subdir . '/' . $theme_dir);
+ $found_stylesheet = false;
+ while ( ($theme_file = readdir($stylish_dir)) !== false ) {
+ if ( $theme_file == 'style.css' ) {
+ $theme_files[] = $subdir_name . '/' . $theme_dir . '/' . $theme_file;
+ $found_stylesheet = true;
+ break;
+ }
+ }
+ @closedir($stylish_dir);
+ }
+ }
+ @closedir($theme_subdir);
+ $wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
+ }
+ }
+ }
+ if ( is_dir( $theme_dir ) )
+ @closedir( $theme_dir );
+
+ if ( !$themes_dir || !$theme_files )
+ return $themes;
+
+ sort($theme_files);
+
+ foreach ( (array) $theme_files as $theme_file ) {
+ if ( !is_readable("$theme_root/$theme_file") ) {
+ $wp_broken_themes[$theme_file] = array('Name' => $theme_file, 'Title' => $theme_file, 'Description' => __('File not readable.'));
+ continue;
+ }
+
+ $theme_data = get_theme_data("$theme_root/$theme_file");
+
+ $name = $theme_data['Name'];
+ $title = $theme_data['Title'];
+ $description = wptexturize($theme_data['Description']);
+ $version = $theme_data['Version'];
+ $author = $theme_data['Author'];
+ $template = $theme_data['Template'];
+ $stylesheet = dirname($theme_file);
+
+ $screenshot = false;
+ foreach ( array('png', 'gif', 'jpg', 'jpeg') as $ext ) {
+ if (file_exists("$theme_root/$stylesheet/screenshot.$ext")) {
+ $screenshot = "screenshot.$ext";
+ break;
+ }
+ }
+
+ if ( empty($name) ) {
+ $name = dirname($theme_file);
+ $title = $name;
+ }
+
+ if ( empty($template) ) {
+ if ( file_exists(dirname("$theme_root/$theme_file/index.php")) )
+ $template = dirname($theme_file);
+ else
+ continue;
+ }
+
+ $template = trim($template);
+
+ if ( !file_exists("$theme_root/$template/index.php") ) {
+ $parent_dir = dirname(dirname($theme_file));
+ if ( file_exists("$theme_root/$parent_dir/$template/index.php") ) {
+ $template = "$parent_dir/$template";
+ } else {
+ $wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => __('Template is missing.'));
+ continue;
+ }
+ }
+
+ $stylesheet_files = array();
+ $template_files = array();
+
+ $stylesheet_dir = @ dir("$theme_root/$stylesheet");
+ if ( $stylesheet_dir ) {
+ while ( ($file = $stylesheet_dir->read()) !== false ) {
+ if ( !preg_match('|^\.+$|', $file) ) {
+ if ( preg_match('|\.css$|', $file) )
+ $stylesheet_files[] = "$theme_loc/$stylesheet/$file";
+ elseif ( preg_match('|\.php$|', $file) )
+ $template_files[] = "$theme_loc/$stylesheet/$file";
+ }
+ }
+ }
+
+ $template_dir = @ dir("$theme_root/$template");
+ if ( $template_dir ) {
+ while(($file = $template_dir->read()) !== false) {
+ if ( !preg_match('|^\.+$|', $file) && preg_match('|\.php$|', $file) )
+ $template_files[] = "$theme_loc/$template/$file";
+ }
+ }
+
+ $template_dir = dirname($template_files[0]);
+ $stylesheet_dir = dirname($stylesheet_files[0]);
+
+ if ( empty($template_dir) )
+ $template_dir = '/';
+ if ( empty($stylesheet_dir) )
+ $stylesheet_dir = '/';
+
+ // Check for theme name collision. This occurs if a theme is copied to
+ // a new theme directory and the theme header is not updated. Whichever
+ // theme is first keeps the name. Subsequent themes get a suffix applied.
+ // The Default and Classic themes always trump their pretenders.
+ if ( isset($themes[$name]) ) {
+ if ( ('WordPress Default' == $name || 'WordPress Classic' == $name) &&
+ ('default' == $stylesheet || 'classic' == $stylesheet) ) {
+ // If another theme has claimed to be one of our default themes, move
+ // them aside.
+ $suffix = $themes[$name]['Stylesheet'];
+ $new_name = "$name/$suffix";
+ $themes[$new_name] = $themes[$name];
+ $themes[$new_name]['Name'] = $new_name;
+ } else {
+ $name = "$name/$stylesheet";
+ }
+ }
+
+ $themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => $description, 'Author' => $author, 'Version' => $version, 'Template' => $template, 'Stylesheet' => $stylesheet, 'Template Files' => $template_files, 'Stylesheet Files' => $stylesheet_files, 'Template Dir' => $template_dir, 'Stylesheet Dir' => $stylesheet_dir, 'Status' => $theme_data['Status'], 'Screenshot' => $screenshot, 'Tags' => $theme_data['Tags']);
+ }
+
+ // Resolve theme dependencies.
+ $theme_names = array_keys($themes);
+
+ foreach ( (array) $theme_names as $theme_name ) {
+ $themes[$theme_name]['Parent Theme'] = '';
+ if ( $themes[$theme_name]['Stylesheet'] != $themes[$theme_name]['Template'] ) {
+ foreach ( (array) $theme_names as $parent_theme_name ) {
+ if ( ($themes[$parent_theme_name]['Stylesheet'] == $themes[$parent_theme_name]['Template']) && ($themes[$parent_theme_name]['Template'] == $themes[$theme_name]['Template']) ) {
+ $themes[$theme_name]['Parent Theme'] = $themes[$parent_theme_name]['Name'];
+ break;
+ }
+ }
+ }
+ }
+
+ $wp_themes = $themes;
+
+ return $themes;
+}
+
+/**
+ * Retrieve theme data.
+ *
+ * @since 1.5.0
+ *
+ * @param string $theme Theme name.
+ * @return array|null Null, if theme name does not exist. Theme data, if exists.
+ */
+function get_theme($theme) {
+ $themes = get_themes();
+
+ if ( array_key_exists($theme, $themes) )
+ return $themes[$theme];
+
+ return null;
+}
+
+/**
+ * Retrieve current theme display name.
+ *
+ * If the 'current_theme' option has already been set, then it will be returned
+ * instead. If it is not set, then each theme will be iterated over until both
+ * the current stylesheet and current template name.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_current_theme() {
+ if ( $theme = get_option('current_theme') )
+ return $theme;
+
+ $themes = get_themes();
+ $theme_names = array_keys($themes);
+ $current_template = get_option('template');
+ $current_stylesheet = get_option('stylesheet');
+ $current_theme = 'WordPress Default';
+
+ if ( $themes ) {
+ foreach ( (array) $theme_names as $theme_name ) {
+ if ( $themes[$theme_name]['Stylesheet'] == $current_stylesheet &&
+ $themes[$theme_name]['Template'] == $current_template ) {
+ $current_theme = $themes[$theme_name]['Name'];
+ break;
+ }
+ }
+ }
+
+ update_option('current_theme', $current_theme);
+
+ return $current_theme;
+}
+
+/**
+ * Retrieve path to themes directory.
+ *
+ * Does not have trailing slash.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'theme_root' filter on path.
+ *
+ * @return string Theme path.
+ */
+function get_theme_root() {
+ return apply_filters('theme_root', WP_CONTENT_DIR . "/themes");
+}
+
+/**
+ * Retrieve URI for themes directory.
+ *
+ * Does not have trailing slash.
+ *
+ * @since 1.5.0
+ *
+ * @return string Themes URI.
+ */
+function get_theme_root_uri() {
+ return apply_filters('theme_root_uri', content_url('themes'), get_option('siteurl'));
+}
+
+/**
+ * Retrieve path to file without the use of extension.
+ *
+ * Used to quickly retrieve the path of file without including the file
+ * extension. It will also check the parent template, if the file exists, with
+ * the use of {@link locate_template()}. Allows for more generic file location
+ * without the use of the other get_*_template() functions.
+ *
+ * Can be used with include() or require() to retrieve path.
+ *
+ * if( '' != get_query_template( '404' ) )
+ * include( get_query_template( '404' ) );
+ *
+ * or the same can be accomplished with
+ *
+ * if( '' != get_404_template() )
+ * include( get_404_template() );
+ *
+ *
+ * @since 1.5.0
+ *
+ * @param string $type Filename without extension.
+ * @return string Full path to file.
+ */
+function get_query_template($type) {
+ $type = preg_replace( '|[^a-z0-9-]+|', '', $type );
+ return apply_filters("{$type}_template", locate_template(array("{$type}.php")));
+}
+
+/**
+ * Retrieve path of 404 template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_404_template() {
+ return get_query_template('404');
+}
+
+/**
+ * Retrieve path of archive template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_archive_template() {
+ return get_query_template('archive');
+}
+
+/**
+ * Retrieve path of author template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_author_template() {
+ return get_query_template('author');
+}
+
+/**
+ * Retrieve path of category template in current or parent template.
+ *
+ * Works by retrieving the current category ID, for example 'category-1.php' and
+ * will fallback to category.php template, if the ID category file doesn't
+ * exist.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'category_template' on file path of category template.
+ *
+ * @return string
+ */
+function get_category_template() {
+ $template = locate_template(array("category-" . absint( get_query_var('cat') ) . '.php', 'category.php'));
+ return apply_filters('category_template', $template);
+}
+
+/**
+ * Retrieve path of tag template in current or parent template.
+ *
+ * Works by retrieving the current tag name, for example 'tag-wordpress.php' and will
+ * fallback to tag.php template, if the name tag file doesn't exist.
+ *
+ * @since 2.3.0
+ * @uses apply_filters() Calls 'tag_template' on file path of tag template.
+ *
+ * @return string
+ */
+function get_tag_template() {
+ $template = locate_template(array("tag-" . get_query_var('tag') . '.php', 'tag.php'));
+ return apply_filters('tag_template', $template);
+}
+
+/**
+ * Retrieve path of taxonomy template in current or parent template.
+ *
+ * Retrieves the taxonomy and term, if term is available. The template is
+ * prepended with 'taxonomy-' and followed by both the taxonomy string and
+ * the taxonomy string followed by a dash and then followed by the term.
+ *
+ * The taxonomy and term template is checked and used first, if it exists.
+ * Second, just the taxonomy template is checked, and then finally, taxonomy.php
+ * template is used. If none of the files exist, then it will fall back on to
+ * index.php.
+ *
+ * @since unknown (2.6.0 most likely)
+ * @uses apply_filters() Calls 'taxonomy_template' filter on found path.
+ *
+ * @return string
+ */
+function get_taxonomy_template() {
+ $taxonomy = get_query_var('taxonomy');
+ $term = get_query_var('term');
+
+ $templates = array();
+ if ( $taxonomy && $term )
+ $templates[] = "taxonomy-$taxonomy-$term.php";
+ if ( $taxonomy )
+ $templates[] = "taxonomy-$taxonomy.php";
+
+ $templates[] = "taxonomy.php";
+
+ $template = locate_template($templates);
+ return apply_filters('taxonomy_template', $template);
+}
+
+/**
+ * Retrieve path of date template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_date_template() {
+ return get_query_template('date');
+}
+
+/**
+ * Retrieve path of home template in current or parent template.
+ *
+ * Attempts to locate 'home.php' first before falling back to 'index.php'.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'home_template' on file path of home template.
+ *
+ * @return string
+ */
+function get_home_template() {
+ $template = locate_template(array('home.php', 'index.php'));
+ return apply_filters('home_template', $template);
+}
+
+/**
+ * Retrieve path of page template in current or parent template.
+ *
+ * First attempt is to look for the file in the '_wp_page_template' page meta
+ * data. The second attempt, if the first has a file and is not empty, is to
+ * look for 'page.php'.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_page_template() {
+ global $wp_query;
+
+ $id = (int) $wp_query->post->ID;
+ $template = get_post_meta($id, '_wp_page_template', true);
+
+ if ( 'default' == $template )
+ $template = '';
+
+ $templates = array();
+ if ( !empty($template) && !validate_file($template) )
+ $templates[] = $template;
+
+ $templates[] = "page.php";
+
+ return apply_filters('page_template', locate_template($templates));
+}
+
+/**
+ * Retrieve path of paged template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_paged_template() {
+ return get_query_template('paged');
+}
+
+/**
+ * Retrieve path of search template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_search_template() {
+ return get_query_template('search');
+}
+
+/**
+ * Retrieve path of single template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_single_template() {
+ return get_query_template('single');
+}
+
+/**
+ * Retrieve path of attachment template in current or parent template.
+ *
+ * The attachment path first checks if the first part of the mime type exists.
+ * The second check is for the second part of the mime type. The last check is
+ * for both types separated by an underscore. If neither are found then the file
+ * 'attachment.php' is checked and returned.
+ *
+ * Some examples for the 'text/plain' mime type are 'text.php', 'plain.php', and
+ * finally 'text_plain.php'.
+ *
+ * @since 2.0.0
+ *
+ * @return string
+ */
+function get_attachment_template() {
+ global $posts;
+ $type = explode('/', $posts[0]->post_mime_type);
+ if ( $template = get_query_template($type[0]) )
+ return $template;
+ elseif ( $template = get_query_template($type[1]) )
+ return $template;
+ elseif ( $template = get_query_template("$type[0]_$type[1]") )
+ return $template;
+ else
+ return get_query_template('attachment');
+}
+
+/**
+ * Retrieve path of comment popup template in current or parent template.
+ *
+ * Checks for comment popup template in current template, if it exists or in the
+ * parent template. If it doesn't exist, then it retrieves the comment-popup.php
+ * file from the default theme. The default theme must then exist for it to
+ * work.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'comments_popup_template' filter on path.
+ *
+ * @return string
+ */
+function get_comments_popup_template() {
+ $template = locate_template(array("comments-popup.php"));
+ if ('' == $template)
+ $template = get_theme_root() . '/default/comments-popup.php';
+
+ return apply_filters('comments_popup_template', $template);
+}
+
+/**
+ * Retrieve the name of the highest priority template file that exists.
+ *
+ * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
+ * inherit from a parent theme can just overload one file.
+ *
+ * @since 2.7.0
+ *
+ * @param array $template_names Array of template files to search for in priority order.
+ * @param bool $load If true the template file will be loaded if it is found.
+ * @return string The template filename if one is located.
+ */
+function locate_template($template_names, $load = false) {
+ if (!is_array($template_names))
+ return '';
+
+ $located = '';
+ foreach($template_names as $template_name) {
+ if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
+ $located = STYLESHEETPATH . '/' . $template_name;
+ break;
+ } else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
+ $located = TEMPLATEPATH . '/' . $template_name;
+ break;
+ }
+ }
+
+ if ($load && '' != $located)
+ load_template($located);
+
+ return $located;
+}
+
+/**
+ * Require once the template file with WordPress environment.
+ *
+ * The globals are set up for the template file to ensure that the WordPress
+ * environment is available from within the function. The query variables are
+ * also available.
+ *
+ * @since 1.5.0
+ *
+ * @param string $_template_file Path to template file.
+ */
+function load_template($_template_file) {
+ global $posts, $post, $wp_did_header, $wp_did_template_redirect, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
+
+ if ( is_array($wp_query->query_vars) )
+ extract($wp_query->query_vars, EXTR_SKIP);
+
+ require_once($_template_file);
+}
+
+/**
+ * Display localized stylesheet link element.
+ *
+ * @since 2.1.0
+ */
+function locale_stylesheet() {
+ $stylesheet = get_locale_stylesheet_uri();
+ if ( empty($stylesheet) )
+ return;
+ echo ' ';
+}
+
+/**
+ * Start preview theme output buffer.
+ *
+ * Will only preform task if the user has permissions and template and preview
+ * query variables exist.
+ *
+ * @since 2.5.0
+ */
+function preview_theme() {
+ if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
+ return;
+
+ if ( !current_user_can( 'switch_themes' ) )
+ return;
+
+ $_GET['template'] = preg_replace('|[^a-z0-9_.-]|i', '', $_GET['template']);
+
+ if ( validate_file($_GET['template']) )
+ return;
+
+ add_filter('template', create_function('', "return '{$_GET['template']}';") );
+
+ if ( isset($_GET['stylesheet']) ) {
+ $_GET['stylesheet'] = preg_replace('|[^a-z0-9_.-]|i', '', $_GET['stylesheet']);
+ if ( validate_file($_GET['stylesheet']) )
+ return;
+ add_filter('stylesheet', create_function('', "return '{$_GET['stylesheet']}';") );
+ }
+
+ ob_start( 'preview_theme_ob_filter' );
+}
+add_action('setup_theme', 'preview_theme');
+
+/**
+ * Callback function for ob_start() to capture all links in the theme.
+ *
+ * @since unknown
+ * @access private
+ *
+ * @param string $content
+ * @return string
+ */
+function preview_theme_ob_filter( $content ) {
+ return preg_replace_callback( "|()|", 'preview_theme_ob_filter_callback', $content );
+}
+
+/**
+ * Manipulates preview theme links in order to control and maintain location.
+ *
+ * Callback function for preg_replace_callback() to accept and filter matches.
+ *
+ * @since unknown
+ * @access private
+ *
+ * @param array $matches
+ * @return string
+ */
+function preview_theme_ob_filter_callback( $matches ) {
+ if ( strpos($matches[4], 'onclick') !== false )
+ $matches[4] = preg_replace('#onclick=([\'"]).*?(?. (? 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'] ), $matches[3] );
+ if ( 0 === strpos($link, 'preview=1') )
+ $link = "?$link";
+ return $matches[1] . attribute_escape( $link ) . $matches[4];
+}
+
+/**
+ * Switches current theme to new template and stylesheet names.
+ *
+ * @since unknown
+ * @uses do_action() Calls 'switch_theme' action on updated theme display name.
+ *
+ * @param string $template Template name
+ * @param string $stylesheet Stylesheet name.
+ */
+function switch_theme($template, $stylesheet) {
+ update_option('template', $template);
+ update_option('stylesheet', $stylesheet);
+ delete_option('current_theme');
+ $theme = get_current_theme();
+ do_action('switch_theme', $theme);
+}
+
+/**
+ * Checks that current theme files 'index.php' and 'style.css' exists.
+ *
+ * Does not check the 'default' theme. The 'default' theme should always exist
+ * or should have another theme renamed to that template name and directory
+ * path. Will switch theme to default if current theme does not validate.
+ * You can use the 'validate_current_theme' filter to return FALSE to
+ * disable this functionality.
+ *
+ * @since 1.5.0
+ *
+ * @return bool
+ */
+function validate_current_theme() {
+ // Don't validate during an install/upgrade.
+ if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
+ return true;
+
+ if ( get_template() != 'default' && !file_exists(get_template_directory() . '/index.php') ) {
+ switch_theme('default', 'default');
+ return false;
+ }
+
+ if ( get_stylesheet() != 'default' && !file_exists(get_template_directory() . '/style.css') ) {
+ switch_theme('default', 'default');
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Retrieve theme modification value for the current theme.
+ *
+ * If the modification name does not exist, then the $default will be passed
+ * through {@link http://php.net/sprintf sprintf()} PHP function with the first
+ * string the template directory URI and the second string the stylesheet
+ * directory URI.
+ *
+ * @since 2.1.0
+ * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
+ *
+ * @param string $name Theme modification name.
+ * @param bool|string $default
+ * @return string
+ */
+function get_theme_mod($name, $default = false) {
+ $theme = get_current_theme();
+
+ $mods = get_option("mods_$theme");
+
+ if ( isset($mods[$name]) )
+ return apply_filters( "theme_mod_$name", $mods[$name] );
+
+ return apply_filters( "theme_mod_$name", sprintf($default, get_template_directory_uri(), get_stylesheet_directory_uri()) );
+}
+
+/**
+ * Update theme modification value for the current theme.
+ *
+ * @since 2.1.0
+ *
+ * @param string $name Theme modification name.
+ * @param string $value theme modification value.
+ */
+function set_theme_mod($name, $value) {
+ $theme = get_current_theme();
+
+ $mods = get_option("mods_$theme");
+
+ $mods[$name] = $value;
+
+ update_option("mods_$theme", $mods);
+ wp_cache_delete("mods_$theme", 'options');
+}
+
+/**
+ * Remove theme modification name from current theme list.
+ *
+ * If removing the name also removes all elements, then the entire option will
+ * be removed.
+ *
+ * @since 2.1.0
+ *
+ * @param string $name Theme modification name.
+ * @return null
+ */
+function remove_theme_mod( $name ) {
+ $theme = get_current_theme();
+
+ $mods = get_option("mods_$theme");
+
+ if ( !isset($mods[$name]) )
+ return;
+
+ unset($mods[$name]);
+
+ if ( empty($mods) )
+ return remove_theme_mods();
+
+ update_option("mods_$theme", $mods);
+ wp_cache_delete("mods_$theme", 'options');
+}
+
+/**
+ * Remove theme modifications option for current theme.
+ *
+ * @since 2.1.0
+ */
+function remove_theme_mods() {
+ $theme = get_current_theme();
+
+ delete_option("mods_$theme");
+}
+
+/**
+ * Retrieve text color for custom header.
+ *
+ * @since 2.1.0
+ * @uses HEADER_TEXTCOLOR
+ *
+ * @return string
+ */
+function get_header_textcolor() {
+ return get_theme_mod('header_textcolor', HEADER_TEXTCOLOR);
+}
+
+/**
+ * Display text color for custom header.
+ *
+ * @since 2.1.0
+ */
+function header_textcolor() {
+ echo get_header_textcolor();
+}
+
+/**
+ * Retrieve header image for custom header.
+ *
+ * @since 2.1.0
+ * @uses HEADER_IMAGE
+ *
+ * @return string
+ */
+function get_header_image() {
+ return get_theme_mod('header_image', HEADER_IMAGE);
+}
+
+/**
+ * Display header image path.
+ *
+ * @since 2.1.0
+ */
+function header_image() {
+ echo get_header_image();
+}
+
+/**
+ * Add callbacks for image header display.
+ *
+ * The parameter $header_callback callback will be required to display the
+ * content for the 'wp_head' action. The parameter $admin_header_callback
+ * callback will be added to Custom_Image_Header class and that will be added
+ * to the 'admin_menu' action.
+ *
+ * @since 2.1.0
+ * @uses Custom_Image_Header Sets up for $admin_header_callback for administration panel display.
+ *
+ * @param callback $header_callback Call on 'wp_head' action.
+ * @param callback $admin_header_callback Call on administration panels.
+ */
+function add_custom_image_header($header_callback, $admin_header_callback) {
+ if ( ! empty($header_callback) )
+ add_action('wp_head', $header_callback);
+
+ if ( ! is_admin() )
+ return;
+ require_once(ABSPATH . 'wp-admin/custom-header.php');
+ $GLOBALS['custom_image_header'] = new Custom_Image_Header($admin_header_callback);
+ add_action('admin_menu', array(&$GLOBALS['custom_image_header'], 'init'));
+}
+
+?>
diff -uNr a/blog/wp-includes/update.php b/blog/wp-includes/update.php
--- a/blog/wp-includes/update.php false
+++ b/blog/wp-includes/update.php 58b246796645ef1d333b56c08faa943d820fb93a3f1a4400f522a0e53e07b9659a8f583c0e1880a4a72c6a1b52b0b063957ae1c4c8f071659e7d768cd9ecafc4
@@ -0,0 +1,308 @@
+last_checked ) &&
+ 43200 > ( time() - $current->last_checked ) &&
+ $current->version_checked == $wp_version
+ )
+ return false;
+
+ // Update last_checked for current to prevent multiple blocking requests if request hangs
+ $current->last_checked = time();
+ update_option( 'update_core', $current );
+
+ if ( method_exists( $wpdb, 'db_version' ) )
+ $mysql_version = preg_replace('/[^0-9.].*/', '', $wpdb->db_version($wpdb->users));
+ else
+ $mysql_version = 'N/A';
+ $local_package = isset( $wp_local_package )? $wp_local_package : '';
+ $url = "http://polimedia.us/muiewp/core/version-check/1.3/?version=$wp_version&php=$php_version&locale=$locale&mysql=$mysql_version&local_package=$local_package";
+
+ $options = array('timeout' => 3);
+ $options['headers'] = array(
+ 'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'),
+ 'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo('url')
+ );
+
+ $response = wp_remote_request($url, $options);
+
+ if ( is_wp_error( $response ) )
+ return false;
+
+ if ( 200 != $response['response']['code'] )
+ return false;
+
+ $body = trim( $response['body'] );
+ $body = str_replace(array("\r\n", "\r"), "\n", $body);
+ $new_options = array();
+ foreach( explode( "\n\n", $body ) as $entry) {
+ $returns = explode("\n", $entry);
+ $new_option = new stdClass();
+ $new_option->response = attribute_escape( $returns[0] );
+ if ( isset( $returns[1] ) )
+ $new_option->url = clean_url( $returns[1] );
+ if ( isset( $returns[2] ) )
+ $new_option->package = clean_url( $returns[2] );
+ if ( isset( $returns[3] ) )
+ $new_option->current = attribute_escape( $returns[3] );
+ if ( isset( $returns[4] ) )
+ $new_option->locale = attribute_escape( $returns[4] );
+ $new_options[] = $new_option;
+ }
+
+ $updates = new stdClass();
+ $updates->updates = $new_options;
+ $updates->last_checked = time();
+ $updates->version_checked = $wp_version;
+ update_option( 'update_core', $updates);
+}
+add_action( 'init', 'wp_version_check' );
+
+/**
+ * Check plugin versions against the latest versions hosted on WordPress.org.
+ *
+ * The WordPress version, PHP version, and Locale is sent along with a list of
+ * all plugins installed. Checks against the WordPress server at
+ * polimedia.us/muiewp. Will only check if WordPress isn't installing.
+ *
+ * @package WordPress
+ * @since 2.3.0
+ * @uses $wp_version Used to notidy the WordPress version.
+ *
+ * @return mixed Returns null if update is unsupported. Returns false if check is too soon.
+ */
+function wp_update_plugins() {
+ global $wp_version;
+
+ if ( defined('WP_INSTALLING') )
+ return false;
+
+ // If running blog-side, bail unless we've not checked in the last 12 hours
+ if ( !function_exists( 'get_plugins' ) )
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
+
+ $plugins = get_plugins();
+ $active = get_option( 'active_plugins' );
+ $current = get_option( 'update_plugins' );
+ if ( ! is_object($current) )
+ $current = new stdClass;
+
+ $new_option = '';
+ $new_option->last_checked = time();
+ $time_not_changed = isset( $current->last_checked ) && 43200 > ( time() - $current->last_checked );
+
+ $plugin_changed = false;
+ foreach ( $plugins as $file => $p ) {
+ $new_option->checked[ $file ] = $p['Version'];
+
+ if ( !isset( $current->checked[ $file ] ) ) {
+ $plugin_changed = true;
+ continue;
+ }
+
+ if ( strval($current->checked[ $file ]) !== strval($p['Version']) )
+ $plugin_changed = true;
+ }
+
+ if ( isset ( $current->response ) && is_array( $current->response ) ) {
+ foreach ( $current->response as $plugin_file => $update_details ) {
+ if ( ! isset($plugins[ $plugin_file ]) ) {
+ $plugin_changed = true;
+ }
+ }
+ }
+
+ // Bail if we've checked in the last 12 hours and if nothing has changed
+ if ( $time_not_changed && !$plugin_changed )
+ return false;
+
+ // Update last_checked for current to prevent multiple blocking requests if request hangs
+ $current->last_checked = time();
+ update_option( 'update_plugins', $current );
+
+ $to_send->plugins = $plugins;
+ $to_send->active = $active;
+ $send = serialize( $to_send );
+ $body = 'plugins=' . urlencode( $send );
+
+ $options = array('method' => 'POST', 'timeout' => 3, 'body' => $body);
+ $options['headers'] = array(
+ 'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'),
+ 'Content-Length' => strlen($body),
+ 'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo('url')
+ );
+
+ $raw_response = wp_remote_request('http://polimedia.us/muiewp/plugins/update-check/1.0/', $options);
+
+ if ( is_wp_error( $raw_response ) )
+ return false;
+
+ if( 200 != $raw_response['response']['code'] ) {
+ return false;
+ }
+
+ $response = unserialize( $raw_response['body'] );
+
+ if ( false !== $response )
+ $new_option->response = $response;
+ else
+ $new_option->response = array();
+
+ update_option( 'update_plugins', $new_option );
+}
+
+/**
+ * Check theme versions against the latest versions hosted on WordPress.org.
+ *
+ * A list of all themes installed in sent to WP. Checks against the
+ * WordPress server at polimedia.us/muiewp. Will only check if WordPress isn't
+ * installing.
+ *
+ * @package WordPress
+ * @since 2.7.0
+ * @uses $wp_version Used to notidy the WordPress version.
+ *
+ * @return mixed Returns null if update is unsupported. Returns false if check is too soon.
+ */
+function wp_update_themes( ) {
+ global $wp_version;
+
+ if( defined( 'WP_INSTALLING' ) )
+ return false;
+
+ if( !function_exists( 'get_themes' ) )
+ require_once( ABSPATH . 'wp-includes/theme.php' );
+
+ $installed_themes = get_themes( );
+ $current_theme = get_option( 'update_themes' );
+ if ( ! is_object($current_theme) )
+ $current_theme = new stdClass;
+
+ $new_option = '';
+ $new_option->last_checked = time( );
+ $time_not_changed = isset( $current_theme->last_checked ) && 43200 > ( time( ) - $current_theme->last_checked );
+
+ if( $time_not_changed )
+ return false;
+
+ // Update last_checked for current to prevent multiple blocking requests if request hangs
+ $current_theme->last_checked = time();
+ update_option( 'update_themes', $current_theme );
+
+ $themes = array( );
+ $themes['current_theme'] = $current_theme;
+ foreach( (array) $installed_themes as $theme_title => $theme ) {
+ $themes[$theme['Template']] = array( );
+
+ foreach( (array) $theme as $key => $value ) {
+ $themes[$theme['Template']][$key] = $value;
+ }
+ }
+
+ $options = array(
+ 'method' => 'POST',
+ 'timeout' => 3,
+ 'body' => 'themes=' . urlencode( serialize( $themes ) )
+ );
+ $options['headers'] = array(
+ 'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
+ 'Content-Length' => strlen( $options['body'] ),
+ 'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )
+ );
+
+ $raw_response = wp_remote_request( 'http://polimedia.us/muiewp/themes/update-check/1.0/', $options );
+
+ if( is_wp_error( $raw_response ) )
+ return false;
+
+ if( 200 != $raw_response['response']['code'] )
+ return false;
+
+ $response = unserialize( $raw_response['body'] );
+ if( $response )
+ $new_option->response = $response;
+
+ update_option( 'update_themes', $new_option );
+}
+
+/**
+ * Check the last time plugins were run before checking plugin versions.
+ *
+ * This might have been backported to WordPress 2.6.1 for performance reasons.
+ * This is used for the wp-admin to check only so often instead of every page
+ * load.
+ *
+ * @since 2.7.0
+ * @access private
+ */
+function _maybe_update_plugins() {
+ $current = get_option( 'update_plugins' );
+ if ( isset( $current->last_checked ) && 43200 > ( time() - $current->last_checked ) )
+ return;
+ wp_update_plugins();
+}
+
+/**
+ * Check themes versions only after a duration of time.
+ *
+ * This is for performance reasons to make sure that on the theme version
+ * checker is not run on every page load.
+ *
+ * @since 2.7.0
+ * @access private
+ */
+function _maybe_update_themes( ) {
+ $current = get_option( 'update_themes' );
+ if( isset( $current->last_checked ) && 43200 > ( time( ) - $current->last_checked ) )
+ return;
+
+ wp_update_themes( );
+}
+
+add_action( 'load-plugins.php', 'wp_update_plugins' );
+add_action( 'load-update.php', 'wp_update_plugins' );
+add_action( 'admin_init', '_maybe_update_plugins' );
+add_action( 'wp_update_plugins', 'wp_update_plugins' );
+
+add_action( 'admin_init', '_maybe_update_themes' );
+add_action( 'wp_update_themes', 'wp_update_themes' );
+
+if ( !wp_next_scheduled('wp_update_plugins') && !defined('WP_INSTALLING') )
+ wp_schedule_event(time(), 'twicedaily', 'wp_update_plugins');
+
+
+if ( !wp_next_scheduled('wp_update_themes') && !defined('WP_INSTALLING') )
+ wp_schedule_event(time(), 'twicedaily', 'wp_update_themes');
+
+?>
diff -uNr a/blog/wp-includes/user.php b/blog/wp-includes/user.php
--- a/blog/wp-includes/user.php false
+++ b/blog/wp-includes/user.php 2ca6b6ae87cc7f7dfc4dc188f5994b546351d8974c1d4d56014cc18f1ac135d200add22e0633fac45ebed49104b7b11f88764bed0e0ea51e70fdb4b82797996a
@@ -0,0 +1,559 @@
+add('empty_username', __('ERROR : The username field is empty.'));
+ if ( empty($credentials['user_password']) )
+ $error->add('empty_password', __('ERROR : The password field is empty.'));
+ return $error;
+ }
+
+ $user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
+ if ( is_wp_error($user) )
+ return $user;
+
+ wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
+ do_action('wp_login', $credentials['user_login']);
+ return $user;
+}
+
+/**
+ * Retrieve user data based on field.
+ *
+ * Use get_profile() will make a database query to get the value of the table
+ * column. The value might be cached using the query cache, but care should be
+ * taken when using the function to not make a lot of queries for retrieving
+ * user profile information.
+ *
+ * If the $user parameter is not used, then the user will be retrieved from a
+ * cookie of the user. Therefore, if the cookie does not exist, then no value
+ * might be returned. Sanity checking must be done to ensure that when using
+ * get_profile() that empty/null/false values are handled and that something is
+ * at least displayed.
+ *
+ * @since 1.5.0
+ * @uses $wpdb WordPress database object to create queries.
+ *
+ * @param string $field User field to retrieve.
+ * @param string $user Optional. User username.
+ * @return string The value in the field.
+ */
+function get_profile($field, $user = false) {
+ global $wpdb;
+ if ( !$user )
+ $user = $wpdb->escape($_COOKIE[USER_COOKIE]);
+ return $wpdb->get_var( $wpdb->prepare("SELECT $field FROM $wpdb->users WHERE user_login = %s", $user) );
+}
+
+/**
+ * Number of posts user has written.
+ *
+ * @since 0.71
+ * @uses $wpdb WordPress database object for queries.
+ *
+ * @param int $userid User ID.
+ * @return int Amount of posts user has written.
+ */
+function get_usernumposts($userid) {
+ global $wpdb;
+ $userid = (int) $userid;
+ $count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->posts WHERE post_author = %d AND post_type = 'post' AND ", $userid) . get_private_posts_cap_sql('post'));
+ return apply_filters('get_usernumposts', $count, $userid);
+}
+
+/**
+ * Check that the user login name and password is correct.
+ *
+ * @since 0.71
+ * @todo xmlrpc only. Maybe move to xmlrpc.php.
+ *
+ * @param string $user_login User name.
+ * @param string $user_pass User password.
+ * @return bool False if does not authenticate, true if username and password authenticates.
+ */
+function user_pass_ok($user_login, $user_pass) {
+ $user = wp_authenticate($user_login, $user_pass);
+ if ( is_wp_error($user) )
+ return false;
+
+ return true;
+}
+
+//
+// User option functions
+//
+
+/**
+ * Retrieve user option that can be either global, user, or blog.
+ *
+ * If the user ID is not given, then the current user will be used instead. If
+ * the user ID is given, then the user data will be retrieved. The filter for
+ * the result, will also pass the original option name and finally the user data
+ * object as the third parameter.
+ *
+ * The option will first check for the non-global name, then the global name,
+ * and if it still doesn't find it, it will try the blog option. The option can
+ * either be modified or set by a plugin.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database object for queries.
+ * @uses apply_filters() Calls 'get_user_option_$option' hook with result,
+ * option parameter, and user data object.
+ *
+ * @param string $option User option name.
+ * @param int $user Optional. User ID.
+ * @param bool $check_blog_options Whether to check for an option in the options table if a per-user option does not exist. Default is true.
+ * @return mixed
+ */
+function get_user_option( $option, $user = 0, $check_blog_options = true ) {
+ global $wpdb;
+
+ $option = preg_replace('|[^a-z0-9_]|i', '', $option);
+ if ( empty($user) )
+ $user = wp_get_current_user();
+ else
+ $user = get_userdata($user);
+
+ if ( isset( $user->{$wpdb->prefix . $option} ) ) // Blog specific
+ $result = $user->{$wpdb->prefix . $option};
+ elseif ( isset( $user->{$option} ) ) // User specific and cross-blog
+ $result = $user->{$option};
+ elseif ( $check_blog_options ) // Blog global
+ $result = get_option( $option );
+ else
+ $result = false;
+
+ return apply_filters("get_user_option_{$option}", $result, $option, $user);
+}
+
+/**
+ * Update user option with global blog capability.
+ *
+ * User options are just like user metadata except that they have support for
+ * global blog options. If the 'global' parameter is false, which it is by false
+ * it will prepend the WordPress table prefix to the option name.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database object for queries
+ *
+ * @param int $user_id User ID
+ * @param string $option_name User option name.
+ * @param mixed $newvalue User option value.
+ * @param bool $global Optional. Whether option name is blog specific or not.
+ * @return unknown
+ */
+function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
+ global $wpdb;
+ if ( !$global )
+ $option_name = $wpdb->prefix . $option_name;
+ return update_usermeta( $user_id, $option_name, $newvalue );
+}
+
+/**
+ * Get users for the blog.
+ *
+ * For setups that use the multi-blog feature. Can be used outside of the
+ * multi-blog feature.
+ *
+ * @since 2.2.0
+ * @uses $wpdb WordPress database object for queries
+ * @uses $blog_id The Blog id of the blog for those that use more than one blog
+ *
+ * @param int $id Blog ID.
+ * @return array List of users that are part of that Blog ID
+ */
+function get_users_of_blog( $id = '' ) {
+ global $wpdb, $blog_id;
+ if ( empty($id) )
+ $id = (int) $blog_id;
+ $users = $wpdb->get_results( "SELECT user_id, user_login, display_name, user_email, meta_value FROM $wpdb->users, $wpdb->usermeta WHERE " . $wpdb->users . ".ID = " . $wpdb->usermeta . ".user_id AND meta_key = '" . $wpdb->prefix . "capabilities' ORDER BY {$wpdb->usermeta}.user_id" );
+ return $users;
+}
+
+//
+// User meta functions
+//
+
+/**
+ * Remove user meta data.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database object for queries.
+ *
+ * @param int $user_id User ID.
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @return bool True deletion completed and false if user_id is not a number.
+ */
+function delete_usermeta( $user_id, $meta_key, $meta_value = '' ) {
+ global $wpdb;
+ if ( !is_numeric( $user_id ) )
+ return false;
+ $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+
+ if ( is_array($meta_value) || is_object($meta_value) )
+ $meta_value = serialize($meta_value);
+ $meta_value = trim( $meta_value );
+
+ if ( ! empty($meta_value) )
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s AND meta_value = %s", $user_id, $meta_key, $meta_value) );
+ else
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key) );
+
+ wp_cache_delete($user_id, 'users');
+
+ return true;
+}
+
+/**
+ * Retrieve user metadata.
+ *
+ * If $user_id is not a number, then the function will fail over with a 'false'
+ * boolean return value. Other returned values depend on whether there is only
+ * one item to be returned, which be that single item type. If there is more
+ * than one metadata value, then it will be list of metadata values.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database object for queries.
+ *
+ * @param int $user_id User ID
+ * @param string $meta_key Optional. Metadata key.
+ * @return mixed
+ */
+function get_usermeta( $user_id, $meta_key = '') {
+ global $wpdb;
+ $user_id = (int) $user_id;
+
+ if ( !$user_id )
+ return false;
+
+ if ( !empty($meta_key) ) {
+ $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+ $user = wp_cache_get($user_id, 'users');
+ // Check the cached user object
+ if ( false !== $user && isset($user->$meta_key) )
+ $metas = array($user->$meta_key);
+ else
+ $metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key) );
+ } else {
+ $metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM $wpdb->usermeta WHERE user_id = %d", $user_id) );
+ }
+
+ if ( empty($metas) ) {
+ if ( empty($meta_key) )
+ return array();
+ else
+ return '';
+ }
+
+ $metas = array_map('maybe_unserialize', $metas);
+
+ if ( count($metas) == 1 )
+ return $metas[0];
+ else
+ return $metas;
+}
+
+/**
+ * Update metadata of user.
+ *
+ * There is no need to serialize values, they will be serialized if it is
+ * needed. The metadata key can only be a string with underscores. All else will
+ * be removed.
+ *
+ * Will remove the metadata, if the meta value is empty.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database object for queries
+ *
+ * @param int $user_id User ID
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @return bool True on successful update, false on failure.
+ */
+function update_usermeta( $user_id, $meta_key, $meta_value ) {
+ global $wpdb;
+ if ( !is_numeric( $user_id ) )
+ return false;
+ $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+
+ /** @todo Might need fix because usermeta data is assumed to be already escaped */
+ if ( is_string($meta_value) )
+ $meta_value = stripslashes($meta_value);
+ $meta_value = maybe_serialize($meta_value);
+
+ if (empty($meta_value)) {
+ return delete_usermeta($user_id, $meta_key);
+ }
+
+ $cur = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key) );
+ if ( !$cur ) {
+ $wpdb->query( $wpdb->prepare("INSERT INTO $wpdb->usermeta ( user_id, meta_key, meta_value )
+ VALUES
+ ( %d, %s, %s )", $user_id, $meta_key, $meta_value) );
+ } else if ( $cur->meta_value != $meta_value ) {
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->usermeta SET meta_value = %s WHERE user_id = %d AND meta_key = %s", $meta_value, $user_id, $meta_key) );
+ } else {
+ return false;
+ }
+
+ wp_cache_delete($user_id, 'users');
+
+ return true;
+}
+
+//
+// Private helper functions
+//
+
+/**
+ * Setup global user vars.
+ *
+ * Used by set_current_user() for back compat. Might be deprecated in the
+ * future.
+ *
+ * @since 2.0.4
+ * @global string $userdata User description.
+ * @global string $user_login The user username for logging in
+ * @global int $user_level The level of the user
+ * @global int $user_ID The ID of the user
+ * @global string $user_email The email address of the user
+ * @global string $user_url The url in the user's profile
+ * @global string $user_pass_md5 MD5 of the user's password
+ * @global string $user_identity The display name of the user
+ *
+ * @param int $user_id Optional. User ID to setup global data.
+ */
+function setup_userdata($user_id = '') {
+ global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_pass_md5, $user_identity;
+
+ if ( '' == $user_id )
+ $user = wp_get_current_user();
+ else
+ $user = new WP_User($user_id);
+
+ if ( 0 == $user->ID )
+ return;
+
+ $userdata = $user->data;
+ $user_login = $user->user_login;
+ $user_level = (int) isset($user->user_level) ? $user->user_level : 0;
+ $user_ID = (int) $user->ID;
+ $user_email = $user->user_email;
+ $user_url = $user->user_url;
+ $user_pass_md5 = md5($user->user_pass);
+ $user_identity = $user->display_name;
+}
+
+/**
+ * Create dropdown HTML content of users.
+ *
+ * The content can either be displayed, which it is by default or retrieved by
+ * setting the 'echo' argument. The 'include' and 'exclude' arguments do not
+ * need to be used; all users will be displayed in that case. Only one can be
+ * used, either 'include' or 'exclude', but not both.
+ *
+ * The available arguments are as follows:
+ *
+ * show_option_all - Text to show all and whether HTML option exists.
+ * show_option_none - Text for show none and whether HTML option exists.
+ *
+ * orderby - SQL order by clause for what order the users appear. Default is
+ * 'display_name'.
+ * order - Default is 'ASC'. Can also be 'DESC'.
+ * include - User IDs to include.
+ * exclude - User IDs to exclude.
+ * multi - Default is 'false'. Whether to skip the ID attribute on the 'select' element.
+ * show - Default is 'display_name'. User table column to display. If the selected item is empty then the user_login will be displayed in parentesis
+ * echo - Default is '1'. Whether to display or retrieve content.
+ * selected - Which User ID is selected.
+ * name - Default is 'user'. Name attribute of select element.
+ * class - Class attribute of select element.
+ *
+ *
+ * @since 2.3.0
+ * @uses $wpdb WordPress database object for queries
+ *
+ * @param string|array $args Optional. Override defaults.
+ * @return string|null Null on display. String of HTML content on retrieve.
+ */
+function wp_dropdown_users( $args = '' ) {
+ global $wpdb;
+ $defaults = array(
+ 'show_option_all' => '', 'show_option_none' => '',
+ 'orderby' => 'display_name', 'order' => 'ASC',
+ 'include' => '', 'exclude' => '', 'multi' => 0,
+ 'show' => 'display_name', 'echo' => 1,
+ 'selected' => 0, 'name' => 'user', 'class' => ''
+ );
+
+ $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $query = "SELECT * FROM $wpdb->users";
+
+ $query_where = array();
+
+ if ( is_array($include) )
+ $include = join(',', $include);
+ $include = preg_replace('/[^0-9,]/', '', $include); // (int)
+ if ( $include )
+ $query_where[] = "ID IN ($include)";
+
+ if ( is_array($exclude) )
+ $exclude = join(',', $exclude);
+ $exclude = preg_replace('/[^0-9,]/', '', $exclude); // (int)
+ if ( $exclude )
+ $query_where[] = "ID NOT IN ($exclude)";
+
+ if ( $query_where )
+ $query .= " WHERE " . join(' AND', $query_where);
+
+ $query .= " ORDER BY $orderby $order";
+
+ $users = $wpdb->get_results( $query );
+
+ $output = '';
+ if ( !empty($users) ) {
+ $id = $multi ? "" : "id='$name'";
+
+ $output = "\n";
+
+ if ( $show_option_all )
+ $output .= "\t$show_option_all \n";
+
+ if ( $show_option_none )
+ $output .= "\t$show_option_none \n";
+
+ foreach ( (array) $users as $user ) {
+ $user->ID = (int) $user->ID;
+ $_selected = $user->ID == $selected ? " selected='selected'" : '';
+ $display = !empty($user->$show) ? $user->$show : '('. $user->user_login . ')';
+ $output .= "\t" . wp_specialchars($display) . " \n";
+ }
+
+ $output .= " ";
+ }
+
+ $output = apply_filters('wp_dropdown_users', $output);
+
+ if ( $echo )
+ echo $output;
+
+ return $output;
+}
+
+/**
+ * Add user meta data as properties to given user object.
+ *
+ * The finished user data is cached, but the cache is not used to fill in the
+ * user data for the given object. Once the function has been used, the cache
+ * should be used to retrieve user data. The purpose seems then to be to ensure
+ * that the data in the object is always fresh.
+ *
+ * @access private
+ * @since 2.5.0
+ * @uses $wpdb WordPress database object for queries
+ *
+ * @param object $user The user data object.
+ */
+function _fill_user( &$user ) {
+ global $wpdb;
+
+ $show = $wpdb->hide_errors();
+ $metavalues = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value FROM $wpdb->usermeta WHERE user_id = %d", $user->ID));
+ $wpdb->show_errors($show);
+
+ if ( $metavalues ) {
+ foreach ( (array) $metavalues as $meta ) {
+ $value = maybe_unserialize($meta->meta_value);
+ $user->{$meta->meta_key} = $value;
+ }
+ }
+
+ $level = $wpdb->prefix . 'user_level';
+ if ( isset( $user->{$level} ) )
+ $user->user_level = $user->{$level};
+
+ // For backwards compat.
+ if ( isset($user->first_name) )
+ $user->user_firstname = $user->first_name;
+ if ( isset($user->last_name) )
+ $user->user_lastname = $user->last_name;
+ if ( isset($user->description) )
+ $user->user_description = $user->description;
+
+ wp_cache_add($user->ID, $user, 'users');
+ wp_cache_add($user->user_login, $user->ID, 'userlogins');
+ wp_cache_add($user->user_email, $user->ID, 'useremail');
+}
+
+?>
diff -uNr a/blog/wp-includes/vars.php b/blog/wp-includes/vars.php
--- a/blog/wp-includes/vars.php false
+++ b/blog/wp-includes/vars.php bf179d74ecdb7163d699dfcb2bd9af2265036922bc38370b8055272a65c8e39eb111f5fede821f6d0aafd8a9a94ec918df2f5873b1fa60a755bee372a232be26
@@ -0,0 +1,76 @@
+
\ No newline at end of file
diff -uNr a/blog/wp-includes/version.php b/blog/wp-includes/version.php
--- a/blog/wp-includes/version.php false
+++ b/blog/wp-includes/version.php 4e7639e4f9150532d4f7c719ac85057e2f6a4120b1bc2de8eea033d2b3610a36902a5762c7e357df6ac30c3b3a58d779bbf1d85525acd54e27d95d21bf535e01
@@ -0,0 +1,20 @@
+
diff -uNr a/blog/wp-includes/widgets.php b/blog/wp-includes/widgets.php
--- a/blog/wp-includes/widgets.php false
+++ b/blog/wp-includes/widgets.php 2ab094dde6cb1285deea3e3731c9c0562e66965990f7e070ca303ab2761bb80d275f23d4c6b8a03dc72f37ec14a4dd1c5da669b77ec75c841038619f0b9a13c3
@@ -0,0 +1,2099 @@
+ 1 ) {
+ $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
+ } else {
+ $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
+ }
+
+ if (isset($args['id'])) {
+ $_args['id'] = $args['id'];
+ } else {
+ $n = count($wp_registered_sidebars);
+ do {
+ $n++;
+ $_args['id'] = "sidebar-$n";
+ } while (isset($wp_registered_sidebars[$_args['id']]));
+ }
+
+ register_sidebar($_args);
+ }
+}
+
+/**
+ * Builds the definition for a single sidebar and returns the ID.
+ *
+ * The $args parameter takes either a string or an array with 'name' and 'id'
+ * contained in either usage. It will be noted that the values will be applied
+ * to all sidebars, so if creating more than one, it will be advised to allow
+ * for WordPress to create the defaults for you.
+ *
+ * Example for string would be 'name=whatever;id=whatever1'
and for
+ * the array it would be array(
+ * 'name' => 'whatever',
+ * 'id' => 'whatever1')
.
+ *
+ * name - The name of the sidebar, which presumably the title which will be
+ * displayed.
+ * id - The unique identifier by which the sidebar will be called by.
+ * before_widget - The content that will prepended to the widgets when they are
+ * displayed.
+ * after_widget - The content that will be appended to the widgets when they are
+ * displayed.
+ * before_title - The content that will be prepended to the title when displayed.
+ * after_title - the content that will be appended to the title when displayed.
+ *
+ * Content is assumed to be HTML and should be formatted as such, but
+ * doesn't have to be.
+ *
+ * @since 2.2.0
+ * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
+ * @uses parse_str() Converts a string to an array to be used in the rest of the function.
+ * @usedby register_sidebars()
+ *
+ * @param string|array $args Builds Sidebar based off of 'name' and 'id' values
+ * @return string The sidebar id that was added.
+ */
+function register_sidebar($args = array()) {
+ global $wp_registered_sidebars;
+
+ if ( is_string($args) )
+ parse_str($args, $args);
+
+ $i = count($wp_registered_sidebars) + 1;
+
+ $defaults = array(
+ 'name' => sprintf(__('Sidebar %d'), $i ),
+ 'id' => "sidebar-$i",
+ 'before_widget' => '',
+ 'after_widget' => " \n",
+ 'before_title' => '\n",
+ );
+
+ $sidebar = array_merge($defaults, (array) $args);
+
+ $wp_registered_sidebars[$sidebar['id']] = $sidebar;
+
+ return $sidebar['id'];
+}
+
+/**
+ * Removes a sidebar from the list.
+ *
+ * @since 2.2.0
+ *
+ * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
+ *
+ * @param string $name The ID of the sidebar when it was added.
+ */
+function unregister_sidebar( $name ) {
+ global $wp_registered_sidebars;
+
+ if ( isset( $wp_registered_sidebars[$name] ) )
+ unset( $wp_registered_sidebars[$name] );
+}
+
+/**
+ * Register widget for sidebar with backwards compatibility.
+ *
+ * Allows $name to be an array that accepts either three elements to grab the
+ * first element and the third for the name or just uses the first element of
+ * the array for the name.
+ *
+ * Passes to {@link wp_register_sidebar_widget()} after argument list and
+ * backwards compatibility is complete.
+ *
+ * @since 2.2.0
+ * @uses wp_register_sidebar_widget() Passes the compiled arguments.
+ *
+ * @param string|int $name Widget ID.
+ * @param callback $output_callback Run when widget is called.
+ * @param string $classname Classname widget option.
+ * @param mixed $params,... Widget parameters.
+ */
+function register_sidebar_widget($name, $output_callback, $classname = '') {
+ // Compat
+ if ( is_array($name) ) {
+ if ( count($name) == 3 )
+ $name = sprintf($name[0], $name[2]);
+ else
+ $name = $name[0];
+ }
+
+ $id = sanitize_title($name);
+ $options = array();
+ if ( !empty($classname) && is_string($classname) )
+ $options['classname'] = $classname;
+ $params = array_slice(func_get_args(), 2);
+ $args = array($id, $name, $output_callback, $options);
+ if ( !empty($params) )
+ $args = array_merge($args, $params);
+
+ call_user_func_array('wp_register_sidebar_widget', $args);
+}
+
+/**
+ * Register widget for use in sidebars.
+ *
+ * The default widget option is 'classname' that can be override.
+ *
+ * The function can also be used to unregister widgets when $output_callback
+ * parameter is an empty string.
+ *
+ * @since 2.2.0
+ *
+ * @uses $wp_registered_widgets Uses stored registered widgets.
+ * @uses $wp_register_widget_defaults Retrieves widget defaults.
+ *
+ * @param int|string $id Widget ID.
+ * @param string $name Widget display title.
+ * @param callback $output_callback Run when widget is called.
+ * @param array|string Optional. $options Widget Options.
+ * @param mixed $params,... Widget parameters to add to widget.
+ * @return null Will return if $output_callback is empty after removing widget.
+ */
+function wp_register_sidebar_widget($id, $name, $output_callback, $options = array()) {
+ global $wp_registered_widgets;
+
+ $id = strtolower($id);
+
+ if ( empty($output_callback) ) {
+ unset($wp_registered_widgets[$id]);
+ return;
+ }
+
+ $defaults = array('classname' => $output_callback);
+ $options = wp_parse_args($options, $defaults);
+ $widget = array(
+ 'name' => $name,
+ 'id' => $id,
+ 'callback' => $output_callback,
+ 'params' => array_slice(func_get_args(), 4)
+ );
+ $widget = array_merge($widget, $options);
+
+ if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) )
+ $wp_registered_widgets[$id] = $widget;
+}
+
+/**
+ * Retrieve description for widget.
+ *
+ * When registering widgets, the options can also include 'description' that
+ * describes the widget for display on the widget administration panel or
+ * in the theme.
+ *
+ * @since 2.5.0
+ *
+ * @param int|string $id Widget ID.
+ * @return string Widget description, if available. Null on failure to retrieve description.
+ */
+function wp_widget_description( $id ) {
+ if ( !is_scalar($id) )
+ return;
+
+ global $wp_registered_widgets;
+
+ if ( isset($wp_registered_widgets[$id]['description']) )
+ return wp_specialchars( $wp_registered_widgets[$id]['description'] );
+}
+
+/**
+ * Alias of {@link wp_unregister_sidebar_widget()}.
+ *
+ * @see wp_unregister_sidebar_widget()
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $id Widget ID.
+ */
+function unregister_sidebar_widget($id) {
+ return wp_unregister_sidebar_widget($id);
+}
+
+/**
+ * Remove widget from sidebar.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $id Widget ID.
+ */
+function wp_unregister_sidebar_widget($id) {
+ wp_register_sidebar_widget($id, '', '');
+ wp_unregister_widget_control($id);
+}
+
+/**
+ * Registers widget control callback for customizing options.
+ *
+ * Allows $name to be an array that accepts either three elements to grab the
+ * first element and the third for the name or just uses the first element of
+ * the array for the name.
+ *
+ * Passes to {@link wp_register_widget_control()} after the argument list has
+ * been compiled.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $name Sidebar ID.
+ * @param callback $control_callback Widget control callback to display and process form.
+ * @param int $width Widget width.
+ * @param int $height Widget height.
+ */
+function register_widget_control($name, $control_callback, $width = '', $height = '') {
+ // Compat
+ if ( is_array($name) ) {
+ if ( count($name) == 3 )
+ $name = sprintf($name[0], $name[2]);
+ else
+ $name = $name[0];
+ }
+
+ $id = sanitize_title($name);
+ $options = array();
+ if ( !empty($width) )
+ $options['width'] = $width;
+ if ( !empty($height) )
+ $options['height'] = $height;
+ $params = array_slice(func_get_args(), 4);
+ $args = array($id, $name, $control_callback, $options);
+ if ( !empty($params) )
+ $args = array_merge($args, $params);
+
+ call_user_func_array('wp_register_widget_control', $args);
+}
+
+/**
+ * Registers widget control callback for customizing options.
+ *
+ * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
+ * option is never used. The 'width' option is the width of the fully expanded
+ * control form, but try hard to use the default width. The 'id_base' is for
+ * multi-widgets (widgets which allow multiple instances such as the text
+ * widget), an id_base must be provided. The widget id will end up looking like
+ * {$id_base}-{$unique_number}.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $id Sidebar ID.
+ * @param string $name Sidebar display name.
+ * @param callback $control_callback Run when sidebar is displayed.
+ * @param array|string $options Optional. Widget options. See above long description.
+ * @param mixed $params,... Optional. Additional parameters to add to widget.
+ */
+function wp_register_widget_control($id, $name, $control_callback, $options = array()) {
+ global $wp_registered_widget_controls;
+
+ $id = strtolower($id);
+
+ if ( empty($control_callback) ) {
+ unset($wp_registered_widget_controls[$id]);
+ return;
+ }
+
+ if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
+ return;
+
+ $defaults = array('width' => 250, 'height' => 200 ); // height is never used
+ $options = wp_parse_args($options, $defaults);
+ $options['width'] = (int) $options['width'];
+ $options['height'] = (int) $options['height'];
+
+ $widget = array(
+ 'name' => $name,
+ 'id' => $id,
+ 'callback' => $control_callback,
+ 'params' => array_slice(func_get_args(), 4)
+ );
+ $widget = array_merge($widget, $options);
+
+ $wp_registered_widget_controls[$id] = $widget;
+}
+
+/**
+ * Alias of {@link wp_unregister_widget_control()}.
+ *
+ * @since 2.2.0
+ * @see wp_unregister_widget_control()
+ *
+ * @param int|string $id Widget ID.
+ */
+function unregister_widget_control($id) {
+ return wp_unregister_widget_control($id);
+}
+
+/**
+ * Remove control callback for widget.
+ *
+ * @since 2.2.0
+ * @uses wp_register_widget_control() Unregisters by using empty callback.
+ *
+ * @param int|string $id Widget ID.
+ */
+function wp_unregister_widget_control($id) {
+ return wp_register_widget_control($id, '', '');
+}
+
+/**
+ * Display dynamic sidebar.
+ *
+ * By default it displays the default sidebar or 'sidebar-1'. The 'sidebar-1' is
+ * not named by the theme, the actual name is '1', but 'sidebar-' is added to
+ * the registered sidebars for the name. If you named your sidebar 'after-post',
+ * then the parameter $index will still be 'after-post', but the lookup will be
+ * for 'sidebar-after-post'.
+ *
+ * It is confusing for the $index parameter, but just know that it should just
+ * work. When you register the sidebar in the theme, you will use the same name
+ * for this function or "Pay no heed to the man behind the curtain." Just accept
+ * it as an oddity of WordPress sidebar register and display.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $index Optional, default is 1. Name or ID of dynamic sidebar.
+ * @return bool True, if widget sidebar was found and called. False if not found or not called.
+ */
+function dynamic_sidebar($index = 1) {
+ global $wp_registered_sidebars, $wp_registered_widgets;
+
+ if ( is_int($index) ) {
+ $index = "sidebar-$index";
+ } else {
+ $index = sanitize_title($index);
+ foreach ( (array) $wp_registered_sidebars as $key => $value ) {
+ if ( sanitize_title($value['name']) == $index ) {
+ $index = $key;
+ break;
+ }
+ }
+ }
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+
+ if ( empty($wp_registered_sidebars[$index]) || !array_key_exists($index, $sidebars_widgets) || !is_array($sidebars_widgets[$index]) || empty($sidebars_widgets[$index]) )
+ return false;
+
+ $sidebar = $wp_registered_sidebars[$index];
+
+ $did_one = false;
+ foreach ( (array) $sidebars_widgets[$index] as $id ) {
+ $params = array_merge(
+ array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
+ (array) $wp_registered_widgets[$id]['params']
+ );
+
+ // Substitute HTML id and class attributes into before_widget
+ $classname_ = '';
+ foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
+ if ( is_string($cn) )
+ $classname_ .= '_' . $cn;
+ elseif ( is_object($cn) )
+ $classname_ .= '_' . get_class($cn);
+ }
+ $classname_ = ltrim($classname_, '_');
+ $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
+
+ $params = apply_filters( 'dynamic_sidebar_params', $params );
+
+ $callback = $wp_registered_widgets[$id]['callback'];
+
+ if ( is_callable($callback) ) {
+ call_user_func_array($callback, $params);
+ $did_one = true;
+ }
+ }
+
+ return $did_one;
+}
+
+/**
+ * Whether widget is registered using callback with widget ID.
+ *
+ * Will only check if both parameters are used. Used to find which sidebar the
+ * widget is located in, but requires that both the callback and the widget ID
+ * be known.
+ *
+ * @since 2.2.0
+ *
+ * @param callback $callback Widget callback to check.
+ * @param int $widget_id Optional, but needed for checking. Widget ID.
+/* @return mixed false if widget is not active or id of sidebar in which the widget is active.
+ */
+function is_active_widget($callback, $widget_id = false) {
+ global $wp_registered_widgets;
+
+ $sidebars_widgets = wp_get_sidebars_widgets(false);
+
+ if ( is_array($sidebars_widgets) ) foreach ( $sidebars_widgets as $sidebar => $widgets )
+ if ( is_array($widgets) ) foreach ( $widgets as $widget )
+ if ( isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback )
+ if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
+ return $sidebar;
+
+
+ return false;
+}
+
+/**
+ * Whether the dynamic sidebar is enabled and used by theme.
+ *
+ * @since 2.2.0
+ *
+ * @return bool True, if using widgets. False, if not using widgets.
+ */
+function is_dynamic_sidebar() {
+ global $wp_registered_widgets, $wp_registered_sidebars;
+ $sidebars_widgets = get_option('sidebars_widgets');
+ foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
+ if ( count($sidebars_widgets[$index]) ) {
+ foreach ( (array) $sidebars_widgets[$index] as $widget )
+ if ( array_key_exists($widget, $wp_registered_widgets) )
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Internal Functions */
+
+/**
+ * Retrieve full list of sidebars and their widgets.
+ *
+ * Will upgrade sidebar widget list, if needed. Will also save updated list, if
+ * needed.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @param bool $update Optional, default is true. Whether to save upgrade of widget array list.
+ * @return array Upgraded list of widgets to version 2 array format.
+ */
+function wp_get_sidebars_widgets($update = true) {
+ global $wp_registered_widgets, $wp_registered_sidebars;
+
+ $sidebars_widgets = get_option('sidebars_widgets');
+ $_sidebars_widgets = array();
+
+ if ( !isset($sidebars_widgets['array_version']) )
+ $sidebars_widgets['array_version'] = 1;
+
+ switch ( $sidebars_widgets['array_version'] ) {
+ case 1 :
+ foreach ( (array) $sidebars_widgets as $index => $sidebar )
+ if ( is_array($sidebar) )
+ foreach ( (array) $sidebar as $i => $name ) {
+ $id = strtolower($name);
+ if ( isset($wp_registered_widgets[$id]) ) {
+ $_sidebars_widgets[$index][$i] = $id;
+ continue;
+ }
+ $id = sanitize_title($name);
+ if ( isset($wp_registered_widgets[$id]) ) {
+ $_sidebars_widgets[$index][$i] = $id;
+ continue;
+ }
+
+ $found = false;
+
+ foreach ( $wp_registered_widgets as $widget_id => $widget ) {
+ if ( strtolower($widget['name']) == strtolower($name) ) {
+ $_sidebars_widgets[$index][$i] = $widget['id'];
+ $found = true;
+ break;
+ } elseif ( sanitize_title($widget['name']) == sanitize_title($name) ) {
+ $_sidebars_widgets[$index][$i] = $widget['id'];
+ $found = true;
+ break;
+ }
+ }
+
+ if ( $found )
+ continue;
+
+ unset($_sidebars_widgets[$index][$i]);
+ }
+ $_sidebars_widgets['array_version'] = 2;
+ $sidebars_widgets = $_sidebars_widgets;
+ unset($_sidebars_widgets);
+
+ case 2 :
+ $sidebars = array_keys( $wp_registered_sidebars );
+ if ( !empty( $sidebars ) ) {
+ // Move the known-good ones first
+ foreach ( (array) $sidebars as $id ) {
+ if ( array_key_exists( $id, $sidebars_widgets ) ) {
+ $_sidebars_widgets[$id] = $sidebars_widgets[$id];
+ unset($sidebars_widgets[$id], $sidebars[$id]);
+ }
+ }
+
+ // Assign to each unmatched registered sidebar the first available orphan
+ unset( $sidebars_widgets[ 'array_version' ] );
+ while ( ( $sidebar = array_shift( $sidebars ) ) && $widgets = array_shift( $sidebars_widgets ) )
+ $_sidebars_widgets[ $sidebar ] = $widgets;
+
+ $_sidebars_widgets['array_version'] = 3;
+ $sidebars_widgets = $_sidebars_widgets;
+ unset($_sidebars_widgets);
+ }
+
+ if ( $update )
+ update_option('sidebars_widgets', $sidebars_widgets);
+ }
+
+ unset($sidebars_widgets['array_version']);
+
+ $sidebars_widgets = apply_filters('sidebars_widgets', $sidebars_widgets);
+ return $sidebars_widgets;
+}
+
+/**
+ * Set the sidebar widget option to update sidebars.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @param array $sidebars_widgets Sidebar widgets and their settings.
+ */
+function wp_set_sidebars_widgets( $sidebars_widgets ) {
+ if ( !isset( $sidebars_widgets['array_version'] ) )
+ $sidebars_widgets['array_version'] = 3;
+ update_option( 'sidebars_widgets', $sidebars_widgets );
+}
+
+/**
+ * Retrieve default registered sidebars list.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @return array
+ */
+function wp_get_widget_defaults() {
+ global $wp_registered_sidebars;
+
+ $defaults = array();
+
+ foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
+ $defaults[$index] = array();
+
+ return $defaults;
+}
+
+/* Default Widgets */
+
+/**
+ * Display pages widget.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Widget arguments.
+ */
+function wp_widget_pages( $args ) {
+ extract( $args );
+ $options = get_option( 'widget_pages' );
+
+ $title = empty( $options['title'] ) ? __( 'Pages' ) : apply_filters('widget_title', $options['title']);
+ $sortby = empty( $options['sortby'] ) ? 'menu_order' : $options['sortby'];
+ $exclude = empty( $options['exclude'] ) ? '' : $options['exclude'];
+
+ if ( $sortby == 'menu_order' ) {
+ $sortby = 'menu_order, post_title';
+ }
+
+ $out = wp_list_pages( array('title_li' => '', 'echo' => 0, 'sort_column' => $sortby, 'exclude' => $exclude) );
+
+ if ( !empty( $out ) ) {
+?>
+
+
+
+
+
+
+
+
+
+ >
+ >
+ >
+
+
+
+
+
+
+
+
+
+ $before_title, 'title_after' => $after_title,
+ 'category_before' => $before_widget, 'category_after' => $after_widget,
+ 'show_images' => true, 'class' => 'linkcat widget'
+ )));
+}
+
+/**
+ * Display search widget.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Widget arguments.
+ */
+function wp_widget_search($args) {
+ extract($args);
+ echo $before_widget;
+
+ // Use current theme search form if it exists
+ get_search_form();
+
+ echo $after_widget;
+}
+
+/**
+ * Display archives widget.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Widget arguments.
+ */
+function wp_widget_archives($args) {
+ extract($args);
+ $options = get_option('widget_archives');
+ $c = $options['count'] ? '1' : '0';
+ $d = $options['dropdown'] ? '1' : '0';
+ $title = empty($options['title']) ? __('Archives') : apply_filters('widget_title', $options['title']);
+
+ echo $before_widget;
+ echo $before_title . $title . $after_title;
+
+ if($d) {
+?>
+
+
+
+
+
+
+ id="archives-count" name="archives-count" />
+
+ id="archives-dropdown" name="archives-dropdown" />
+
+
+
+
+
+
+
+
+
+
+';
+ get_calendar();
+ echo ' ';
+ echo $after_widget;
+}
+
+/**
+ * Display and process calendar widget options form.
+ *
+ * @since 2.2.0
+ */
+function wp_widget_calendar_control() {
+ $options = $newoptions = get_option('widget_calendar');
+ if ( isset($_POST["calendar-submit"]) ) {
+ $newoptions['title'] = strip_tags(stripslashes($_POST["calendar-title"]));
+ }
+ if ( $options != $newoptions ) {
+ $options = $newoptions;
+ update_option('widget_calendar', $options);
+ }
+ $title = attribute_escape($options['title']);
+?>
+
+
+ $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract( $widget_args, EXTR_SKIP );
+
+ $options = get_option('widget_text');
+ if ( !isset($options[$number]) )
+ return;
+
+ $title = apply_filters('widget_title', $options[$number]['title']);
+ $text = apply_filters( 'widget_text', $options[$number]['text'] );
+?>
+
+
+
+
+ $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract( $widget_args, EXTR_SKIP );
+
+ $options = get_option('widget_text');
+ if ( !is_array($options) )
+ $options = array();
+
+ if ( !$updated && !empty($_POST['sidebar']) ) {
+ $sidebar = (string) $_POST['sidebar'];
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+ if ( isset($sidebars_widgets[$sidebar]) )
+ $this_sidebar =& $sidebars_widgets[$sidebar];
+ else
+ $this_sidebar = array();
+
+ foreach ( (array) $this_sidebar as $_widget_id ) {
+ if ( 'wp_widget_text' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+ $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+ if ( !in_array( "text-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed.
+ unset($options[$widget_number]);
+ }
+ }
+
+ foreach ( (array) $_POST['widget-text'] as $widget_number => $widget_text ) {
+ if ( !isset($widget_text['text']) && isset($options[$widget_number]) ) // user clicked cancel
+ continue;
+ $title = strip_tags(stripslashes($widget_text['title']));
+ if ( current_user_can('unfiltered_html') )
+ $text = stripslashes( $widget_text['text'] );
+ else
+ $text = stripslashes(wp_filter_post_kses( $widget_text['text'] ));
+ $options[$widget_number] = compact( 'title', 'text' );
+ }
+
+ update_option('widget_text', $options);
+ $updated = true;
+ }
+
+ if ( -1 == $number ) {
+ $title = '';
+ $text = '';
+ $number = '%i%';
+ } else {
+ $title = attribute_escape($options[$number]['title']);
+ $text = format_to_edit($options[$number]['text']);
+ }
+?>
+
+
+
+
+
+ 'widget_text', 'description' => __('Arbitrary text or HTML'));
+ $control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'text');
+ $name = __('Text');
+
+ $id = false;
+ foreach ( (array) array_keys($options) as $o ) {
+ // Old widgets can have null values for some reason
+ if ( !isset($options[$o]['title']) || !isset($options[$o]['text']) )
+ continue;
+ $id = "text-$o"; // Never never never translate an id
+ wp_register_sidebar_widget($id, $name, 'wp_widget_text', $widget_ops, array( 'number' => $o ));
+ wp_register_widget_control($id, $name, 'wp_widget_text_control', $control_ops, array( 'number' => $o ));
+ }
+
+ // If there are none, we register the widget's existance with a generic template
+ if ( !$id ) {
+ wp_register_sidebar_widget( 'text-1', $name, 'wp_widget_text', $widget_ops, array( 'number' => -1 ) );
+ wp_register_widget_control( 'text-1', $name, 'wp_widget_text_control', $control_ops, array( 'number' => -1 ) );
+ }
+}
+
+/**
+ * Display categories widget.
+ *
+ * Allows multiple category widgets.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Widget arguments.
+ * @param int $number Widget number.
+ */
+function wp_widget_categories($args, $widget_args = 1) {
+ extract($args, EXTR_SKIP);
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract($widget_args, EXTR_SKIP);
+
+ $options = get_option('widget_categories');
+ if ( !isset($options[$number]) )
+ return;
+
+ $c = $options[$number]['count'] ? '1' : '0';
+ $h = $options[$number]['hierarchical'] ? '1' : '0';
+ $d = $options[$number]['dropdown'] ? '1' : '0';
+
+ $title = empty($options[$number]['title']) ? __('Categories') : apply_filters('widget_title', $options[$number]['title']);
+
+ echo $before_widget;
+ echo $before_title . $title . $after_title;
+
+ $cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h);
+
+ if ( $d ) {
+ $cat_args['show_option_none'] = __('Select Category');
+ wp_dropdown_categories($cat_args);
+?>
+
+
+
+
+
+ $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract($widget_args, EXTR_SKIP);
+
+ $options = get_option('widget_categories');
+
+ if ( !is_array( $options ) )
+ $options = array();
+
+ if ( !$updated && !empty($_POST['sidebar']) ) {
+ $sidebar = (string) $_POST['sidebar'];
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+ if ( isset($sidebars_widgets[$sidebar]) )
+ $this_sidebar =& $sidebars_widgets[$sidebar];
+ else
+ $this_sidebar = array();
+
+ foreach ( (array) $this_sidebar as $_widget_id ) {
+ if ( 'wp_widget_categories' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+ $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+ if ( !in_array( "categories-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed.
+ unset($options[$widget_number]);
+ }
+ }
+
+ foreach ( (array) $_POST['widget-categories'] as $widget_number => $widget_cat ) {
+ if ( !isset($widget_cat['title']) && isset($options[$widget_number]) ) // user clicked cancel
+ continue;
+ $title = trim(strip_tags(stripslashes($widget_cat['title'])));
+ $count = isset($widget_cat['count']);
+ $hierarchical = isset($widget_cat['hierarchical']);
+ $dropdown = isset($widget_cat['dropdown']);
+ $options[$widget_number] = compact( 'title', 'count', 'hierarchical', 'dropdown' );
+ }
+
+ update_option('widget_categories', $options);
+ $updated = true;
+ }
+
+ if ( -1 == $number ) {
+ $title = '';
+ $count = false;
+ $hierarchical = false;
+ $dropdown = false;
+ $number = '%i%';
+ } else {
+ $title = attribute_escape( $options[$number]['title'] );
+ $count = (bool) $options[$number]['count'];
+ $hierarchical = (bool) $options[$number]['hierarchical'];
+ $dropdown = (bool) $options[$number]['dropdown'];
+ }
+?>
+
+
+
+
+
+
+
+
+
+ />
+
+
+
+
+ />
+
+
+
+
+ />
+
+
+
+
+
+ 'widget_categories', 'description' => __( "A list or dropdown of categories" ) );
+
+ $name = __( 'Categories' );
+
+ $id = false;
+ foreach ( (array) array_keys($options) as $o ) {
+ // Old widgets can have null values for some reason
+ if ( !isset($options[$o]['title']) )
+ continue;
+ $id = "categories-$o";
+ wp_register_sidebar_widget( $id, $name, 'wp_widget_categories', $widget_ops, array( 'number' => $o ) );
+ wp_register_widget_control( $id, $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => $o ) );
+ }
+
+ // If there are none, we register the widget's existance with a generic template
+ if ( !$id ) {
+ wp_register_sidebar_widget( 'categories-1', $name, 'wp_widget_categories', $widget_ops, array( 'number' => -1 ) );
+ wp_register_widget_control( 'categories-1', $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => -1 ) );
+ }
+}
+
+/**
+ * Upgrade previous category widget to current version.
+ *
+ * @since 2.3.0
+ *
+ * @return array
+ */
+function wp_widget_categories_upgrade() {
+ $options = get_option( 'widget_categories' );
+
+ if ( !isset( $options['title'] ) )
+ return $options;
+
+ $newoptions = array( 1 => $options );
+
+ update_option( 'widget_categories', $newoptions );
+
+ $sidebars_widgets = get_option( 'sidebars_widgets' );
+ if ( is_array( $sidebars_widgets ) ) {
+ foreach ( $sidebars_widgets as $sidebar => $widgets ) {
+ if ( is_array( $widgets ) ) {
+ foreach ( $widgets as $widget )
+ $new_widgets[$sidebar][] = ( $widget == 'categories' ) ? 'categories-1' : $widget;
+ } else {
+ $new_widgets[$sidebar] = $widgets;
+ }
+ }
+ if ( $new_widgets != $sidebars_widgets )
+ update_option( 'sidebars_widgets', $new_widgets );
+ }
+
+ return $newoptions;
+}
+
+/**
+ * Display recent entries widget.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Widget arguments.
+ * @return int Displayed cache.
+ */
+function wp_widget_recent_entries($args) {
+ if ( '%BEG_OF_TITLE%' != $args['before_title'] ) {
+ if ( $output = wp_cache_get('widget_recent_entries', 'widget') )
+ return print($output);
+ ob_start();
+ }
+
+ extract($args);
+ $options = get_option('widget_recent_entries');
+ $title = empty($options['title']) ? __('Recent Posts') : apply_filters('widget_title', $options['title']);
+ if ( !$number = (int) $options['number'] )
+ $number = 10;
+ else if ( $number < 1 )
+ $number = 1;
+ else if ( $number > 15 )
+ $number = 15;
+
+ $r = new WP_Query(array('showposts' => $number, 'what_to_show' => 'posts', 'nopaging' => 0, 'post_status' => 'publish', 'caller_get_posts' => 1));
+ if ($r->have_posts()) :
+?>
+
+
+
+ have_posts()) : $r->the_post(); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 15 )
+ $number = 15;
+
+ if ( !$comments = wp_cache_get( 'recent_comments', 'widget' ) ) {
+ $comments = $wpdb->get_results("SELECT * FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT $number");
+ wp_cache_add( 'recent_comments', $comments, 'widget' );
+ }
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'widget_recent_comments', 'description' => __( 'The most recent comments' ) );
+ wp_register_sidebar_widget('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments', $widget_ops);
+ wp_register_widget_control('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments_control');
+
+ if ( is_active_widget('wp_widget_recent_comments') )
+ add_action('wp_head', 'wp_widget_recent_comments_style');
+}
+
+/**
+ * Display RSS widget.
+ *
+ * Allows for multiple widgets to be displayed.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Widget arguments.
+ * @param int $number Widget number.
+ */
+function wp_widget_rss($args, $widget_args = 1) {
+ extract($args, EXTR_SKIP);
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract($widget_args, EXTR_SKIP);
+
+ $options = get_option('widget_rss');
+
+ if ( !isset($options[$number]) )
+ return;
+
+ if ( isset($options[$number]['error']) && $options[$number]['error'] )
+ return;
+
+ $url = $options[$number]['url'];
+ while ( strstr($url, 'http') != $url )
+ $url = substr($url, 1);
+ if ( empty($url) )
+ return;
+
+ require_once(ABSPATH . WPINC . '/rss.php');
+
+ $rss = fetch_rss($url);
+ $link = clean_url(strip_tags($rss->channel['link']));
+ while ( strstr($link, 'http') != $link )
+ $link = substr($link, 1);
+ $desc = attribute_escape(strip_tags(html_entity_decode($rss->channel['description'], ENT_QUOTES)));
+ $title = $options[$number]['title'];
+ if ( empty($title) )
+ $title = htmlentities(strip_tags($rss->channel['title']));
+ if ( empty($title) )
+ $title = $desc;
+ if ( empty($title) )
+ $title = __('Unknown Feed');
+ $title = apply_filters('widget_title', $title );
+ $url = clean_url(strip_tags($url));
+ if ( file_exists(dirname(__FILE__) . '/rss.png') )
+ $icon = str_replace(ABSPATH, site_url() . '/', dirname(__FILE__)) . '/rss.png';
+ else
+ $icon = includes_url('images/rss.png');
+ $title = " ";
+
+ echo $before_widget;
+ echo $before_title . $title . $after_title;
+
+ wp_widget_rss_output( $rss, $options[$number] );
+
+ echo $after_widget;
+}
+
+/**
+ * Display the RSS entries in a list.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array|object $rss RSS url.
+ * @param array $args Widget arguments.
+ */
+function wp_widget_rss_output( $rss, $args = array() ) {
+ if ( is_string( $rss ) ) {
+ require_once(ABSPATH . WPINC . '/rss.php');
+ if ( !$rss = fetch_rss($rss) )
+ return;
+ } elseif ( is_array($rss) && isset($rss['url']) ) {
+ require_once(ABSPATH . WPINC . '/rss.php');
+ $args = $rss;
+ if ( !$rss = fetch_rss($rss['url']) )
+ return;
+ } elseif ( !is_object($rss) ) {
+ return;
+ }
+
+ $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0 );
+ $args = wp_parse_args( $args, $default_args );
+ extract( $args, EXTR_SKIP );
+
+ $items = (int) $items;
+ if ( $items < 1 || 20 < $items )
+ $items = 10;
+ $show_summary = (int) $show_summary;
+ $show_author = (int) $show_author;
+ $show_date = (int) $show_date;
+
+ if ( is_array( $rss->items ) && !empty( $rss->items ) ) {
+ $rss->items = array_slice($rss->items, 0, $items);
+ echo '';
+ foreach ( (array) $rss->items as $item ) {
+ while ( strstr($item['link'], 'http') != $item['link'] )
+ $item['link'] = substr($item['link'], 1);
+ $link = clean_url(strip_tags($item['link']));
+ $title = attribute_escape(strip_tags($item['title']));
+ if ( empty($title) )
+ $title = __('Untitled');
+ $desc = '';
+ if ( isset( $item['description'] ) && is_string( $item['description'] ) )
+ $desc = str_replace(array("\n", "\r"), ' ', attribute_escape(strip_tags(html_entity_decode($item['description'], ENT_QUOTES))));
+ elseif ( isset( $item['summary'] ) && is_string( $item['summary'] ) )
+ $desc = str_replace(array("\n", "\r"), ' ', attribute_escape(strip_tags(html_entity_decode($item['summary'], ENT_QUOTES))));
+ if ( 360 < strlen( $desc ) )
+ $desc = wp_html_excerpt( $desc, 360 ) . ' […]';
+ $summary = $desc;
+
+ if ( $show_summary ) {
+ $desc = '';
+ $summary = wp_specialchars( $summary );
+ $summary = "";
+ } else {
+ $summary = '';
+ }
+
+ $date = '';
+ if ( $show_date ) {
+ if ( isset($item['pubdate']) )
+ $date = $item['pubdate'];
+ elseif ( isset($item['published']) )
+ $date = $item['published'];
+
+ if ( $date ) {
+ if ( $date_stamp = strtotime( $date ) )
+ $date = ' ';
+ else
+ $date = '';
+ }
+ }
+
+ $author = '';
+ if ( $show_author ) {
+ if ( isset($item['dc']['creator']) )
+ $author = ' ' . wp_specialchars( strip_tags( $item['dc']['creator'] ) ) . ' ';
+ elseif ( isset($item['author_name']) )
+ $author = ' ' . wp_specialchars( strip_tags( $item['author_name'] ) ) . ' ';
+ }
+
+ if ( $link == '' ) {
+ echo "$title{$date}{$summary}{$author} ";
+ } else {
+ echo "{$date}{$summary}{$author} ";
+ }
+}
+ echo ' ';
+ } else {
+ echo '' . __( 'An error has occurred; the feed is probably down. Try again later.' ) . ' ';
+ }
+}
+
+/**
+ * Display and process RSS widget control form.
+ *
+ * @since 2.2.0
+ *
+ * @param int $widget_args Widget number.
+ */
+function wp_widget_rss_control($widget_args) {
+ global $wp_registered_widgets;
+ static $updated = false;
+
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract($widget_args, EXTR_SKIP);
+
+ $options = get_option('widget_rss');
+ if ( !is_array($options) )
+ $options = array();
+
+ $urls = array();
+ foreach ( (array) $options as $option )
+ if ( isset($option['url']) )
+ $urls[$option['url']] = true;
+
+ if ( !$updated && 'POST' == $_SERVER['REQUEST_METHOD'] && !empty($_POST['sidebar']) ) {
+ $sidebar = (string) $_POST['sidebar'];
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+ if ( isset($sidebars_widgets[$sidebar]) )
+ $this_sidebar =& $sidebars_widgets[$sidebar];
+ else
+ $this_sidebar = array();
+
+ foreach ( (array) $this_sidebar as $_widget_id ) {
+ if ( 'wp_widget_rss' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+ $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+ if ( !in_array( "rss-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed.
+ unset($options[$widget_number]);
+ }
+ }
+
+ foreach( (array) $_POST['widget-rss'] as $widget_number => $widget_rss ) {
+ if ( !isset($widget_rss['url']) && isset($options[$widget_number]) ) // user clicked cancel
+ continue;
+ $widget_rss = stripslashes_deep( $widget_rss );
+ $url = sanitize_url(strip_tags($widget_rss['url']));
+ $options[$widget_number] = wp_widget_rss_process( $widget_rss, !isset($urls[$url]) );
+ }
+
+ update_option('widget_rss', $options);
+ $updated = true;
+ }
+
+ if ( -1 == $number ) {
+ $title = '';
+ $url = '';
+ $items = 10;
+ $error = false;
+ $number = '%i%';
+ $show_summary = 0;
+ $show_author = 0;
+ $show_date = 0;
+ } else {
+ extract( (array) $options[$number] );
+ }
+
+ wp_widget_rss_form( compact( 'number', 'title', 'url', 'items', 'error', 'show_summary', 'show_author', 'show_date' ) );
+}
+
+/**
+ * Display RSS widget options form.
+ *
+ * The options for what fields are displayed for the RSS form are all booleans
+ * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
+ * 'show_date'.
+ *
+ * @since 2.5.0
+ *
+ * @param array|string $args Values for input fields.
+ * @param array $inputs Override default display options.
+ */
+function wp_widget_rss_form( $args, $inputs = null ) {
+
+ $default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
+ $inputs = wp_parse_args( $inputs, $default_inputs );
+ extract( $args );
+ extract( $inputs, EXTR_SKIP);
+
+ $number = attribute_escape( $number );
+ $title = attribute_escape( $title );
+ $url = attribute_escape( $url );
+ $items = (int) $items;
+ if ( $items < 1 || 20 < $items )
+ $items = 10;
+ $show_summary = (int) $show_summary;
+ $show_author = (int) $show_author;
+ $show_date = (int) $show_date;
+
+ if ( $inputs['url'] ) :
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+channel['link']));
+ while ( strstr($link, 'http') != $link )
+ $link = substr($link, 1);
+ }
+ }
+
+ return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
+}
+
+/**
+ * Register RSS widget to allow multiple RSS widgets on startup.
+ *
+ * @since 2.2.0
+ */
+function wp_widget_rss_register() {
+ if ( !$options = get_option('widget_rss') )
+ $options = array();
+ $widget_ops = array('classname' => 'widget_rss', 'description' => __( 'Entries from any RSS or Atom feed' ));
+ $control_ops = array('width' => 400, 'height' => 200, 'id_base' => 'rss');
+ $name = __('RSS');
+
+ $id = false;
+ foreach ( (array) array_keys($options) as $o ) {
+ // Old widgets can have null values for some reason
+ if ( !isset($options[$o]['url']) || !isset($options[$o]['title']) || !isset($options[$o]['items']) )
+ continue;
+ $id = "rss-$o"; // Never never never translate an id
+ wp_register_sidebar_widget($id, $name, 'wp_widget_rss', $widget_ops, array( 'number' => $o ));
+ wp_register_widget_control($id, $name, 'wp_widget_rss_control', $control_ops, array( 'number' => $o ));
+ }
+
+ // If there are none, we register the widget's existance with a generic template
+ if ( !$id ) {
+ wp_register_sidebar_widget( 'rss-1', $name, 'wp_widget_rss', $widget_ops, array( 'number' => -1 ) );
+ wp_register_widget_control( 'rss-1', $name, 'wp_widget_rss_control', $control_ops, array( 'number' => -1 ) );
+ }
+}
+
+/**
+ * Display tag cloud widget.
+ *
+ * @since 2.3.0
+ *
+ * @param array $args Widget arguments.
+ */
+function wp_widget_tag_cloud($args) {
+ extract($args);
+ $options = get_option('widget_tag_cloud');
+ $title = empty($options['title']) ? __('Tags') : apply_filters('widget_title', $options['title']);
+
+ echo $before_widget;
+ echo $before_title . $title . $after_title;
+ wp_tag_cloud();
+ echo $after_widget;
+}
+
+/**
+ * Manage WordPress Tag Cloud widget options.
+ *
+ * Displays management form for changing the tag cloud widget title.
+ *
+ * @since 2.3.0
+ */
+function wp_widget_tag_cloud_control() {
+ $options = $newoptions = get_option('widget_tag_cloud');
+
+ if ( isset($_POST['tag-cloud-submit']) ) {
+ $newoptions['title'] = strip_tags(stripslashes($_POST['tag-cloud-title']));
+ }
+
+ if ( $options != $newoptions ) {
+ $options = $newoptions;
+ update_option('widget_tag_cloud', $options);
+ }
+
+ $title = attribute_escape( $options['title'] );
+?>
+
+
+
+
+ 'widget_pages', 'description' => __( "Your blog's WordPress Pages") );
+ wp_register_sidebar_widget('pages', __('Pages'), 'wp_widget_pages', $widget_ops);
+ wp_register_widget_control('pages', __('Pages'), 'wp_widget_pages_control' );
+
+ $widget_ops = array('classname' => 'widget_calendar', 'description' => __( "A calendar of your blog's posts") );
+ wp_register_sidebar_widget('calendar', __('Calendar'), 'wp_widget_calendar', $widget_ops);
+ wp_register_widget_control('calendar', __('Calendar'), 'wp_widget_calendar_control' );
+
+ $widget_ops = array('classname' => 'widget_archive', 'description' => __( "A monthly archive of your blog's posts") );
+ wp_register_sidebar_widget('archives', __('Archives'), 'wp_widget_archives', $widget_ops);
+ wp_register_widget_control('archives', __('Archives'), 'wp_widget_archives_control' );
+
+ $widget_ops = array('classname' => 'widget_links', 'description' => __( "Your blogroll") );
+ wp_register_sidebar_widget('links', __('Links'), 'wp_widget_links', $widget_ops);
+
+ $widget_ops = array('classname' => 'widget_meta', 'description' => __( "Log in/out, admin, feed and WordPress links") );
+ wp_register_sidebar_widget('meta', __('Meta'), 'wp_widget_meta', $widget_ops);
+ wp_register_widget_control('meta', __('Meta'), 'wp_widget_meta_control' );
+
+ $widget_ops = array('classname' => 'widget_search', 'description' => __( "A search form for your blog") );
+ wp_register_sidebar_widget('search', __('Search'), 'wp_widget_search', $widget_ops);
+
+ $widget_ops = array('classname' => 'widget_recent_entries', 'description' => __( "The most recent posts on your blog") );
+ wp_register_sidebar_widget('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries', $widget_ops);
+ wp_register_widget_control('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries_control' );
+
+ $widget_ops = array('classname' => 'widget_tag_cloud', 'description' => __( "Your most used tags in cloud format") );
+ wp_register_sidebar_widget('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud', $widget_ops);
+ wp_register_widget_control('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud_control' );
+
+ wp_widget_categories_register();
+ wp_widget_text_register();
+ wp_widget_rss_register();
+ wp_widget_recent_comments_register();
+
+ do_action('widgets_init');
+}
+
+add_action('init', 'wp_widgets_init', 1);
+
+/*
+ * Pattern for multi-widget (allows multiple instances such as the text widget).
+ *
+ * Make sure to close the comments after copying.
+
+/**
+ * Displays widget.
+ *
+ * Supports multiple widgets.
+ *
+ * @param array $args Widget arguments.
+ * @param array|int $widget_args Widget number. Which of the several widgets of this type do we mean.
+ * /
+function widget_many( $args, $widget_args = 1 ) {
+ extract( $args, EXTR_SKIP );
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract( $widget_args, EXTR_SKIP );
+
+ // Data should be stored as array: array( number => data for that instance of the widget, ... )
+ $options = get_option('widget_many');
+ if ( !isset($options[$number]) )
+ return;
+
+ echo $before_widget;
+
+ // Do stuff for this widget, drawing data from $options[$number]
+
+ echo $after_widget;
+}
+
+/**
+ * Displays form for a particular instance of the widget.
+ *
+ * Also updates the data after a POST submit.
+ *
+ * @param array|int $widget_args Widget number. Which of the several widgets of this type do we mean.
+ * /
+function widget_many_control( $widget_args = 1 ) {
+ global $wp_registered_widgets;
+ static $updated = false; // Whether or not we have already updated the data after a POST submit
+
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ extract( $widget_args, EXTR_SKIP );
+
+ // Data should be stored as array: array( number => data for that instance of the widget, ... )
+ $options = get_option('widget_many');
+ if ( !is_array($options) )
+ $options = array();
+
+ // We need to update the data
+ if ( !$updated && !empty($_POST['sidebar']) ) {
+ // Tells us what sidebar to put the data in
+ $sidebar = (string) $_POST['sidebar'];
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+ if ( isset($sidebars_widgets[$sidebar]) )
+ $this_sidebar =& $sidebars_widgets[$sidebar];
+ else
+ $this_sidebar = array();
+
+ foreach ( $this_sidebar as $_widget_id ) {
+ // Remove all widgets of this type from the sidebar. We'll add the new data in a second. This makes sure we don't get any duplicate data
+ // since widget ids aren't necessarily persistent across multiple updates
+ if ( 'widget_many' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+ $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+ if ( !in_array( "many-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed. "many-$widget_number" is "{id_base}-{widget_number}
+ unset($options[$widget_number]);
+ }
+ }
+
+ foreach ( (array) $_POST['widget-many'] as $widget_number => $widget_many_instance ) {
+ // compile data from $widget_many_instance
+ if ( !isset($widget_many_instance['something']) && isset($options[$widget_number]) ) // user clicked cancel
+ continue;
+ $something = wp_specialchars( $widget_many_instance['something'] );
+ $options[$widget_number] = array( 'something' => $something ); // Even simple widgets should store stuff in array, rather than in scalar
+ }
+
+ update_option('widget_many', $options);
+
+ $updated = true; // So that we don't go through this more than once
+ }
+
+
+ // Here we echo out the form
+ if ( -1 == $number ) { // We echo out a template for a form which can be converted to a specific form later via JS
+ $something = '';
+ $number = '%i%';
+ } else {
+ $something = attribute_escape($options[$number]['something']);
+ }
+
+ // The form has inputs with names like widget-many[$number][something] so that all data for that instance of
+ // the widget are stored in one $_POST variable: $_POST['widget-many'][$number]
+?>
+
+
+
+
+ 'widget_many', 'description' => __('Widget which allows multiple instances'));
+ $control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'many');
+ $name = __('Many');
+
+ $registered = false;
+ foreach ( array_keys($options) as $o ) {
+ // Old widgets can have null values for some reason
+ if ( !isset($options[$o]['something']) ) // we used 'something' above in our exampple. Replace with with whatever your real data are.
+ continue;
+
+ // $id should look like {$id_base}-{$o}
+ $id = "many-$o"; // Never never never translate an id
+ $registered = true;
+ wp_register_sidebar_widget( $id, $name, 'widget_many', $widget_ops, array( 'number' => $o ) );
+ wp_register_widget_control( $id, $name, 'widget_many_control', $control_ops, array( 'number' => $o ) );
+ }
+
+ // If there are none, we register the widget's existance with a generic template
+ if ( !$registered ) {
+ wp_register_sidebar_widget( 'many-1', $name, 'widget_many', $widget_ops, array( 'number' => -1 ) );
+ wp_register_widget_control( 'many-1', $name, 'widget_many_control', $control_ops, array( 'number' => -1 ) );
+ }
+}
+
+// This is important
+add_action( 'widgets_init', 'widget_many_register' )
+
+*/
+
+?>
diff -uNr a/blog/wp-includes/wp-db.php b/blog/wp-includes/wp-db.php
--- a/blog/wp-includes/wp-db.php false
+++ b/blog/wp-includes/wp-db.php 6012308d31760e385ebd1bf0ecbedcd52a03a57edf0d8dde838ff219be715cc66fe6a49adc3d2bd958861a7bd439fde63c1464a2ea241368ec1f66d90b968049
@@ -0,0 +1,996 @@
+__construct($dbuser, $dbpassword, $dbname, $dbhost);
+ }
+
+ /**
+ * Connects to the database server and selects a database
+ *
+ * PHP5 style constructor for compatibility with PHP5. Does
+ * the actual setting up of the class properties and connection
+ * to the database.
+ *
+ * @since 2.0.8
+ *
+ * @param string $dbuser MySQL database user
+ * @param string $dbpassword MySQL database password
+ * @param string $dbname MySQL database name
+ * @param string $dbhost MySQL database host
+ */
+ function __construct($dbuser, $dbpassword, $dbname, $dbhost) {
+ register_shutdown_function(array(&$this, "__destruct"));
+
+ if ( defined('WP_DEBUG') and WP_DEBUG == true )
+ $this->show_errors();
+
+ if ( defined('DB_CHARSET') )
+ $this->charset = DB_CHARSET;
+
+ if ( defined('DB_COLLATE') )
+ $this->collate = DB_COLLATE;
+
+ $this->dbh = @mysql_connect($dbhost, $dbuser, $dbpassword, true);
+ if (!$this->dbh) {
+ $this->bail(sprintf(/*WP_I18N_DB_CONN_ERROR*/"
+Error establishing a database connection
+This either means that the username and password information in your wp-config.php
file is incorrect or we can't contact the database server at %s
. This could mean your host's database server is down.
+
+ Are you sure you have the correct username and password?
+ Are you sure that you have typed the correct hostname?
+ Are you sure that the database server is running?
+
+If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums .
+"/*/WP_I18N_DB_CONN_ERROR*/, $dbhost));
+ return;
+ }
+
+ $this->ready = true;
+
+ if ( $this->has_cap( 'collation' ) ) {
+ $collation_query = '';
+ if ( !empty($this->charset) ) {
+ $collation_query = "SET NAMES '{$this->charset}'";
+ if (!empty($this->collate) )
+ $collation_query .= " COLLATE '{$this->collate}'";
+ }
+
+ if ( !empty($collation_query) )
+ $this->query($collation_query);
+
+ }
+
+ $this->select($dbname);
+ }
+
+ /**
+ * PHP5 style destructor and will run when database object is destroyed.
+ *
+ * @since 2.0.8
+ *
+ * @return bool Always true
+ */
+ function __destruct() {
+ return true;
+ }
+
+ /**
+ * Sets the table prefix for the WordPress tables.
+ *
+ * Also allows for the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE to
+ * override the WordPress users and usersmeta tables.
+ *
+ * @since 2.5.0
+ *
+ * @param string $prefix Alphanumeric name for the new prefix.
+ * @return string Old prefix
+ */
+ function set_prefix($prefix) {
+
+ if ( preg_match('|[^a-z0-9_]|i', $prefix) )
+ return new WP_Error('invalid_db_prefix', /*WP_I18N_DB_BAD_PREFIX*/'Invalid database prefix'/*/WP_I18N_DB_BAD_PREFIX*/);
+
+ $old_prefix = $this->prefix;
+ $this->prefix = $prefix;
+
+ foreach ( (array) $this->tables as $table )
+ $this->$table = $this->prefix . $table;
+
+ if ( defined('CUSTOM_USER_TABLE') )
+ $this->users = CUSTOM_USER_TABLE;
+
+ if ( defined('CUSTOM_USER_META_TABLE') )
+ $this->usermeta = CUSTOM_USER_META_TABLE;
+
+ return $old_prefix;
+ }
+
+ /**
+ * Selects a database using the current database connection.
+ *
+ * The database name will be changed based on the current database
+ * connection. On failure, the execution will bail and display an DB error.
+ *
+ * @since 0.71
+ *
+ * @param string $db MySQL database name
+ * @return null Always null.
+ */
+ function select($db) {
+ if (!@mysql_select_db($db, $this->dbh)) {
+ $this->ready = false;
+ $this->bail(sprintf(/*WP_I18N_DB_SELECT_DB*/'
+Can’t select database
+We were able to connect to the database server (which means your username and password is okay) but not able to select the %1$s
database.
+
+Are you sure it exists?
+Does the user %2$s
have permission to use the %1$s
database?
+On some systems the name of your database is prefixed with your username, so it would be like username_%1$s
. Could that be the problem?
+
+If you don\'t know how to setup a database you should contact your host . If all else fails you may find help at the WordPress Support Forums .
'/*/WP_I18N_DB_SELECT_DB*/, $db, DB_USER));
+ return;
+ }
+ }
+
+ /**
+ * Escapes content for insertion into the database, for security
+ *
+ * @since 0.71
+ *
+ * @param string $string
+ * @return string query safe string
+ */
+ function escape($string) {
+ return addslashes( $string );
+ // Disable rest for now, causing problems
+ /*
+ if( !$this->dbh || version_compare( phpversion(), '4.3.0' ) == '-1' )
+ return mysql_escape_string( $string );
+ else
+ return mysql_real_escape_string( $string, $this->dbh );
+ */
+ }
+
+ /**
+ * Escapes content by reference for insertion into the database, for security
+ *
+ * @since 2.3.0
+ *
+ * @param string $s
+ */
+ function escape_by_ref(&$s) {
+ $s = $this->escape($s);
+ }
+
+ /**
+ * Prepares a SQL query for safe use, using sprintf() syntax.
+ *
+ * @link http://php.net/sprintf See for syntax to use for query string.
+ * @since 2.3.0
+ *
+ * @param null|string $args If string, first parameter must be query statement
+ * @param mixed $args,... If additional parameters, they will be set inserted into the query.
+ * @return null|string Sanitized query string
+ */
+ function prepare($args=null) {
+ if ( is_null( $args ) )
+ return;
+ $args = func_get_args();
+ $query = array_shift($args);
+ $query = str_replace("'%s'", '%s', $query); // in case someone mistakenly already singlequoted it
+ $query = str_replace('"%s"', '%s', $query); // doublequote unquoting
+ $query = str_replace('%s', "'%s'", $query); // quote the strings
+ array_walk($args, array(&$this, 'escape_by_ref'));
+ return @vsprintf($query, $args);
+ }
+
+ /**
+ * Print SQL/DB error.
+ *
+ * @since 0.71
+ * @global array $EZSQL_ERROR Stores error information of query and error string
+ *
+ * @param string $str The error to display
+ * @return bool False if the showing of errors is disabled.
+ */
+ function print_error($str = '') {
+ global $EZSQL_ERROR;
+
+ if (!$str) $str = mysql_error($this->dbh);
+ $EZSQL_ERROR[] = array ('query' => $this->last_query, 'error_str' => $str);
+
+ if ( $this->suppress_errors )
+ return false;
+
+ if ( $caller = $this->get_caller() )
+ $error_str = sprintf(/*WP_I18N_DB_QUERY_ERROR_FULL*/'WordPress database error %1$s for query %2$s made by %3$s'/*/WP_I18N_DB_QUERY_ERROR_FULL*/, $str, $this->last_query, $caller);
+ else
+ $error_str = sprintf(/*WP_I18N_DB_QUERY_ERROR*/'WordPress database error %1$s for query %2$s'/*/WP_I18N_DB_QUERY_ERROR*/, $str, $this->last_query);
+
+ $log_error = true;
+ if ( ! function_exists('error_log') )
+ $log_error = false;
+
+ $log_file = @ini_get('error_log');
+ if ( !empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file) )
+ $log_error = false;
+
+ if ( $log_error )
+ @error_log($error_str, 0);
+
+ // Is error output turned on or not..
+ if ( !$this->show_errors )
+ return false;
+
+ $str = htmlspecialchars($str, ENT_QUOTES);
+ $query = htmlspecialchars($this->last_query, ENT_QUOTES);
+
+ // If there is an error then take note of it
+ print "
+
WordPress database error: [$str]
+ $query
+
";
+ }
+
+ /**
+ * Enables showing of database errors.
+ *
+ * This function should be used only to enable showing of errors.
+ * wpdb::hide_errors() should be used instead for hiding of errors. However,
+ * this function can be used to enable and disable showing of database
+ * errors.
+ *
+ * @since 0.71
+ *
+ * @param bool $show Whether to show or hide errors
+ * @return bool Old value for showing errors.
+ */
+ function show_errors( $show = true ) {
+ $errors = $this->show_errors;
+ $this->show_errors = $show;
+ return $errors;
+ }
+
+ /**
+ * Disables showing of database errors.
+ *
+ * @since 0.71
+ *
+ * @return bool Whether showing of errors was active or not
+ */
+ function hide_errors() {
+ $show = $this->show_errors;
+ $this->show_errors = false;
+ return $show;
+ }
+
+ /**
+ * Whether to suppress database errors.
+ *
+ * @param unknown_type $suppress
+ * @return unknown
+ */
+ function suppress_errors( $suppress = true ) {
+ $errors = $this->suppress_errors;
+ $this->suppress_errors = $suppress;
+ return $errors;
+ }
+
+ /**
+ * Kill cached query results.
+ *
+ * @since 0.71
+ */
+ function flush() {
+ $this->last_result = array();
+ $this->col_info = null;
+ $this->last_query = null;
+ }
+
+ /**
+ * Perform a MySQL database query, using current database connection.
+ *
+ * More information can be found on the codex page.
+ *
+ * @since 0.71
+ *
+ * @param string $query
+ * @return unknown
+ */
+ function query($query) {
+ if ( ! $this->ready )
+ return false;
+
+ // filter the query, if filters are available
+ // NOTE: some queries are made before the plugins have been loaded, and thus cannot be filtered with this method
+ if ( function_exists('apply_filters') )
+ $query = apply_filters('query', $query);
+
+ // initialise return
+ $return_val = 0;
+ $this->flush();
+
+ // Log how the function was called
+ $this->func_call = "\$db->query(\"$query\")";
+
+ // Keep track of the last query for debug..
+ $this->last_query = $query;
+
+ // Perform the query via std mysql_query function..
+ if ( defined('SAVEQUERIES') && SAVEQUERIES )
+ $this->timer_start();
+
+ $this->result = @mysql_query($query, $this->dbh);
+ ++$this->num_queries;
+
+ if ( defined('SAVEQUERIES') && SAVEQUERIES )
+ $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
+
+ // If there is an error then take note of it..
+ if ( $this->last_error = mysql_error($this->dbh) ) {
+ $this->print_error();
+ return false;
+ }
+
+ if ( preg_match("/^\\s*(insert|delete|update|replace|alter) /i",$query) ) {
+ $this->rows_affected = mysql_affected_rows($this->dbh);
+ // Take note of the insert_id
+ if ( preg_match("/^\\s*(insert|replace) /i",$query) ) {
+ $this->insert_id = mysql_insert_id($this->dbh);
+ }
+ // Return number of rows affected
+ $return_val = $this->rows_affected;
+ } else {
+ $i = 0;
+ while ($i < @mysql_num_fields($this->result)) {
+ $this->col_info[$i] = @mysql_fetch_field($this->result);
+ $i++;
+ }
+ $num_rows = 0;
+ while ( $row = @mysql_fetch_object($this->result) ) {
+ $this->last_result[$num_rows] = $row;
+ $num_rows++;
+ }
+
+ @mysql_free_result($this->result);
+
+ // Log number of rows the query returned
+ $this->num_rows = $num_rows;
+
+ // Return number of rows selected
+ $return_val = $this->num_rows;
+ }
+
+ return $return_val;
+ }
+
+ /**
+ * Insert an array of data into a table.
+ *
+ * @since 2.5.0
+ *
+ * @param string $table WARNING: not sanitized!
+ * @param array $data Should not already be SQL-escaped
+ * @return mixed Results of $this->query()
+ */
+ function insert($table, $data) {
+ $data = add_magic_quotes($data);
+ $fields = array_keys($data);
+ return $this->query("INSERT INTO $table (`" . implode('`,`',$fields) . "`) VALUES ('".implode("','",$data)."')");
+ }
+
+ /**
+ * Update a row in the table with an array of data.
+ *
+ * @since 2.5.0
+ *
+ * @param string $table WARNING: not sanitized!
+ * @param array $data Should not already be SQL-escaped
+ * @param array $where A named array of WHERE column => value relationships. Multiple member pairs will be joined with ANDs. WARNING: the column names are not currently sanitized!
+ * @return mixed Results of $this->query()
+ */
+ function update($table, $data, $where){
+ $data = add_magic_quotes($data);
+ $bits = $wheres = array();
+ foreach ( (array) array_keys($data) as $k )
+ $bits[] = "`$k` = '$data[$k]'";
+
+ if ( is_array( $where ) )
+ foreach ( $where as $c => $v )
+ $wheres[] = "$c = '" . $this->escape( $v ) . "'";
+ else
+ return false;
+
+ return $this->query( "UPDATE $table SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres ) );
+ }
+
+ /**
+ * Retrieve one variable from the database.
+ *
+ * This combines the functionality of wpdb::get_row() and wpdb::get_col(),
+ * so both the column and row can be picked.
+ *
+ * It is possible to use this function without executing more queries. If
+ * you already made a query, you can set the $query to 'null' value and just
+ * retrieve either the column and row of the last query result.
+ *
+ * @since 0.71
+ *
+ * @param string $query Can be null as well, for caching
+ * @param int $x Column num to return
+ * @param int $y Row num to return
+ * @return mixed Database query results
+ */
+ function get_var($query=null, $x = 0, $y = 0) {
+ $this->func_call = "\$db->get_var(\"$query\",$x,$y)";
+ if ( $query )
+ $this->query($query);
+
+ // Extract var out of cached results based x,y vals
+ if ( !empty( $this->last_result[$y] ) ) {
+ $values = array_values(get_object_vars($this->last_result[$y]));
+ }
+
+ // If there is a value return it else return null
+ return (isset($values[$x]) && $values[$x]!=='') ? $values[$x] : null;
+ }
+
+ /**
+ * Retrieve one row from the database.
+ *
+ * @since 0.71
+ *
+ * @param string $query SQL query
+ * @param string $output ARRAY_A | ARRAY_N | OBJECT
+ * @param int $y Row num to return
+ * @return mixed Database query results
+ */
+ function get_row($query = null, $output = OBJECT, $y = 0) {
+ $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
+ if ( $query )
+ $this->query($query);
+ else
+ return null;
+
+ if ( !isset($this->last_result[$y]) )
+ return null;
+
+ if ( $output == OBJECT ) {
+ return $this->last_result[$y] ? $this->last_result[$y] : null;
+ } elseif ( $output == ARRAY_A ) {
+ return $this->last_result[$y] ? get_object_vars($this->last_result[$y]) : null;
+ } elseif ( $output == ARRAY_N ) {
+ return $this->last_result[$y] ? array_values(get_object_vars($this->last_result[$y])) : null;
+ } else {
+ $this->print_error(/*WP_I18N_DB_GETROW_ERROR*/" \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N"/*/WP_I18N_DB_GETROW_ERROR*/);
+ }
+ }
+
+ /**
+ * Retrieve one column from the database.
+ *
+ * @since 0.71
+ *
+ * @param string $query Can be null as well, for caching
+ * @param int $x Col num to return. Starts from 0.
+ * @return array Column results
+ */
+ function get_col($query = null , $x = 0) {
+ if ( $query )
+ $this->query($query);
+
+ $new_array = array();
+ // Extract the column values
+ for ( $i=0; $i < count($this->last_result); $i++ ) {
+ $new_array[$i] = $this->get_var(null, $x, $i);
+ }
+ return $new_array;
+ }
+
+ /**
+ * Retrieve an entire result set from the database.
+ *
+ * @since 0.71
+ *
+ * @param string|null $query Can also be null to pull from the cache
+ * @param string $output ARRAY_A | ARRAY_N | OBJECT_K | OBJECT
+ * @return mixed Database query results
+ */
+ function get_results($query = null, $output = OBJECT) {
+ $this->func_call = "\$db->get_results(\"$query\", $output)";
+
+ if ( $query )
+ $this->query($query);
+ else
+ return null;
+
+ if ( $output == OBJECT ) {
+ // Return an integer-keyed array of row objects
+ return $this->last_result;
+ } elseif ( $output == OBJECT_K ) {
+ // Return an array of row objects with keys from column 1
+ // (Duplicates are discarded)
+ foreach ( $this->last_result as $row ) {
+ $key = array_shift( get_object_vars( $row ) );
+ if ( !isset( $new_array[ $key ] ) )
+ $new_array[ $key ] = $row;
+ }
+ return $new_array;
+ } elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
+ // Return an integer-keyed array of...
+ if ( $this->last_result ) {
+ $i = 0;
+ foreach( (array) $this->last_result as $row ) {
+ if ( $output == ARRAY_N ) {
+ // ...integer-keyed row arrays
+ $new_array[$i] = array_values( get_object_vars( $row ) );
+ } else {
+ // ...column name-keyed row arrays
+ $new_array[$i] = get_object_vars( $row );
+ }
+ ++$i;
+ }
+ return $new_array;
+ }
+ }
+ }
+
+ /**
+ * Retrieve column metadata from the last query.
+ *
+ * @since 0.71
+ *
+ * @param string $info_type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill
+ * @param int $col_offset 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type
+ * @return mixed Column Results
+ */
+ function get_col_info($info_type = 'name', $col_offset = -1) {
+ if ( $this->col_info ) {
+ if ( $col_offset == -1 ) {
+ $i = 0;
+ foreach( (array) $this->col_info as $col ) {
+ $new_array[$i] = $col->{$info_type};
+ $i++;
+ }
+ return $new_array;
+ } else {
+ return $this->col_info[$col_offset]->{$info_type};
+ }
+ }
+ }
+
+ /**
+ * Starts the timer, for debugging purposes.
+ *
+ * @since 1.5.0
+ *
+ * @return bool Always returns true
+ */
+ function timer_start() {
+ $mtime = microtime();
+ $mtime = explode(' ', $mtime);
+ $this->time_start = $mtime[1] + $mtime[0];
+ return true;
+ }
+
+ /**
+ * Stops the debugging timer.
+ *
+ * @since 1.5.0
+ *
+ * @return int Total time spent on the query, in milliseconds
+ */
+ function timer_stop() {
+ $mtime = microtime();
+ $mtime = explode(' ', $mtime);
+ $time_end = $mtime[1] + $mtime[0];
+ $time_total = $time_end - $this->time_start;
+ return $time_total;
+ }
+
+ /**
+ * Wraps fatal errors in a nice header and footer and dies.
+ *
+ * @since 1.5.0
+ *
+ * @param string $message
+ * @return unknown
+ */
+ function bail($message) {
+ if ( !$this->show_errors ) {
+ if ( class_exists('WP_Error') )
+ $this->error = new WP_Error('500', $message);
+ else
+ $this->error = $message;
+ return false;
+ }
+ wp_die($message);
+ }
+
+ /**
+ * Whether or not MySQL database is minimal required version.
+ *
+ * @since 2.5.0
+ * @uses $wp_version
+ *
+ * @return WP_Error
+ */
+ function check_database_version()
+ {
+ global $wp_version;
+ // Make sure the server has MySQL 4.0
+ if ( version_compare($this->db_version(), '4.0.0', '<') )
+ return new WP_Error('database_version',sprintf(__('ERROR : WordPress %s requires MySQL 4.0.0 or higher'), $wp_version));
+ }
+
+ /**
+ * Whether of not the database version supports collation.
+ *
+ * Called when WordPress is generating the table scheme.
+ *
+ * @since 2.5.0
+ *
+ * @return bool True if collation is supported, false if version does not
+ */
+ function supports_collation()
+ {
+ return $this->has_cap( 'collation' );
+ }
+
+ /**
+ * Generic function to determine if a database supports a particular feature
+ * @param string $db_cap the feature
+ * @param false|string|resource $dbh_or_table the databaese (the current database, the database housing the specified table, or the database of the mysql resource)
+ * @return bool
+ */
+ function has_cap( $db_cap ) {
+ $version = $this->db_version();
+
+ switch ( strtolower( $db_cap ) ) :
+ case 'collation' : // @since 2.5.0
+ case 'group_concat' : // @since 2.7
+ case 'subqueries' : // @since 2.7
+ return version_compare($version, '4.1', '>=');
+ break;
+ endswitch;
+
+ return false;
+ }
+
+ /**
+ * Retrieve the name of the function that called wpdb.
+ *
+ * Requires PHP 4.3 and searches up the list of functions until it reaches
+ * the one that would most logically had called this method.
+ *
+ * @since 2.5.0
+ *
+ * @return string The name of the calling function
+ */
+ function get_caller() {
+ // requires PHP 4.3+
+ if ( !is_callable('debug_backtrace') )
+ return '';
+
+ $bt = debug_backtrace();
+ $caller = array();
+
+ $bt = array_reverse( $bt );
+ foreach ( (array) $bt as $call ) {
+ if ( @$call['class'] == __CLASS__ )
+ continue;
+ $function = $call['function'];
+ if ( isset( $call['class'] ) )
+ $function = $call['class'] . "->$function";
+ $caller[] = $function;
+ }
+ $caller = join( ', ', $caller );
+
+ return $caller;
+ }
+
+ /**
+ * The database version number
+ * @return false|string false on failure, version number on success
+ */
+ function db_version() {
+ return preg_replace('/[^0-9.].*/', '', mysql_get_server_info( $this->dbh ));
+ }
+}
+
+if ( ! isset($wpdb) ) {
+ /**
+ * WordPress Database Object, if it isn't set already in wp-content/db.php
+ * @global object $wpdb Creates a new wpdb object based on wp-config.php Constants for the database
+ * @since 0.71
+ */
+ $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
+}
+?>
diff -uNr a/blog/wp-includes/wp-diff.php b/blog/wp-includes/wp-diff.php
--- a/blog/wp-includes/wp-diff.php false
+++ b/blog/wp-includes/wp-diff.php 37a20fbecb6915bdf4afde9ad10f3bf9b118814cd1fc816451541e94dae4336f2cbb4aa795e78d91215e7289ef9e0394c27b233dc54e2b4572903e0b3cc48c4f
@@ -0,0 +1,471 @@
+$parent( $params );
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $header
+ * @return string
+ */
+ function _startBlock( $header ) {
+ return '';
+ }
+
+ /**
+ * @ignore
+ *
+ * @param array $lines
+ * @param string $prefix
+ */
+ function _lines( $lines, $prefix=' ' ) {
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $line HTML-escape the value.
+ * @return string
+ */
+ function addedLine( $line ) {
+ return "+{$line}";
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $line HTML-escape the value.
+ * @return string
+ */
+ function deletedLine( $line ) {
+ return "-{$line}";
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $line HTML-escape the value.
+ * @return string
+ */
+ function contextLine( $line ) {
+ return " {$line}";
+ }
+
+ /**
+ * @ignore
+ *
+ * @return string
+ */
+ function emptyLine() {
+ return ' ';
+ }
+
+ /**
+ * @ignore
+ * @access private
+ *
+ * @param array $lines
+ * @param bool $encode
+ * @return string
+ */
+ function _added( $lines, $encode = true ) {
+ $r = '';
+ foreach ($lines as $line) {
+ if ( $encode )
+ $line = htmlspecialchars( $line );
+ $r .= '' . $this->emptyLine() . $this->addedLine( $line ) . "\n";
+ }
+ return $r;
+ }
+
+ /**
+ * @ignore
+ * @access private
+ *
+ * @param array $lines
+ * @param bool $encode
+ * @return string
+ */
+ function _deleted( $lines, $encode = true ) {
+ $r = '';
+ foreach ($lines as $line) {
+ if ( $encode )
+ $line = htmlspecialchars( $line );
+ $r .= '' . $this->deletedLine( $line ) . $this->emptyLine() . "\n";
+ }
+ return $r;
+ }
+
+ /**
+ * @ignore
+ * @access private
+ *
+ * @param array $lines
+ * @param bool $encode
+ * @return string
+ */
+ function _context( $lines, $encode = true ) {
+ $r = '';
+ foreach ($lines as $line) {
+ if ( $encode )
+ $line = htmlspecialchars( $line );
+ $r .= '' .
+ $this->contextLine( $line ) . $this->contextLine( $line ) . "\n";
+ }
+ return $r;
+ }
+
+ /**
+ * Process changed lines to do word-by-word diffs for extra highlighting.
+ *
+ * (TRAC style) sometimes these lines can actually be deleted or added rows.
+ * We do additional processing to figure that out
+ *
+ * @access private
+ * @since 2.6.0
+ *
+ * @param array $orig
+ * @param array $final
+ * @return string
+ */
+ function _changed( $orig, $final ) {
+ $r = '';
+
+ // Does the aforementioned additional processing
+ // *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes
+ // match is numeric: an index in other column
+ // match is 'X': no match. It is a new row
+ // *_rows are column vectors for the orig column and the final column.
+ // row >= 0: an indix of the $orig or $final array
+ // row < 0: a blank row for that column
+ list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
+
+
+ // These will hold the word changes as determined by an inline diff
+ $orig_diffs = array();
+ $final_diffs = array();
+
+ // Compute word diffs for each matched pair using the inline diff
+ foreach ( $orig_matches as $o => $f ) {
+ if ( is_numeric($o) && is_numeric($f) ) {
+ $text_diff = new Text_Diff( 'auto', array( array($orig[$o]), array($final[$f]) ) );
+ $renderer = new $this->inline_diff_renderer;
+ $diff = $renderer->render( $text_diff );
+
+ // If they're too different, don't include any or
+ if ( $diff_count = preg_match_all( '!(.*? |.*?)!', $diff, $diff_matches ) ) {
+ // length of all text between or
+ $stripped_matches = strlen(strip_tags( join(' ', $diff_matches[0]) ));
+ // since we count lengith of text between or (instead of picking just one),
+ // we double the length of chars not in those tags.
+ $stripped_diff = strlen(strip_tags( $diff )) * 2 - $stripped_matches;
+ $diff_ratio = $stripped_matches / $stripped_diff;
+ if ( $diff_ratio > $this->_diff_threshold )
+ continue; // Too different. Don't save diffs.
+ }
+
+ // Un-inline the diffs by removing del or ins
+ $orig_diffs[$o] = preg_replace( '|.*? |', '', $diff );
+ $final_diffs[$f] = preg_replace( '|.*?|', '', $diff );
+ }
+ }
+
+ foreach ( array_keys($orig_rows) as $row ) {
+ // Both columns have blanks. Ignore them.
+ if ( $orig_rows[$row] < 0 && $final_rows[$row] < 0 )
+ continue;
+
+ // If we have a word based diff, use it. Otherwise, use the normal line.
+ $orig_line = isset($orig_diffs[$orig_rows[$row]])
+ ? $orig_diffs[$orig_rows[$row]]
+ : htmlspecialchars($orig[$orig_rows[$row]]);
+ $final_line = isset($final_diffs[$final_rows[$row]])
+ ? $final_diffs[$final_rows[$row]]
+ : htmlspecialchars($final[$final_rows[$row]]);
+
+ if ( $orig_rows[$row] < 0 ) { // Orig is blank. This is really an added row.
+ $r .= $this->_added( array($final_line), false );
+ } elseif ( $final_rows[$row] < 0 ) { // Final is blank. This is really a deleted row.
+ $r .= $this->_deleted( array($orig_line), false );
+ } else { // A true changed row.
+ $r .= '' . $this->deletedLine( $orig_line ) . $this->addedLine( $final_line ) . "\n";
+ }
+ }
+
+ return $r;
+ }
+
+ /**
+ * Takes changed blocks and matches which rows in orig turned into which rows in final.
+ *
+ * Returns
+ * *_matches ( which rows match with which )
+ * *_rows ( order of rows in each column interleaved with blank rows as
+ * necessary )
+ *
+ * @since 2.6.0
+ *
+ * @param unknown_type $orig
+ * @param unknown_type $final
+ * @return unknown
+ */
+ function interleave_changed_lines( $orig, $final ) {
+
+ // Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
+ $matches = array();
+ foreach ( array_keys($orig) as $o ) {
+ foreach ( array_keys($final) as $f ) {
+ $matches["$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] );
+ }
+ }
+ asort($matches); // Order by string distance.
+
+ $orig_matches = array();
+ $final_matches = array();
+
+ foreach ( $matches as $keys => $difference ) {
+ list($o, $f) = explode(',', $keys);
+ $o = (int) $o;
+ $f = (int) $f;
+
+ // Already have better matches for these guys
+ if ( isset($orig_matches[$o]) && isset($final_matches[$f]) )
+ continue;
+
+ // First match for these guys. Must be best match
+ if ( !isset($orig_matches[$o]) && !isset($final_matches[$f]) ) {
+ $orig_matches[$o] = $f;
+ $final_matches[$f] = $o;
+ continue;
+ }
+
+ // Best match of this final is already taken? Must mean this final is a new row.
+ if ( isset($orig_matches[$o]) )
+ $final_matches[$f] = 'x';
+
+ // Best match of this orig is already taken? Must mean this orig is a deleted row.
+ elseif ( isset($final_matches[$f]) )
+ $orig_matches[$o] = 'x';
+ }
+
+ // We read the text in this order
+ ksort($orig_matches);
+ ksort($final_matches);
+
+
+ // Stores rows and blanks for each column.
+ $orig_rows = $orig_rows_copy = array_keys($orig_matches);
+ $final_rows = array_keys($final_matches);
+
+ // Interleaves rows with blanks to keep matches aligned.
+ // We may end up with some extraneous blank rows, but we'll just ignore them later.
+ foreach ( $orig_rows_copy as $orig_row ) {
+ $final_pos = array_search($orig_matches[$orig_row], $final_rows, true);
+ $orig_pos = (int) array_search($orig_row, $orig_rows, true);
+
+ if ( false === $final_pos ) { // This orig is paired with a blank final.
+ array_splice( $final_rows, $orig_pos, 0, -1 );
+ } elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways. Pad final with blank rows.
+ $diff_pos = $final_pos - $orig_pos;
+ while ( $diff_pos < 0 )
+ array_splice( $final_rows, $orig_pos, 0, $diff_pos++ );
+ } elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways. Pad orig with blank rows.
+ $diff_pos = $orig_pos - $final_pos;
+ while ( $diff_pos < 0 )
+ array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ );
+ }
+ }
+
+
+ // Pad the ends with blank rows if the columns aren't the same length
+ $diff_count = count($orig_rows) - count($final_rows);
+ if ( $diff_count < 0 ) {
+ while ( $diff_count < 0 )
+ array_push($orig_rows, $diff_count++);
+ } elseif ( $diff_count > 0 ) {
+ $diff_count = -1 * $diff_count;
+ while ( $diff_count < 0 )
+ array_push($final_rows, $diff_count++);
+ }
+
+ return array($orig_matches, $final_matches, $orig_rows, $final_rows);
+
+/*
+ // Debug
+ echo "\n\n\n\n\n";
+
+ echo "-- DEBUG Matches: Orig -> Final --";
+
+ foreach ( $orig_matches as $o => $f ) {
+ echo "\n\n\n\n\n";
+ echo "ORIG: $o, FINAL: $f\n";
+ var_dump($orig[$o],$final[$f]);
+ }
+ echo "\n\n\n\n\n";
+
+ echo "-- DEBUG Matches: Final -> Orig --";
+
+ foreach ( $final_matches as $f => $o ) {
+ echo "\n\n\n\n\n";
+ echo "FINAL: $f, ORIG: $o\n";
+ var_dump($final[$f],$orig[$o]);
+ }
+ echo "\n\n\n\n\n";
+
+ echo "-- DEBUG Rows: Orig -- Final --";
+
+ echo "\n\n\n\n\n";
+ foreach ( $orig_rows as $row => $o ) {
+ if ( $o < 0 )
+ $o = 'X';
+ $f = $final_rows[$row];
+ if ( $f < 0 )
+ $f = 'X';
+ echo "$o -- $f\n";
+ }
+ echo "\n\n\n\n\n";
+
+ echo "-- END DEBUG --";
+
+ echo "\n\n\n\n\n";
+
+ return array($orig_matches, $final_matches, $orig_rows, $final_rows);
+*/
+ }
+
+ /**
+ * Computes a number that is intended to reflect the "distance" between two strings.
+ *
+ * @since 2.6.0
+ *
+ * @param string $string1
+ * @param string $string2
+ * @return int
+ */
+ function compute_string_distance( $string1, $string2 ) {
+ // Vectors containing character frequency for all chars in each string
+ $chars1 = count_chars($string1);
+ $chars2 = count_chars($string2);
+
+ // L1-norm of difference vector.
+ $difference = array_sum( array_map( array(&$this, 'difference'), $chars1, $chars2 ) );
+
+ // $string1 has zero length? Odd. Give huge penalty by not dividing.
+ if ( !$string1 )
+ return $difference;
+
+ // Return distance per charcter (of string1)
+ return $difference / strlen($string1);
+ }
+
+ /**
+ * @ignore
+ * @since 2.6.0
+ *
+ * @param int $a
+ * @param int $b
+ * @return int
+ */
+ function difference( $a, $b ) {
+ return abs( $a - $b );
+ }
+
+}
+
+/**
+ * Better word splitting than the PEAR package provides.
+ *
+ * @since 2.6.0
+ * @uses Text_Diff_Renderer_inline Extends
+ */
+class WP_Text_Diff_Renderer_inline extends Text_Diff_Renderer_inline {
+
+ /**
+ * @ignore
+ * @since 2.6.0
+ *
+ * @param string $string
+ * @param string $newlineEscape
+ * @return string
+ */
+ function _splitOnWords($string, $newlineEscape = "\n") {
+ $string = str_replace("\0", '', $string);
+ $words = preg_split( '/([^\w])/u', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
+ $words = str_replace( "\n", $newlineEscape, $words );
+ return $words;
+ }
+
+}
+
+?>
diff -uNr a/blog/wp-links-opml.php b/blog/wp-links-opml.php
--- a/blog/wp-links-opml.php false
+++ b/blog/wp-links-opml.php 81d1c71bcac651606202bdddeb8d099dbe6fc164b4a46397020cf3f250b678d4c489ea182ffd848b0895b5a3941e883bf3ef250fa72af88bb496cf190baa0d90
@@ -0,0 +1,65 @@
+\n"; ?>
+
+
+
+ Links for <?php echo attribute_escape(get_bloginfo('name', 'display').$cat_name); ?>
+ GMT
+
+
+name);
+
+?>
+
+term_id}");
+ foreach ((array) $bookmarks as $bookmark) {
+ $title = attribute_escape(apply_filters('link_title', $bookmark->link_name));
+?>
+
+
+
+
+
+
diff -uNr a/blog/wp-load.php b/blog/wp-load.php
--- a/blog/wp-load.php false
+++ b/blog/wp-load.php 340ebe1057da577969e59f32254915a5f5f04276bcd9bd91b250b64da939f360256ed5b7ebe0e17a0db0ffce937e0a42d13e4362720c998cdfce7463d97b120c
@@ -0,0 +1,50 @@
+wp-config.php file. I need this before we can get started. Need more help? We got it . You can create a wp-config.php
file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file.
Create a Configuration File "/*/WP_I18N_NO_CONFIG*/, $path), /*WP_I18N_ERROR_TITLE*/"WordPress › Error"/*/WP_I18N_ERROR_TITLE*/);
+
+}
+
+?>
diff -uNr a/blog/wp-login.php b/blog/wp-login.php
--- a/blog/wp-login.php false
+++ b/blog/wp-login.php ba6a8927b35a5f974f334ff0bf8113a38885fd3614605de0b5a127436ffe857967acfd92cfc65294d142689675538795fc9a423ce9f1aec28e2d21f8e2a8738d
@@ -0,0 +1,517 @@
+ element.
+ * @param string $message Optional. Message to display in header.
+ * @param WP_Error $wp_error Optional. WordPress Error Object
+ */
+function login_header($title = 'Log In', $message = '', $wp_error = '') {
+ global $error;
+
+ if ( empty($wp_error) )
+ $wp_error = new WP_Error();
+ ?>
+
+>
+
+
<?php bloginfo('name'); ?> › <?php echo $title; ?>
+
+
+
+
+
+
+add('error', $error);
+ unset($error);
+ }
+
+ if ( $wp_error->get_error_code() ) {
+ $errors = '';
+ $messages = '';
+ foreach ( $wp_error->get_error_codes() as $code ) {
+ $severity = $wp_error->get_error_data($code);
+ foreach ( $wp_error->get_error_messages($code) as $error ) {
+ if ( 'message' == $severity )
+ $messages .= ' ' . $error . "
\n";
+ else
+ $errors .= ' ' . $error . "
\n";
+ }
+ }
+ if ( !empty($errors) )
+ echo '
' . apply_filters('login_errors', $errors) . "
\n";
+ if ( !empty($messages) )
+ echo '
' . apply_filters('login_messages', $messages) . "
\n";
+ }
+} // End of login_header()
+
+/**
+ * Handles sending password retrieval email to user.
+ *
+ * @uses $wpdb WordPress Database object
+ *
+ * @return bool|WP_Error True: when finish. WP_Error on error
+ */
+function retrieve_password() {
+ global $wpdb;
+
+ $errors = new WP_Error();
+
+ if ( empty( $_POST['user_login'] ) && empty( $_POST['user_email'] ) )
+ $errors->add('empty_username', __('
ERROR : Enter a username or e-mail address.'));
+
+ if ( strpos($_POST['user_login'], '@') ) {
+ $user_data = get_user_by_email(trim($_POST['user_login']));
+ if ( empty($user_data) )
+ $errors->add('invalid_email', __('
ERROR : There is no user registered with that email address.'));
+ } else {
+ $login = trim($_POST['user_login']);
+ $user_data = get_userdatabylogin($login);
+ }
+
+ do_action('lostpassword_post');
+
+ if ( $errors->get_error_code() )
+ return $errors;
+
+ if ( !$user_data ) {
+ $errors->add('invalidcombo', __('
ERROR : Invalid username or e-mail.'));
+ return $errors;
+ }
+
+ // redefining user_login ensures we return the right case in the email
+ $user_login = $user_data->user_login;
+ $user_email = $user_data->user_email;
+
+ do_action('retreive_password', $user_login); // Misspelled and deprecated
+ do_action('retrieve_password', $user_login);
+
+ $allow = apply_filters('allow_password_reset', true, $user_data->ID);
+
+ if ( ! $allow )
+ return new WP_Error('no_password_reset', __('Password reset is not allowed for this user'));
+ else if ( is_wp_error($allow) )
+ return $allow;
+
+ $key = $wpdb->get_var($wpdb->prepare("SELECT user_activation_key FROM $wpdb->users WHERE user_login = %s", $user_login));
+ if ( empty($key) ) {
+ // Generate something random for a key...
+ $key = wp_generate_password(20, false);
+ do_action('retrieve_password_key', $user_login, $key);
+ // Now insert the new md5 key into the db
+ $wpdb->query($wpdb->prepare("UPDATE $wpdb->users SET user_activation_key = %s WHERE user_login = %s", $key, $user_login));
+ }
+ $message = __('Someone has asked to reset the password for the following site and username.') . "\r\n\r\n";
+ $message .= get_option('siteurl') . "\r\n\r\n";
+ $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
+ $message .= __('To reset your password visit the following address, otherwise just ignore this email and nothing will happen.') . "\r\n\r\n";
+ $message .= site_url("wp-login.php?action=rp&key=$key", 'login') . "\r\n";
+
+ if ( !wp_mail($user_email, sprintf(__('[%s] Password Reset'), get_option('blogname')), $message) )
+ die('
' . __('The e-mail could not be sent.') . " \n" . __('Possible reason: your host may have disabled the mail() function...') . '
');
+
+ return true;
+}
+
+/**
+ * Handles resetting the user's password.
+ *
+ * @uses $wpdb WordPress Database object
+ *
+ * @param string $key Hash to validate sending user's password
+ * @return bool|WP_Error
+ */
+function reset_password($key) {
+ global $wpdb;
+
+ $key = preg_replace('/[^a-z0-9]/i', '', $key);
+
+ if ( empty( $key ) )
+ return new WP_Error('invalid_key', __('Invalid key'));
+
+ $user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s", $key));
+ if ( empty( $user ) )
+ return new WP_Error('invalid_key', __('Invalid key'));
+
+ do_action('password_reset', $user);
+
+ // Generate something random for a password...
+ $new_pass = wp_generate_password();
+ wp_set_password($new_pass, $user->ID);
+ $message = sprintf(__('Username: %s'), $user->user_login) . "\r\n";
+ $message .= sprintf(__('Password: %s'), $new_pass) . "\r\n";
+ $message .= site_url('wp-login.php', 'login') . "\r\n";
+
+ if ( !wp_mail($user->user_email, sprintf(__('[%s] Your new password'), get_option('blogname')), $message) )
+ die('
' . __('The e-mail could not be sent.') . " \n" . __('Possible reason: your host may have disabled the mail() function...') . '
');
+
+ wp_password_change_notification($user);
+
+ return true;
+}
+
+/**
+ * Handles registering a new user.
+ *
+ * @param string $user_login User's username for logging in
+ * @param string $user_email User's email address to send password and add
+ * @return int|WP_Error Either user's ID or error on failure.
+ */
+function register_new_user($user_login, $user_email) {
+ $errors = new WP_Error();
+
+ $user_login = sanitize_user( $user_login );
+ $user_email = apply_filters( 'user_registration_email', $user_email );
+
+ // Check the username
+ if ( $user_login == '' )
+ $errors->add('empty_username', __('
ERROR : Please enter a username.'));
+ elseif ( !validate_username( $user_login ) ) {
+ $errors->add('invalid_username', __('
ERROR : This username is invalid. Please enter a valid username.'));
+ $user_login = '';
+ } elseif ( username_exists( $user_login ) )
+ $errors->add('username_exists', __('
ERROR : This username is already registered, please choose another one.'));
+
+ // Check the e-mail address
+ if ($user_email == '') {
+ $errors->add('empty_email', __('
ERROR : Please type your e-mail address.'));
+ } elseif ( !is_email( $user_email ) ) {
+ $errors->add('invalid_email', __('
ERROR : The email address isn’t correct.'));
+ $user_email = '';
+ } elseif ( email_exists( $user_email ) )
+ $errors->add('email_exists', __('
ERROR : This email is already registered, please choose another one.'));
+
+ do_action('register_post', $user_login, $user_email, $errors);
+
+ $errors = apply_filters( 'registration_errors', $errors );
+
+ if ( $errors->get_error_code() )
+ return $errors;
+
+ $user_pass = wp_generate_password();
+ $user_id = wp_create_user( $user_login, $user_pass, $user_email );
+ if ( !$user_id ) {
+ $errors->add('registerfail', sprintf(__('
ERROR : Couldn’t register you... please contact the
webmaster !'), get_option('admin_email')));
+ return $errors;
+ }
+
+ wp_new_user_notification($user_id, $user_pass);
+
+ return $user_id;
+}
+
+//
+// Main
+//
+
+$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
+$errors = new WP_Error();
+
+if ( isset($_GET['key']) )
+ $action = 'resetpass';
+
+nocache_headers();
+
+header('Content-Type: '.get_bloginfo('html_type').'; charset='.get_bloginfo('charset'));
+
+if ( defined('RELOCATE') ) { // Move flag is set
+ if ( isset( $_SERVER['PATH_INFO'] ) && ($_SERVER['PATH_INFO'] != $_SERVER['PHP_SELF']) )
+ $_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] );
+
+ $schema = ( isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ) ? 'https://' : 'http://';
+ if ( dirname($schema . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']) != get_option('siteurl') )
+ update_option('siteurl', dirname($schema . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']) );
+}
+
+//Set a cookie now to see if they are supported by the browser.
+setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN);
+if ( SITECOOKIEPATH != COOKIEPATH )
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN);
+
+$http_post = ('POST' == $_SERVER['REQUEST_METHOD']);
+switch ($action) {
+
+case 'logout' :
+ check_admin_referer('log-out');
+ wp_logout();
+
+ $redirect_to = 'wp-login.php?loggedout=true';
+ if ( isset( $_REQUEST['redirect_to'] ) )
+ $redirect_to = $_REQUEST['redirect_to'];
+
+ wp_safe_redirect($redirect_to);
+ exit();
+
+break;
+
+case 'lostpassword' :
+case 'retrievepassword' :
+ if ( $http_post ) {
+ $errors = retrieve_password();
+ if ( !is_wp_error($errors) ) {
+ wp_redirect('wp-login.php?checkemail=confirm');
+ exit();
+ }
+ }
+
+ if ( isset($_GET['error']) && 'invalidkey' == $_GET['error'] ) $errors->add('invalidkey', __('Sorry, that key does not appear to be valid.'));
+
+ do_action('lost_password');
+ login_header(__('Lost Password'), '
' . __('Please enter your username or e-mail address. You will receive a new password via e-mail.') . '
', $errors);
+
+ $user_login = isset($_POST['user_login']) ? stripslashes($_POST['user_login']) : '';
+
+?>
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+' . __('Register For This Site') . '
', $errors);
+?>
+
+
+
+
+ |
+
+
+
+
' . get_comment_author_link() . '', $comment_post_link." ".$comment_link, ' ' . __( '[Pending]' ) . '' ); ?>
+ + comment_type ) : + case 'pingback' : + $type = __( 'Pingback' ); + break; + case 'trackback' : + $type = __( 'Trackback' ); + break; + default : + $type = ucwords( $comment->comment_type ); + endswitch; + $type = wp_specialchars( $type ); + ?> + +$type", $comment_post_link ); ?>
+ + + + + + +