modified file enshrined

This commit is contained in:
KawaiiPunk 2024-07-19 19:46:16 +00:00 committed by Gitium
parent 39ec06fbc1
commit 51937c2f57
856 changed files with 3722 additions and 180872 deletions

View File

@ -1,42 +0,0 @@
.DS_Store
.editorconfig
.git
.gitignore
.github
.travis.yml
.codeclimate.yml
.data
.svnignore
.wordpress-org
.php_cs
Gruntfile.js
LINGUAS
Makefile
README.md
readme.md
CHANGELOG.md
CODE_OF_CONDUCT.md
FEDERATION.md
SECURITY.md
LICENSE.md
_site
_config.yml
bin
composer.json
composer.lock
docker-compose.yml
docker-compose-test.yml
Dockerfile
gulpfile.js
package.json
node_modules
npm-debug.log
phpcs.xml
package.json
package-lock.json
phpunit.xml
phpunit.xml.dist
tests
node_modules
vendor
src

View File

@ -3,7 +3,7 @@
* Plugin Name: ActivityPub
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
* Version: 2.3.1
* Version: 2.4.0
* Author: Matthias Pfefferle & Automattic
* Author URI: https://automattic.com/
* License: MIT
@ -21,7 +21,7 @@ use function Activitypub\site_supports_blocks;
require_once __DIR__ . '/includes/compat.php';
require_once __DIR__ . '/includes/functions.php';
\define( 'ACTIVITYPUB_PLUGIN_VERSION', '2.3.1' );
\define( 'ACTIVITYPUB_PLUGIN_VERSION', '2.4.0' );
/**
* Initialize the plugin constants.
@ -50,7 +50,7 @@ require_once __DIR__ . '/includes/functions.php';
* Initialize REST routes.
*/
function rest_init() {
Rest\Users::init();
Rest\Actors::init();
Rest\Outbox::init();
Rest\Inbox::init();
Rest\Followers::init();
@ -100,6 +100,11 @@ function plugin_init() {
require_once __DIR__ . '/integration/class-enable-mastodon-apps.php';
Integration\Enable_Mastodon_Apps::init();
if ( \defined( 'JETPACK__VERSION' ) && ! \defined( 'IS_WPCOM' ) ) {
require_once __DIR__ . '/integration/class-jetpack.php';
Integration\Jetpack::init();
}
}
\add_action( 'plugins_loaded', __NAMESPACE__ . '\plugin_init' );

View File

@ -197,3 +197,8 @@ input.blog-user-identifier {
border-bottom: none;
margin-bottom: 0;
}
#dashboard_right_now li a.activitypub-followers::before {
content: "\f307";
font-family: dashicons;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-url'), 'version' => '536d43b3eaab93a5c9ef');
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-url'), 'version' => 'a351235e5feab398a954');

View File

@ -1,3 +1,3 @@
(()=>{var e={942:(e,t)=>{var a;!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e="",t=0;t<arguments.length;t++){var a=arguments[t];a&&(e=o(e,l(a)))}return e}function l(e){if("string"==typeof e||"number"==typeof e)return e;if("object"!=typeof e)return"";if(Array.isArray(e))return r.apply(null,e);if(e.toString!==Object.prototype.toString&&!e.toString.toString().includes("[native code]"))return e.toString();var t="";for(var a in e)n.call(e,a)&&e[a]&&(t=o(t,a));return t}function o(e,t){return t?e?e+" "+t:e+t:e}e.exports?(r.default=r,e.exports=r):void 0===(a=function(){return r}.apply(t,[]))||(e.exports=a)}()}},t={};function a(n){var r=t[n];if(void 0!==r)return r.exports;var l=t[n]={exports:{}};return e[n](l,l.exports,a),l.exports}a.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return a.d(t,{a:t}),t},a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{"use strict";const e=window.wp.blocks,t=window.React,n=window.wp.primitives,r=(0,t.createElement)(n.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},(0,t.createElement)(n.Path,{d:"M15.5 9.5a1 1 0 100-2 1 1 0 000 2zm0 1.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5zm-2.25 6v-2a2.75 2.75 0 00-2.75-2.75h-4A2.75 2.75 0 003.75 15v2h1.5v-2c0-.69.56-1.25 1.25-1.25h4c.69 0 1.25.56 1.25 1.25v2h1.5zm7-2v2h-1.5v-2c0-.69-.56-1.25-1.25-1.25H15v-1.5h2.5A2.75 2.75 0 0120.25 15zM9.5 8.5a1 1 0 11-2 0 1 1 0 012 0zm1.5 0a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z",fillRule:"evenodd"})),l=window.wp.components,o=window.wp.element,i=window.wp.blockEditor,c=window.wp.i18n,s=window.wp.apiFetch;var p=a.n(s);const u=window.wp.url;var v=a(942),m=a.n(v);function w({active:e,children:a,page:n,pageClick:r,className:l}){const o=m()("wp-block activitypub-pager",l,{current:e});return(0,t.createElement)("a",{className:o,onClick:t=>{t.preventDefault(),!e&&r(n)}},a)}const b={outlined:"outlined",minimal:"minimal"};function d({compact:e,nextLabel:a,page:n,pageClick:r,perPage:l,prevLabel:o,total:i,variant:c=b.outlined}){const s=((e,t)=>{let a=[1,e-2,e-1,e,e+1,e+2,t];a.sort(((e,t)=>e-t)),a=a.filter(((e,a,n)=>e>=1&&e<=t&&n.lastIndexOf(e)===a));for(let e=a.length-2;e>=0;e--)a[e]===a[e+1]&&a.splice(e+1,1);return a})(n,Math.ceil(i/l)),p=m()("alignwide wp-block-query-pagination is-content-justification-space-between is-layout-flex wp-block-query-pagination-is-layout-flex",`is-${c}`,{"is-compact":e});return(0,t.createElement)("nav",{className:p},o&&(0,t.createElement)(w,{key:"prev",page:n-1,pageClick:r,active:1===n,"aria-label":o,className:"wp-block-query-pagination-previous block-editor-block-list__block"},o),!e&&(0,t.createElement)("div",{className:"block-editor-block-list__block wp-block wp-block-query-pagination-numbers"},s.map((e=>(0,t.createElement)(w,{key:e,page:e,pageClick:r,active:e===n,className:"page-numbers"},e)))),a&&(0,t.createElement)(w,{key:"next",page:n+1,pageClick:r,active:n===Math.ceil(i/l),"aria-label":a,className:"wp-block-query-pagination-next block-editor-block-list__block"},a))}const{namespace:f}=window._activityPubOptions;function g({selectedUser:e,per_page:a,order:n,title:r,page:l,setPage:i,className:s="",followLinks:v=!0,followerData:m=!1}){const w="site"===e?0:e,[b,g]=(0,t.useState)([]),[k,h]=(0,t.useState)(0),[E,_]=(0,t.useState)(0),[x,C]=function(){const[e,a]=(0,t.useState)(1);return[e,a]}(),S=l||x,N=i||C,P=(0,o.createInterpolateElement)(/* translators: arrow for previous followers link */ /* translators: arrow for previous followers link */
(0,c.__)("<span>←</span> Less","activitypub"),{span:(0,t.createElement)("span",{class:"wp-block-query-pagination-previous-arrow is-arrow-arrow","aria-hidden":"true"})}),L=(0,o.createInterpolateElement)(/* translators: arrow for next followers link */ /* translators: arrow for next followers link */
(0,c.__)("More <span>→</span>","activitypub"),{span:(0,t.createElement)("span",{class:"wp-block-query-pagination-next-arrow is-arrow-arrow","aria-hidden":"true"})}),O=(e,t)=>{g(e),_(t),h(Math.ceil(t/a))};return(0,t.useEffect)((()=>{if(m&&1===S)return O(m.followers,m.total);const e=function(e,t,a,n){const r=`/${f}/users/${e}/followers`,l={per_page:t,order:a,page:n,context:"full"};return(0,u.addQueryArgs)(r,l)}(w,a,n,S);p()({path:e}).then((e=>O(e.orderedItems,e.totalItems))).catch((()=>{}))}),[w,a,n,S,m]),(0,t.createElement)("div",{className:"activitypub-follower-block "+s},(0,t.createElement)("h3",null,r),(0,t.createElement)("ul",null,b&&b.map((e=>(0,t.createElement)("li",{key:e.url},(0,t.createElement)(y,{...e,followLinks:v}))))),k>1&&(0,t.createElement)(d,{page:S,perPage:a,total:E,pageClick:N,nextLabel:L,prevLabel:P,compact:"is-style-compact"===s}))}function y({name:e,icon:a,url:n,preferredUsername:r,followLinks:o=!0}){const i=`@${r}`,c={};return o||(c.onClick=e=>e.preventDefault()),(0,t.createElement)(l.ExternalLink,{className:"activitypub-link",href:n,title:i,...c},(0,t.createElement)("img",{width:"40",height:"40",src:a.url,class:"avatar activitypub-avatar",alt:e}),(0,t.createElement)("span",{class:"activitypub-actor"},(0,t.createElement)("strong",{className:"activitypub-name"},e),(0,t.createElement)("span",{class:"sep"},"/"),(0,t.createElement)("span",{class:"activitypub-handle"},i)))}const k=window.wp.data,h=window._activityPubOptions?.enabled;(0,e.registerBlockType)("activitypub/followers",{edit:function({attributes:e,setAttributes:a}){const{order:n,per_page:r,selectedUser:s,title:p}=e,u=(0,i.useBlockProps)(),[v,m]=(0,o.useState)(1),w=[{label:(0,c.__)("New to old","activitypub"),value:"desc"},{label:(0,c.__)("Old to new","activitypub"),value:"asc"}],b=function(){const e=h?.users?(0,k.useSelect)((e=>e("core").getUsers({who:"authors"}))):[];return(0,o.useMemo)((()=>{if(!e)return[];const t=h?.site?[{label:(0,c.__)("Whole Site","activitypub"),value:"site"}]:[];return e.reduce(((e,t)=>(e.push({label:t.name,value:`${t.id}`}),e)),t)}),[e])}(),d=e=>t=>{m(1),a({[e]:t})};return(0,o.useEffect)((()=>{b.length&&(b.find((({value:e})=>e===s))||a({selectedUser:b[0].value}))}),[s,b]),(0,t.createElement)("div",{...u},(0,t.createElement)(i.InspectorControls,{key:"setting"},(0,t.createElement)(l.PanelBody,{title:(0,c.__)("Followers Options","activitypub")},(0,t.createElement)(l.TextControl,{label:(0,c.__)("Title","activitypub"),help:(0,c.__)("Title to display above the list of followers. Blank for none.","activitypub"),value:p,onChange:e=>a({title:e})}),b.length>1&&(0,t.createElement)(l.SelectControl,{label:(0,c.__)("Select User","activitypub"),value:s,options:b,onChange:d("selectedUser")}),(0,t.createElement)(l.SelectControl,{label:(0,c.__)("Sort","activitypub"),value:n,options:w,onChange:d("order")}),(0,t.createElement)(l.RangeControl,{label:(0,c.__)("Number of Followers","activitypub"),value:r,onChange:d("per_page"),min:1,max:10}))),(0,t.createElement)(g,{...e,page:v,setPage:m,followLinks:!1}))},save:()=>null,icon:r})})()})();
(()=>{var e={184:(e,t)=>{var a;!function(){"use strict";var l={}.hasOwnProperty;function n(){for(var e=[],t=0;t<arguments.length;t++){var a=arguments[t];if(a){var r=typeof a;if("string"===r||"number"===r)e.push(a);else if(Array.isArray(a)){if(a.length){var o=n.apply(null,a);o&&e.push(o)}}else if("object"===r){if(a.toString!==Object.prototype.toString&&!a.toString.toString().includes("[native code]")){e.push(a.toString());continue}for(var i in a)l.call(a,i)&&a[i]&&e.push(i)}}}return e.join(" ")}e.exports?(n.default=n,e.exports=n):void 0===(a=function(){return n}.apply(t,[]))||(e.exports=a)}()}},t={};function a(l){var n=t[l];if(void 0!==n)return n.exports;var r=t[l]={exports:{}};return e[l](r,r.exports,a),r.exports}a.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return a.d(t,{a:t}),t},a.d=(e,t)=>{for(var l in t)a.o(t,l)&&!a.o(e,l)&&Object.defineProperty(e,l,{enumerable:!0,get:t[l]})},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{"use strict";const e=window.wp.blocks,t=window.wp.element,l=window.wp.primitives,n=(0,t.createElement)(l.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},(0,t.createElement)(l.Path,{d:"M15.5 9.5a1 1 0 100-2 1 1 0 000 2zm0 1.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5zm-2.25 6v-2a2.75 2.75 0 00-2.75-2.75h-4A2.75 2.75 0 003.75 15v2h1.5v-2c0-.69.56-1.25 1.25-1.25h4c.69 0 1.25.56 1.25 1.25v2h1.5zm7-2v2h-1.5v-2c0-.69-.56-1.25-1.25-1.25H15v-1.5h2.5A2.75 2.75 0 0120.25 15zM9.5 8.5a1 1 0 11-2 0 1 1 0 012 0zm1.5 0a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z",fillRule:"evenodd"})),r=window.wp.components,o=window.wp.blockEditor,i=window.wp.i18n,c=window.React,s=window.wp.apiFetch;var p=a.n(s);const u=window.wp.url;var v=a(184),m=a.n(v);function w({active:e,children:a,page:l,pageClick:n,className:r}){const o=m()("wp-block activitypub-pager",r,{current:e});return(0,t.createElement)("a",{className:o,onClick:t=>{t.preventDefault(),!e&&n(l)}},a)}const b={outlined:"outlined",minimal:"minimal"};function d({compact:e,nextLabel:a,page:l,pageClick:n,perPage:r,prevLabel:o,total:i,variant:c=b.outlined}){const s=((e,t)=>{let a=[1,e-2,e-1,e,e+1,e+2,t];a.sort(((e,t)=>e-t)),a=a.filter(((e,a,l)=>e>=1&&e<=t&&l.lastIndexOf(e)===a));for(let e=a.length-2;e>=0;e--)a[e]===a[e+1]&&a.splice(e+1,1);return a})(l,Math.ceil(i/r)),p=m()("alignwide wp-block-query-pagination is-content-justification-space-between is-layout-flex wp-block-query-pagination-is-layout-flex",`is-${c}`,{"is-compact":e});return(0,t.createElement)("nav",{className:p},o&&(0,t.createElement)(w,{key:"prev",page:l-1,pageClick:n,active:1===l,"aria-label":o,className:"wp-block-query-pagination-previous block-editor-block-list__block"},o),!e&&(0,t.createElement)("div",{className:"block-editor-block-list__block wp-block wp-block-query-pagination-numbers"},s.map((e=>(0,t.createElement)(w,{key:e,page:e,pageClick:n,active:e===l,className:"page-numbers"},e)))),a&&(0,t.createElement)(w,{key:"next",page:l+1,pageClick:n,active:l===Math.ceil(i/r),"aria-label":a,className:"wp-block-query-pagination-next block-editor-block-list__block"},a))}const{namespace:g}=window._activityPubOptions;function f({selectedUser:e,per_page:a,order:l,title:n,page:r,setPage:o,className:s="",followLinks:v=!0,followerData:m=!1}){const w="site"===e?0:e,[b,f]=(0,c.useState)([]),[h,k]=(0,c.useState)(0),[E,_]=(0,c.useState)(0),[x,C]=function(){const[e,t]=(0,c.useState)(1);return[e,t]}(),S=r||x,N=o||C,P=(0,t.createInterpolateElement)(/* translators: arrow for previous followers link */
(0,i.__)("<span>←</span> Less","activitypub"),{span:(0,t.createElement)("span",{class:"wp-block-query-pagination-previous-arrow is-arrow-arrow","aria-hidden":"true"})}),L=(0,t.createInterpolateElement)(/* translators: arrow for next followers link */
(0,i.__)("More <span>→</span>","activitypub"),{span:(0,t.createElement)("span",{class:"wp-block-query-pagination-next-arrow is-arrow-arrow","aria-hidden":"true"})}),O=(e,t)=>{f(e),_(t),k(Math.ceil(t/a))};return(0,c.useEffect)((()=>{if(m&&1===S)return O(m.followers,m.total);const e=function(e,t,a,l){const n=`/${g}/actors/${e}/followers`,r={per_page:t,order:a,page:l,context:"full"};return(0,u.addQueryArgs)(n,r)}(w,a,l,S);p()({path:e}).then((e=>O(e.orderedItems,e.totalItems))).catch((()=>{}))}),[w,a,l,S,m]),(0,t.createElement)("div",{className:"activitypub-follower-block "+s},(0,t.createElement)("h3",null,n),(0,t.createElement)("ul",null,b&&b.map((e=>(0,t.createElement)("li",{key:e.url},(0,t.createElement)(y,{...e,followLinks:v}))))),h>1&&(0,t.createElement)(d,{page:S,perPage:a,total:E,pageClick:N,nextLabel:L,prevLabel:P,compact:"is-style-compact"===s}))}function y({name:e,icon:a,url:l,preferredUsername:n,followLinks:o=!0}){const i=`@${n}`,c={};return o||(c.onClick=e=>e.preventDefault()),(0,t.createElement)(r.ExternalLink,{className:"activitypub-link",href:l,title:i,...c},(0,t.createElement)("img",{width:"40",height:"40",src:a.url,class:"avatar activitypub-avatar",alt:e}),(0,t.createElement)("span",{class:"activitypub-actor"},(0,t.createElement)("strong",{className:"activitypub-name"},e),(0,t.createElement)("span",{class:"sep"},"/"),(0,t.createElement)("span",{class:"activitypub-handle"},i)))}const h=window.wp.data,k=window._activityPubOptions?.enabled;(0,e.registerBlockType)("activitypub/followers",{edit:function({attributes:e,setAttributes:a}){const{order:l,per_page:n,selectedUser:c,title:s}=e,p=(0,o.useBlockProps)(),[u,v]=(0,t.useState)(1),m=[{label:(0,i.__)("New to old","activitypub"),value:"desc"},{label:(0,i.__)("Old to new","activitypub"),value:"asc"}],w=function(){const e=k?.users?(0,h.useSelect)((e=>e("core").getUsers({who:"authors"}))):[];return(0,t.useMemo)((()=>{if(!e)return[];const t=k?.site?[{label:(0,i.__)("Whole Site","activitypub"),value:"site"}]:[];return e.reduce(((e,t)=>(e.push({label:t.name,value:`${t.id}`}),e)),t)}),[e])}(),b=e=>t=>{v(1),a({[e]:t})};return(0,t.useEffect)((()=>{w.length&&(w.find((({value:e})=>e===c))||a({selectedUser:w[0].value}))}),[c,w]),(0,t.createElement)("div",{...p},(0,t.createElement)(o.InspectorControls,{key:"setting"},(0,t.createElement)(r.PanelBody,{title:(0,i.__)("Followers Options","activitypub")},(0,t.createElement)(r.TextControl,{label:(0,i.__)("Title","activitypub"),help:(0,i.__)("Title to display above the list of followers. Blank for none.","activitypub"),value:s,onChange:e=>a({title:e})}),w.length>1&&(0,t.createElement)(r.SelectControl,{label:(0,i.__)("Select User","activitypub"),value:c,options:w,onChange:b("selectedUser")}),(0,t.createElement)(r.SelectControl,{label:(0,i.__)("Sort","activitypub"),value:l,options:m,onChange:b("order")}),(0,t.createElement)(r.RangeControl,{label:(0,i.__)("Number of Followers","activitypub"),value:n,onChange:b("per_page"),min:1,max:10}))),(0,t.createElement)(f,{...e,page:u,setPage:v,followLinks:!1}))},save:()=>null,icon:n})})()})();

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '23bc54443801976420cd');
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '8c01e26171636c3b698f');

View File

@ -1,3 +1,3 @@
(()=>{var e,t={250:(e,t,a)=>{"use strict";const r=window.React,n=window.wp.apiFetch;var l=a.n(n);const o=window.wp.url,i=window.wp.element,c=window.wp.i18n;var s=a(942),p=a.n(s);function u({active:e,children:t,page:a,pageClick:n,className:l}){const o=p()("wp-block activitypub-pager",l,{current:e});return(0,r.createElement)("a",{className:o,onClick:t=>{t.preventDefault(),!e&&n(a)}},t)}const m={outlined:"outlined",minimal:"minimal"};function f({compact:e,nextLabel:t,page:a,pageClick:n,perPage:l,prevLabel:o,total:i,variant:c=m.outlined}){const s=((e,t)=>{let a=[1,e-2,e-1,e,e+1,e+2,t];a.sort(((e,t)=>e-t)),a=a.filter(((e,a,r)=>e>=1&&e<=t&&r.lastIndexOf(e)===a));for(let e=a.length-2;e>=0;e--)a[e]===a[e+1]&&a.splice(e+1,1);return a})(a,Math.ceil(i/l)),f=p()("alignwide wp-block-query-pagination is-content-justification-space-between is-layout-flex wp-block-query-pagination-is-layout-flex",`is-${c}`,{"is-compact":e});return(0,r.createElement)("nav",{className:f},o&&(0,r.createElement)(u,{key:"prev",page:a-1,pageClick:n,active:1===a,"aria-label":o,className:"wp-block-query-pagination-previous block-editor-block-list__block"},o),!e&&(0,r.createElement)("div",{className:"block-editor-block-list__block wp-block wp-block-query-pagination-numbers"},s.map((e=>(0,r.createElement)(u,{key:e,page:e,pageClick:n,active:e===a,className:"page-numbers"},e)))),t&&(0,r.createElement)(u,{key:"next",page:a+1,pageClick:n,active:a===Math.ceil(i/l),"aria-label":t,className:"wp-block-query-pagination-next block-editor-block-list__block"},t))}const v=window.wp.components,{namespace:b}=window._activityPubOptions;function d({selectedUser:e,per_page:t,order:a,title:n,page:s,setPage:p,className:u="",followLinks:m=!0,followerData:v=!1}){const d="site"===e?0:e,[g,y]=(0,r.useState)([]),[k,h]=(0,r.useState)(0),[E,x]=(0,r.useState)(0),[_,O]=function(){const[e,t]=(0,r.useState)(1);return[e,t]}(),N=s||_,S=p||O,C=(0,i.createInterpolateElement)(/* translators: arrow for previous followers link */ /* translators: arrow for previous followers link */
(0,c.__)("<span>←</span> Less","activitypub"),{span:(0,r.createElement)("span",{class:"wp-block-query-pagination-previous-arrow is-arrow-arrow","aria-hidden":"true"})}),L=(0,i.createInterpolateElement)(/* translators: arrow for next followers link */ /* translators: arrow for next followers link */
(0,c.__)("More <span>→</span>","activitypub"),{span:(0,r.createElement)("span",{class:"wp-block-query-pagination-next-arrow is-arrow-arrow","aria-hidden":"true"})}),q=(e,a)=>{y(e),x(a),h(Math.ceil(a/t))};return(0,r.useEffect)((()=>{if(v&&1===N)return q(v.followers,v.total);const e=function(e,t,a,r){const n=`/${b}/users/${e}/followers`,l={per_page:t,order:a,page:r,context:"full"};return(0,o.addQueryArgs)(n,l)}(d,t,a,N);l()({path:e}).then((e=>q(e.orderedItems,e.totalItems))).catch((()=>{}))}),[d,t,a,N,v]),(0,r.createElement)("div",{className:"activitypub-follower-block "+u},(0,r.createElement)("h3",null,n),(0,r.createElement)("ul",null,g&&g.map((e=>(0,r.createElement)("li",{key:e.url},(0,r.createElement)(w,{...e,followLinks:m}))))),k>1&&(0,r.createElement)(f,{page:N,perPage:t,total:E,pageClick:S,nextLabel:L,prevLabel:C,compact:"is-style-compact"===u}))}function w({name:e,icon:t,url:a,preferredUsername:n,followLinks:l=!0}){const o=`@${n}`,i={};return l||(i.onClick=e=>e.preventDefault()),(0,r.createElement)(v.ExternalLink,{className:"activitypub-link",href:a,title:o,...i},(0,r.createElement)("img",{width:"40",height:"40",src:t.url,class:"avatar activitypub-avatar",alt:e}),(0,r.createElement)("span",{class:"activitypub-actor"},(0,r.createElement)("strong",{className:"activitypub-name"},e),(0,r.createElement)("span",{class:"sep"},"/"),(0,r.createElement)("span",{class:"activitypub-handle"},o)))}const g=window.wp.domReady;a.n(g)()((()=>{[].forEach.call(document.querySelectorAll(".activitypub-follower-block"),(e=>{const t=JSON.parse(e.dataset.attrs);(0,i.render)((0,r.createElement)(d,{...t}),e)}))}))},942:(e,t)=>{var a;!function(){"use strict";var r={}.hasOwnProperty;function n(){for(var e="",t=0;t<arguments.length;t++){var a=arguments[t];a&&(e=o(e,l(a)))}return e}function l(e){if("string"==typeof e||"number"==typeof e)return e;if("object"!=typeof e)return"";if(Array.isArray(e))return n.apply(null,e);if(e.toString!==Object.prototype.toString&&!e.toString.toString().includes("[native code]"))return e.toString();var t="";for(var a in e)r.call(e,a)&&e[a]&&(t=o(t,a));return t}function o(e,t){return t?e?e+" "+t:e+t:e}e.exports?(n.default=n,e.exports=n):void 0===(a=function(){return n}.apply(t,[]))||(e.exports=a)}()}},a={};function r(e){var n=a[e];if(void 0!==n)return n.exports;var l=a[e]={exports:{}};return t[e](l,l.exports,r),l.exports}r.m=t,e=[],r.O=(t,a,n,l)=>{if(!a){var o=1/0;for(p=0;p<e.length;p++){for(var[a,n,l]=e[p],i=!0,c=0;c<a.length;c++)(!1&l||o>=l)&&Object.keys(r.O).every((e=>r.O[e](a[c])))?a.splice(c--,1):(i=!1,l<o&&(o=l));if(i){e.splice(p--,1);var s=n();void 0!==s&&(t=s)}}return t}l=l||0;for(var p=e.length;p>0&&e[p-1][2]>l;p--)e[p]=e[p-1];e[p]=[a,n,l]},r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var a in t)r.o(t,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={996:0,528:0};r.O.j=t=>0===e[t];var t=(t,a)=>{var n,l,[o,i,c]=a,s=0;if(o.some((t=>0!==e[t]))){for(n in i)r.o(i,n)&&(r.m[n]=i[n]);if(c)var p=c(r)}for(t&&t(a);s<o.length;s++)l=o[s],r.o(e,l)&&e[l]&&e[l][0](),e[l]=0;return r.O(p)},a=globalThis.webpackChunkwordpress_activitypub=globalThis.webpackChunkwordpress_activitypub||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})();var n=r.O(void 0,[528],(()=>r(250)));n=r.O(n)})();
(()=>{var e,t={142:(e,t,a)=>{"use strict";const r=window.wp.element,n=window.React,l=window.wp.apiFetch;var o=a.n(l);const i=window.wp.url,c=window.wp.i18n;var s=a(184),p=a.n(s);function u({active:e,children:t,page:a,pageClick:n,className:l}){const o=p()("wp-block activitypub-pager",l,{current:e});return(0,r.createElement)("a",{className:o,onClick:t=>{t.preventDefault(),!e&&n(a)}},t)}const m={outlined:"outlined",minimal:"minimal"};function f({compact:e,nextLabel:t,page:a,pageClick:n,perPage:l,prevLabel:o,total:i,variant:c=m.outlined}){const s=((e,t)=>{let a=[1,e-2,e-1,e,e+1,e+2,t];a.sort(((e,t)=>e-t)),a=a.filter(((e,a,r)=>e>=1&&e<=t&&r.lastIndexOf(e)===a));for(let e=a.length-2;e>=0;e--)a[e]===a[e+1]&&a.splice(e+1,1);return a})(a,Math.ceil(i/l)),f=p()("alignwide wp-block-query-pagination is-content-justification-space-between is-layout-flex wp-block-query-pagination-is-layout-flex",`is-${c}`,{"is-compact":e});return(0,r.createElement)("nav",{className:f},o&&(0,r.createElement)(u,{key:"prev",page:a-1,pageClick:n,active:1===a,"aria-label":o,className:"wp-block-query-pagination-previous block-editor-block-list__block"},o),!e&&(0,r.createElement)("div",{className:"block-editor-block-list__block wp-block wp-block-query-pagination-numbers"},s.map((e=>(0,r.createElement)(u,{key:e,page:e,pageClick:n,active:e===a,className:"page-numbers"},e)))),t&&(0,r.createElement)(u,{key:"next",page:a+1,pageClick:n,active:a===Math.ceil(i/l),"aria-label":t,className:"wp-block-query-pagination-next block-editor-block-list__block"},t))}const v=window.wp.components,{namespace:d}=window._activityPubOptions;function b({selectedUser:e,per_page:t,order:a,title:l,page:s,setPage:p,className:u="",followLinks:m=!0,followerData:v=!1}){const b="site"===e?0:e,[g,k]=(0,n.useState)([]),[y,h]=(0,n.useState)(0),[E,x]=(0,n.useState)(0),[_,O]=function(){const[e,t]=(0,n.useState)(1);return[e,t]}(),N=s||_,S=p||O,C=(0,r.createInterpolateElement)(/* translators: arrow for previous followers link */
(0,c.__)("<span>←</span> Less","activitypub"),{span:(0,r.createElement)("span",{class:"wp-block-query-pagination-previous-arrow is-arrow-arrow","aria-hidden":"true"})}),L=(0,r.createInterpolateElement)(/* translators: arrow for next followers link */
(0,c.__)("More <span>→</span>","activitypub"),{span:(0,r.createElement)("span",{class:"wp-block-query-pagination-next-arrow is-arrow-arrow","aria-hidden":"true"})}),j=(e,a)=>{k(e),x(a),h(Math.ceil(a/t))};return(0,n.useEffect)((()=>{if(v&&1===N)return j(v.followers,v.total);const e=function(e,t,a,r){const n=`/${d}/actors/${e}/followers`,l={per_page:t,order:a,page:r,context:"full"};return(0,i.addQueryArgs)(n,l)}(b,t,a,N);o()({path:e}).then((e=>j(e.orderedItems,e.totalItems))).catch((()=>{}))}),[b,t,a,N,v]),(0,r.createElement)("div",{className:"activitypub-follower-block "+u},(0,r.createElement)("h3",null,l),(0,r.createElement)("ul",null,g&&g.map((e=>(0,r.createElement)("li",{key:e.url},(0,r.createElement)(w,{...e,followLinks:m}))))),y>1&&(0,r.createElement)(f,{page:N,perPage:t,total:E,pageClick:S,nextLabel:L,prevLabel:C,compact:"is-style-compact"===u}))}function w({name:e,icon:t,url:a,preferredUsername:n,followLinks:l=!0}){const o=`@${n}`,i={};return l||(i.onClick=e=>e.preventDefault()),(0,r.createElement)(v.ExternalLink,{className:"activitypub-link",href:a,title:o,...i},(0,r.createElement)("img",{width:"40",height:"40",src:t.url,class:"avatar activitypub-avatar",alt:e}),(0,r.createElement)("span",{class:"activitypub-actor"},(0,r.createElement)("strong",{className:"activitypub-name"},e),(0,r.createElement)("span",{class:"sep"},"/"),(0,r.createElement)("span",{class:"activitypub-handle"},o)))}const g=window.wp.domReady;a.n(g)()((()=>{[].forEach.call(document.querySelectorAll(".activitypub-follower-block"),(e=>{const t=JSON.parse(e.dataset.attrs);(0,r.render)((0,r.createElement)(b,{...t}),e)}))}))},184:(e,t)=>{var a;!function(){"use strict";var r={}.hasOwnProperty;function n(){for(var e=[],t=0;t<arguments.length;t++){var a=arguments[t];if(a){var l=typeof a;if("string"===l||"number"===l)e.push(a);else if(Array.isArray(a)){if(a.length){var o=n.apply(null,a);o&&e.push(o)}}else if("object"===l){if(a.toString!==Object.prototype.toString&&!a.toString.toString().includes("[native code]")){e.push(a.toString());continue}for(var i in a)r.call(a,i)&&a[i]&&e.push(i)}}}return e.join(" ")}e.exports?(n.default=n,e.exports=n):void 0===(a=function(){return n}.apply(t,[]))||(e.exports=a)}()}},a={};function r(e){var n=a[e];if(void 0!==n)return n.exports;var l=a[e]={exports:{}};return t[e](l,l.exports,r),l.exports}r.m=t,e=[],r.O=(t,a,n,l)=>{if(!a){var o=1/0;for(p=0;p<e.length;p++){a=e[p][0],n=e[p][1],l=e[p][2];for(var i=!0,c=0;c<a.length;c++)(!1&l||o>=l)&&Object.keys(r.O).every((e=>r.O[e](a[c])))?a.splice(c--,1):(i=!1,l<o&&(o=l));if(i){e.splice(p--,1);var s=n();void 0!==s&&(t=s)}}return t}l=l||0;for(var p=e.length;p>0&&e[p-1][2]>l;p--)e[p]=e[p-1];e[p]=[a,n,l]},r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var a in t)r.o(t,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={638:0,962:0};r.O.j=t=>0===e[t];var t=(t,a)=>{var n,l,o=a[0],i=a[1],c=a[2],s=0;if(o.some((t=>0!==e[t]))){for(n in i)r.o(i,n)&&(r.m[n]=i[n]);if(c)var p=c(r)}for(t&&t(a);s<o.length;s++)l=o[s],r.o(e,l)&&e[l]&&e[l][0](),e[l]=0;return r.O(p)},a=self.webpackChunkwordpress_activitypub=self.webpackChunkwordpress_activitypub||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})();var n=r.O(void 0,[962],(()=>r(142)));n=r.O(n)})();

File diff suppressed because one or more lines are too long

View File

@ -162,7 +162,13 @@ class Activity extends Base_Object {
}
if ( $object->get_id() && ! $this->get_id() ) {
$this->set( 'id', $object->get_id() . '#activity' );
$id = strtok( $object->get_id(), '#' );
if ( $object->get_updated() ) {
$updated = $object->get_updated();
} else {
$updated = $object->get_published();
}
$this->set( 'id', $id . '#activity-' . strtolower( $this->get_type() ) . '-' . $updated );
}
}

View File

@ -64,7 +64,11 @@ class Activity_Dispatcher {
* @return void
*/
public static function send_activity( $wp_object, $type, $user_id = null ) {
$transformer = Factory::get_transformer( $wp_object );
$transformer = Factory::get_transformer( $wp_object ); // Could potentially return a `\WP_Error` instance.
if ( \is_wp_error( $transformer ) ) {
return;
}
if ( null !== $user_id ) {
$transformer->change_wp_user_id( $user_id );
@ -98,18 +102,22 @@ class Activity_Dispatcher {
return;
}
// do not announce replies
if ( $wp_object instanceof WP_Comment ) {
$transformer = Factory::get_transformer( $wp_object );
if ( \is_wp_error( $transformer ) ) {
return;
}
$transformer = Factory::get_transformer( $wp_object );
$transformer->change_wp_user_id( Users::BLOG_USER_ID );
$user_id = Users::BLOG_USER_ID;
$activity = $transformer->to_activity( $type );
$user = Users::get_by_id( Users::BLOG_USER_ID );
$user_id = $transformer->get_wp_user_id();
$activity = $transformer->to_activity( 'Announce' );
$announce = new Activity();
$announce->set_type( 'Announce' );
$announce->set_object( $activity );
$announce->set_actor( $user->get_id() );
self::send_activity_to_followers( $activity, $user_id, $wp_object );
self::send_activity_to_followers( $announce, $user_id, $wp_object );
}
/**

View File

@ -9,6 +9,7 @@ use Activitypub\Collection\Followers;
use function Activitypub\is_comment;
use function Activitypub\sanitize_url;
use function Activitypub\is_local_comment;
use function Activitypub\is_user_type_disabled;
use function Activitypub\is_activitypub_request;
use function Activitypub\should_comment_be_federated;
@ -95,37 +96,39 @@ class Activitypub {
$json_template = false;
// check if user can publish posts
if ( \is_author() && is_wp_error( Users::get_by_id( \get_the_author_meta( 'ID' ) ) ) ) {
return $template;
}
// check if blog-user is enabled
if ( \is_home() && is_wp_error( Users::get_by_id( Users::BLOG_USER_ID ) ) ) {
return $template;
}
if ( \is_author() ) {
if ( \is_author() && ! is_user_disabled( \get_the_author_meta( 'ID' ) ) ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/author-json.php';
} elseif ( is_comment() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/comment-json.php';
} elseif ( \is_singular() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/post-json.php';
} elseif ( \is_home() ) {
} elseif ( \is_home() && ! is_user_type_disabled( 'blog' ) ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/blog-json.php';
}
if ( ACTIVITYPUB_AUTHORIZED_FETCH ) {
/*
* Check if the request is authorized.
*
* @see https://www.w3.org/wiki/SocialCG/ActivityPub/Primer/Authentication_Authorization#Authorized_fetch
* @see https://swicg.github.io/activitypub-http-signature/#authorized-fetch
*/
if ( $json_template && ACTIVITYPUB_AUTHORIZED_FETCH ) {
$verification = Signature::verify_http_signature( $_SERVER );
if ( \is_wp_error( $verification ) ) {
header( 'HTTP/1.1 401 Unauthorized' );
// fallback as template_loader can't return http headers
return $template;
}
}
if ( $json_template ) {
return $json_template;
}
return $template;
}
/**
* Custom redirects for ActivityPub requests.
*
@ -292,7 +295,7 @@ class Activitypub {
\add_rewrite_rule(
'^@([\w\-\.]+)',
'index.php?rest_route=/' . ACTIVITYPUB_REST_NAMESPACE . '/users/$matches[1]',
'index.php?rest_route=/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/$matches[1]',
'top'
);

View File

@ -2,8 +2,10 @@
namespace Activitypub;
use WP_User_Query;
use Activitypub\Model\Blog_User;
use Activitypub\Model\Blog;
use Activitypub\Collection\Users;
use function Activitypub\count_followers;
use function Activitypub\is_user_disabled;
use function Activitypub\was_comment_received;
use function Activitypub\is_comment_federatable;
@ -37,6 +39,8 @@ class Admin {
if ( ! is_user_disabled( get_current_user_id() ) ) {
\add_action( 'show_user_profile', array( self::class, 'add_profile' ) );
}
\add_filter( 'dashboard_glance_items', array( self::class, 'dashboard_glance_items' ) );
}
/**
@ -216,7 +220,7 @@ class Admin {
'type' => 'string',
'description' => \esc_html__( 'The Identifier of the Blog-User', 'activitypub' ),
'show_in_rest' => true,
'default' => Blog_User::get_default_username(),
'default' => Blog::get_default_username(),
'sanitize_callback' => function ( $value ) {
// hack to allow dots in the username
$parts = explode( '.', $value );
@ -247,7 +251,7 @@ class Admin {
'error'
);
return Blog_User::get_default_username();
return Blog::get_default_username();
}
return $sanitized;
@ -313,8 +317,12 @@ class Admin {
public static function enqueue_scripts( $hook_suffix ) {
if ( false !== strpos( $hook_suffix, 'activitypub' ) ) {
wp_enqueue_style( 'activitypub-admin-styles', plugins_url( 'assets/css/activitypub-admin.css', ACTIVITYPUB_PLUGIN_FILE ), array(), '1.0.0' );
wp_enqueue_script( 'activitypub-admin-styles', plugins_url( 'assets/js/activitypub-admin.js', ACTIVITYPUB_PLUGIN_FILE ), array( 'jquery' ), '1.0.0', false );
wp_enqueue_style( 'activitypub-admin-styles', plugins_url( 'assets/css/activitypub-admin.css', ACTIVITYPUB_PLUGIN_FILE ), array(), get_plugin_version() );
wp_enqueue_script( 'activitypub-admin-script', plugins_url( 'assets/js/activitypub-admin.js', ACTIVITYPUB_PLUGIN_FILE ), array( 'jquery' ), get_plugin_version(), false );
}
if ( 'index.php' === $hook_suffix ) {
wp_enqueue_style( 'activitypub-admin-styles', plugins_url( 'assets/css/activitypub-admin.css', ACTIVITYPUB_PLUGIN_FILE ), array(), get_plugin_version() );
}
}
@ -469,4 +477,57 @@ class Admin {
return $sendback;
}
/**
* Add ActivityPub infos to the dashboard glance items
*
* @param array $items The existing glance items.
*
* @return array The extended glance items.
*/
public static function dashboard_glance_items( $items ) {
\add_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 3 );
if ( ! is_user_disabled( get_current_user_id() ) ) {
$follower_count = sprintf(
// translators: %s: number of followers
_n(
'%s Follower',
'%s Followers',
count_followers( \get_current_user_id() ),
'activitypub'
),
\number_format_i18n( count_followers( \get_current_user_id() ) )
);
$items['activitypub-followers-user'] = sprintf(
'<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
\esc_url( \admin_url( 'users.php?page=activitypub-followers-list' ) ),
\esc_attr__( 'Your followers', 'activitypub' ),
\esc_html( $follower_count )
);
}
if ( ! is_user_type_disabled( 'blog' ) && current_user_can( 'manage_options' ) ) {
$follower_count = sprintf(
// translators: %s: number of followers
_n(
'%s Follower (Blog)',
'%s Followers (Blog)',
count_followers( Users::BLOG_USER_ID ),
'activitypub'
),
\number_format_i18n( count_followers( Users::BLOG_USER_ID ) )
);
$items['activitypub-followers-blog'] = sprintf(
'<a class="activitypub-followers" href="%1$s" title="%2$s">%3$s</a>',
\esc_url( \admin_url( 'options-general.php?page=activitypub&tab=followers' ) ),
\esc_attr__( 'The Blog\'s followers', 'activitypub' ),
\esc_html( $follower_count )
);
}
\remove_filter( 'number_format_i18n', '\Activitypub\custom_large_numbers', 10, 3 );
return $items;
}
}

View File

@ -379,7 +379,7 @@ class Comment {
}
// generate URI based on comment ID
return \add_query_arg( 'c', $comment->comment_ID, \home_url() );
return \add_query_arg( 'c', $comment->comment_ID, \trailingslashit( \home_url() ) );
}
/**

View File

@ -1,6 +1,7 @@
<?php
namespace Activitypub;
use Activitypub\Handler\Announce;
use Activitypub\Handler\Create;
use Activitypub\Handler\Delete;
use Activitypub\Handler\Follow;
@ -22,6 +23,7 @@ class Handler {
* Register handlers.
*/
public static function register_handlers() {
Announce::init();
Create::init();
Delete::init();
Follow::init();

View File

@ -154,4 +154,98 @@ class Http {
public static function generate_cache_key( $url ) {
return 'activitypub_http_' . \md5( $url );
}
/**
* Requests the Data from the Object-URL or Object-Array
*
* @param array|string $url_or_object The Object or the Object URL.
* @param bool $cached If the result should be cached.
*
* @return array|WP_Error The Object data as array or WP_Error on failure.
*/
public static function get_remote_object( $url_or_object, $cached = true ) {
if ( is_array( $url_or_object ) ) {
if ( array_key_exists( 'id', $url_or_object ) ) {
$url = $url_or_object['id'];
} elseif ( array_key_exists( 'url', $url_or_object ) ) {
$url = $url_or_object['url'];
} else {
return new WP_Error(
'activitypub_no_valid_actor_identifier',
\__( 'The "actor" identifier is not valid', 'activitypub' ),
array(
'status' => 404,
'object' => $url_or_object,
)
);
}
} else {
$url = $url_or_object;
}
if ( preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $url ) ) {
$url = Webfinger::resolve( $url );
}
if ( ! $url ) {
return new WP_Error(
'activitypub_no_valid_actor_identifier',
\__( 'The "actor" identifier is not valid', 'activitypub' ),
array(
'status' => 404,
'object' => $url,
)
);
}
if ( is_wp_error( $url ) ) {
return $url;
}
$transient_key = self::generate_cache_key( $url );
// only check the cache if needed.
if ( $cached ) {
$data = \get_transient( $transient_key );
if ( $data ) {
return $data;
}
}
if ( ! \wp_http_validate_url( $url ) ) {
return new WP_Error(
'activitypub_no_valid_object_url',
\__( 'The "object" is/has no valid URL', 'activitypub' ),
array(
'status' => 400,
'object' => $url,
)
);
}
$response = self::get( $url );
if ( \is_wp_error( $response ) ) {
return $response;
}
$data = \wp_remote_retrieve_body( $response );
$data = \json_decode( $data, true );
if ( ! $data ) {
return new WP_Error(
'activitypub_invalid_json',
\__( 'No valid JSON data', 'activitypub' ),
array(
'status' => 400,
'object' => $url,
)
);
}
\set_transient( $transient_key, $data, WEEK_IN_SECONDS );
return $data;
}
}

View File

@ -4,6 +4,8 @@ namespace Activitypub;
use WP_Error;
use Activitypub\Webfinger;
use function Activitypub\object_to_uri;
/**
* ActivityPub Mention Class
*
@ -93,7 +95,11 @@ class Mention {
public static function replace_with_links( $result ) {
$metadata = get_remote_metadata_by_actor( $result[0] );
if ( ! empty( $metadata ) && ! is_wp_error( $metadata ) && ! empty( $metadata['url'] ) ) {
if (
! empty( $metadata ) &&
! is_wp_error( $metadata ) &&
( ! empty( $metadata['id'] ) || ! empty( $metadata['url'] ) )
) {
$username = ltrim( $result[0], '@' );
if ( ! empty( $metadata['name'] ) ) {
$username = $metadata['name'];
@ -102,11 +108,7 @@ class Mention {
$username = $metadata['preferredUsername'];
}
$url = isset( $metadata['url'] ) ? $metadata['url'] : $metadata['id'];
if ( \is_array( $url ) ) {
$url = $url[0];
}
$url = isset( $metadata['url'] ) ? object_to_uri( $metadata['url'] ) : object_to_uri( $metadata['id'] );
return \sprintf( '<a rel="mention" class="u-url mention" href="%s">@<span>%s</span></a>', esc_url( $url ), esc_html( $username ) );
}

View File

@ -2,7 +2,7 @@
namespace Activitypub;
use Activitypub\Activitypub;
use Activitypub\Model\Blog_User;
use Activitypub\Model\Blog;
use Activitypub\Collection\Followers;
/**

View File

@ -0,0 +1,58 @@
<?php
namespace Activitypub;
/**
* Notification class.
*/
class Notification {
/**
* The type of the notification.
*
* @var string
*/
public $type;
/**
* The actor URL.
*
* @var string
*/
public $actor;
/**
* The Activity object.
*
* @var array
*/
public $object;
/**
* The WordPress User-Id.
*
* @var int
*/
public $target;
/**
* Notification constructor.
*
* @param string $type The type of the notification.
* @param string $actor The actor URL.
* @param array $object The Activity object.
* @param int $target The WordPress User-Id.
*/
public function __construct( $type, $actor, $object, $target ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound
$this->type = $type;
$this->actor = $actor;
$this->object = $object;
$this->target = $target;
}
/**
* Send the notification.
*/
public function send() {
do_action( 'activitypub_notification', $this );
}
}

View File

@ -4,8 +4,8 @@ namespace Activitypub\Collection;
use WP_Error;
use WP_User_Query;
use Activitypub\Model\User;
use Activitypub\Model\Blog_User;
use Activitypub\Model\Application_User;
use Activitypub\Model\Blog;
use Activitypub\Model\Application;
use function Activitypub\object_to_uri;
use function Activitypub\url_to_authorid;
@ -47,9 +47,9 @@ class Users {
}
if ( self::BLOG_USER_ID === $user_id ) {
return Blog_User::from_wp_user( $user_id );
return new Blog();
} elseif ( self::APPLICATION_USER_ID === $user_id ) {
return Application_User::from_wp_user( $user_id );
return new Application();
} elseif ( $user_id > 0 ) {
return User::from_wp_user( $user_id );
}
@ -70,12 +70,12 @@ class Users {
*/
public static function get_by_username( $username ) {
// check for blog user.
if ( Blog_User::get_default_username() === $username ) {
return self::get_by_id( self::BLOG_USER_ID );
if ( Blog::get_default_username() === $username ) {
return new Blog();
}
if ( get_option( 'activitypub_blog_user_identifier' ) === $username ) {
return self::get_by_id( self::BLOG_USER_ID );
return new Blog();
}
// check for application user.
@ -144,25 +144,32 @@ class Users {
// try to extract the scheme and the host
if ( preg_match( '/^([a-zA-Z^:]+):(.*)$/i', $resource, $match ) ) {
// extract the scheme
$scheme = esc_attr( $match[1] );
$scheme = \esc_attr( $match[1] );
}
switch ( $scheme ) {
// check for http(s) URIs
case 'http':
case 'https':
$url_parts = wp_parse_url( $resource );
$resource_path = \wp_parse_url( $resource, PHP_URL_PATH );
if ( $resource_path ) {
$blog_path = \wp_parse_url( \home_url(), PHP_URL_PATH );
if ( $blog_path ) {
$resource_path = \str_replace( $blog_path, '', $resource_path );
}
$resource_path = \trim( $resource_path, '/' );
// check for http(s)://blog.example.com/@username
if (
isset( $url_parts['path'] ) &&
str_starts_with( $url_parts['path'], '/@' )
) {
$identifier = str_replace( '/@', '', $url_parts['path'] );
$identifier = untrailingslashit( $identifier );
if ( str_starts_with( $resource_path, '@' ) ) {
$identifier = \str_replace( '@', '', $resource_path );
$identifier = \trim( $identifier, '/' );
return self::get_by_username( $identifier );
}
}
// check for http(s)://blog.example.com/author/username
$user_id = url_to_authorid( $resource );
@ -222,18 +229,26 @@ class Users {
* @return \Acitvitypub\Model\User The User.
*/
public static function get_by_various( $id ) {
$user = null;
if ( is_numeric( $id ) ) {
return self::get_by_id( $id );
$user = self::get_by_id( $id );
} elseif (
// is URL
filter_var( $id, FILTER_VALIDATE_URL ) ||
// is acct
str_starts_with( $id, 'acct:' )
str_starts_with( $id, 'acct:' ) ||
// is email
filter_var( $id, FILTER_VALIDATE_EMAIL )
) {
return self::get_by_resource( $id );
} else {
return self::get_by_username( $id );
$user = self::get_by_resource( $id );
}
if ( $user && ! is_wp_error( $user ) ) {
return $user;
}
return self::get_by_username( $id );
}
/**

View File

@ -854,3 +854,118 @@ function get_masked_wp_version() {
return implode( '.', $version );
}
/**
* Get the enclosures of a post.
*
* @param int $post_id The post ID.
*
* @return array The enclosures.
*/
function get_enclosures( $post_id ) {
$enclosures = get_post_meta( $post_id, 'enclosure' );
if ( ! $enclosures ) {
return array();
}
$enclosures = array_map(
function ( $enclosure ) {
$attributes = explode( "\n", $enclosure );
if ( ! isset( $attributes[0] ) || ! \wp_http_validate_url( $attributes[0] ) ) {
return false;
}
return array(
'url' => $attributes[0],
'length' => isset( $attributes[1] ) ? trim( $attributes[1] ) : null,
'mediaType' => isset( $attributes[2] ) ? trim( $attributes[2] ) : null,
);
},
$enclosures
);
return array_filter( $enclosures );
}
/**
* Retrieves the IDs of the ancestors of a comment.
*
* Adaption of `get_post_ancestors` from WordPress core.
*
* @see https://developer.wordpress.org/reference/functions/get_post_ancestors/
*
* @param int|WP_Comment $comment Comment ID or comment object.
*
* @return WP_Comment[] Array of ancestor comments or empty array if there are none.
*/
function get_comment_ancestors( $comment ) {
$comment = \get_comment( $comment );
// phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
if ( ! $comment || empty( $comment->comment_parent ) || $comment->comment_parent == $comment->comment_ID ) {
return array();
}
$ancestors = array();
$id = (int) $comment->comment_parent;
$ancestors[] = $id;
// phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
while ( $id > 0 ) {
$ancestor = \get_comment( $id );
$parent_id = (int) $ancestor->comment_parent;
// Loop detection: If the ancestor has been seen before, break.
if ( empty( $parent_id ) || ( $parent_id === (int) $comment->comment_ID ) || in_array( $parent_id, $ancestors, true ) ) {
break;
}
$id = $parent_id;
$ancestors[] = $id;
}
return $ancestors;
}
/**
* Change the display of large numbers on the site.
*
* @author Jeremy Herve
*
* @see https://wordpress.org/support/topic/abbreviate-numbers-with-k/
*
* @param string $formatted Converted number in string format.
* @param float $number The number to convert based on locale.
* @param int $decimals Precision of the number of decimal places.
*
* @return string Converted number in string format.
*/
function custom_large_numbers( $formatted, $number, $decimals ) {
global $wp_locale;
$decimals = 0;
$decimal_point = '.';
$thousands_sep = ',';
if ( isset( $wp_locale ) ) {
$decimals = (int) $wp_locale->number_format['decimal_point'];
$decimal_point = $wp_locale->number_format['decimal_point'];
$thousands_sep = $wp_locale->number_format['thousands_sep'];
}
if ( $number < 1000 ) { // any number less than a Thousand.
return \number_format( $number, $decimals, $decimal_point, $thousands_sep );
} elseif ( $number < 1000000 ) { // any number less than a million
return \number_format( $number / 1000, $decimals, $decimal_point, $thousands_sep ) . 'K';
} elseif ( $number < 1000000000 ) { // any number less than a billion
return \number_format( $number / 1000000, $decimals, $decimal_point, $thousands_sep ) . 'M';
} else { // at least a billion
return \number_format( $number / 1000000000, $decimals, $decimal_point, $thousands_sep ) . 'B';
}
// Default fallback. We should not get here.
return $formatted;
}

View File

@ -0,0 +1,69 @@
<?php
namespace Activitypub\Handler;
use Activitypub\Http;
use function Activitypub\is_activity_public;
/**
* Handle Create requests
*/
class Announce {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_action(
'activitypub_inbox_announce',
array( self::class, 'handle_announce' ),
10,
3
);
}
/**
* Handles "Announce" requests
*
* @param array $array The activity-object
* @param int $user_id The id of the local blog-user
* @param Activitypub\Activity $activity The activity object
*
* @return void
*/
public static function handle_announce( $array, $user_id, $activity = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
if ( ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS ) {
return;
}
if ( ! isset( $array['object'] ) ) {
return;
}
// check if Activity is public or not
if ( ! is_activity_public( $array ) ) {
// @todo maybe send email
return;
}
// @todo save the `Announce`-Activity itself
if ( is_string( $array['object'] ) ) {
$object = Http::get_remote_object( $array['object'] );
} else {
$object = $array['object'];
}
if ( ! $object || is_wp_error( $object ) ) {
return;
}
if ( ! isset( $object['type'] ) ) {
return;
}
$type = \strtolower( $object['type'] );
\do_action( 'activitypub_inbox', $object, $user_id, $type, $activity );
\do_action( "activitypub_inbox_{$type}", $object, $user_id, $activity );
}
}

View File

@ -2,6 +2,7 @@
namespace Activitypub\Handler;
use Activitypub\Http;
use Activitypub\Notification;
use Activitypub\Activity\Activity;
use Activitypub\Collection\Users;
use Activitypub\Collection\Followers;
@ -57,6 +58,15 @@ class Follow {
$user_id,
$follower
);
// send notification
$notification = new Notification(
'follow',
$activity['actor'],
$activity,
$user_id
);
$notification->send();
}
/**

View File

@ -1,79 +0,0 @@
<?php
namespace Activitypub\Model;
use WP_Query;
use Activitypub\Signature;
use Activitypub\Collection\Users;
use function Activitypub\get_rest_url_by_path;
class Application_User extends Blog_User {
/**
* The User-ID
*
* @var int
*/
protected $_id = Users::APPLICATION_USER_ID; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
public function get_type() {
return 'Application';
}
public function get_discoverable() {
return false;
}
public function get_manually_approves_followers() {
return true;
}
/**
* Get the User-Url.
*
* @return string The User-Url.
*/
public function get_url() {
return get_rest_url_by_path( 'application' );
}
/**
* Returns the User-URL with @-Prefix for the username.
*
* @return string The User-URL with @-Prefix for the username.
*/
public function get_alternate_url() {
return \esc_url( \trailingslashit( get_home_url() ) . '@' . $this->get_preferred_username() );
}
public function get_name() {
return 'application';
}
public function get_preferred_username() {
return $this->get_name();
}
public function get_followers() {
return null;
}
public function get_following() {
return null;
}
public function get_attachment() {
return null;
}
public function get_featured() {
return null;
}
public function get_moderators() {
return null;
}
public function get_indexable() {
return false;
}
}

View File

@ -0,0 +1,200 @@
<?php
namespace Activitypub\Model;
use WP_Query;
use Activitypub\Signature;
use Activitypub\Activity\Actor;
use Activitypub\Collection\Users;
use function Activitypub\get_rest_url_by_path;
class Application extends Actor {
/**
* The User-ID
*
* @var int
*/
protected $_id = Users::APPLICATION_USER_ID; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* If the User is discoverable.
*
* @see https://docs.joinmastodon.org/spec/activitypub/#discoverable
*
* @context http://joinmastodon.org/ns#discoverable
*
* @var boolean
*/
protected $discoverable = false;
/**
* If the User is indexable.
*
* @context http://joinmastodon.org/ns#indexable
*
* @var boolean
*/
protected $indexable = false;
/**
* The WebFinger Resource.
*
* @var string<url>
*/
protected $webfinger;
public function get_type() {
return 'Application';
}
public function get_manually_approves_followers() {
return true;
}
public function get_id() {
return get_rest_url_by_path( 'application' );
}
/**
* Get the User-Url.
*
* @return string The User-Url.
*/
public function get_url() {
return $this->get_id();
}
/**
* Returns the User-URL with @-Prefix for the username.
*
* @return string The User-URL with @-Prefix for the username.
*/
public function get_alternate_url() {
return $this->get_url();
}
public function get_name() {
return 'application';
}
public function get_preferred_username() {
return $this->get_name();
}
/**
* Get the User-Icon.
*
* @return array The User-Icon.
*/
public function get_icon() {
// try site icon first
$icon_id = get_option( 'site_icon' );
// try custom logo second
if ( ! $icon_id ) {
$icon_id = get_theme_mod( 'custom_logo' );
}
$icon_url = false;
if ( $icon_id ) {
$icon = wp_get_attachment_image_src( $icon_id, 'full' );
if ( $icon ) {
$icon_url = $icon[0];
}
}
if ( ! $icon_url ) {
// fallback to default icon
$icon_url = plugins_url( '/assets/img/wp-logo.png', ACTIVITYPUB_PLUGIN_FILE );
}
return array(
'type' => 'Image',
'url' => esc_url( $icon_url ),
);
}
/**
* Get the User-Header-Image.
*
* @return array|null The User-Header-Image.
*/
public function get_header_image() {
if ( \has_header_image() ) {
return array(
'type' => 'Image',
'url' => esc_url( \get_header_image() ),
);
}
return null;
}
public function get_published() {
$first_post = new WP_Query(
array(
'orderby' => 'date',
'order' => 'ASC',
'number' => 1,
)
);
if ( ! empty( $first_post->posts[0] ) ) {
$time = \strtotime( $first_post->posts[0]->post_date_gmt );
} else {
$time = \time();
}
return \gmdate( 'Y-m-d\TH:i:s\Z', $time );
}
/**
* Returns the Inbox-API-Endpoint.
*
* @return string The Inbox-Endpoint.
*/
public function get_inbox() {
return get_rest_url_by_path( sprintf( 'actors/%d/inbox', $this->get__id() ) );
}
/**
* Returns the Outbox-API-Endpoint.
*
* @return string The Outbox-Endpoint.
*/
public function get_outbox() {
return get_rest_url_by_path( sprintf( 'actors/%d/outbox', $this->get__id() ) );
}
/**
* Returns a user@domain type of identifier for the user.
*
* @return string The Webfinger-Identifier.
*/
public function get_webfinger() {
return $this->get_preferred_username() . '@' . \wp_parse_url( \home_url(), \PHP_URL_HOST );
}
public function get_public_key() {
return array(
'id' => $this->get_id() . '#main-key',
'owner' => $this->get_id(),
'publicKeyPem' => Signature::get_public_key_for( Users::APPLICATION_USER_ID ),
);
}
/**
* Get the User-Description.
*
* @return string The User-Description.
*/
public function get_summary() {
return \wpautop(
\wp_kses(
\get_bloginfo( 'description' ),
'default'
)
);
}
}

View File

@ -4,13 +4,38 @@ namespace Activitypub\Model;
use WP_Query;
use WP_Error;
use Activitypub\Signature;
use Activitypub\Activity\Actor;
use Activitypub\Collection\Users;
use function Activitypub\is_single_user;
use function Activitypub\is_user_disabled;
use function Activitypub\get_rest_url_by_path;
class Blog_User extends User {
class Blog extends Actor {
/**
* The Featured-Posts.
*
* @see https://docs.joinmastodon.org/spec/activitypub/#featured
*
* @context {
* "@id": "http://joinmastodon.org/ns#featured",
* "@type": "@id"
* }
*
* @var string
*/
protected $featured;
/**
* Moderators endpoint.
*
* @see https://join-lemmy.org/docs/contributors/05-federation.html
*
* @var string
*/
protected $moderators;
/**
* The User-ID
*
@ -18,6 +43,42 @@ class Blog_User extends User {
*/
protected $_id = Users::BLOG_USER_ID; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* If the User is indexable.
*
* @context http://joinmastodon.org/ns#indexable
*
* @var boolean
*/
protected $indexable;
/**
* The WebFinger Resource.
*
* @var string<url>
*/
protected $webfinger;
/**
* If the User is discoverable.
*
* @see https://docs.joinmastodon.org/spec/activitypub/#discoverable
*
* @context http://joinmastodon.org/ns#discoverable
*
* @var boolean
*/
protected $discoverable;
/**
* Restrict posting to mods
*
* @see https://join-lemmy.org/docs/contributors/05-federation.html
*
* @var boolean
*/
protected $posting_restricted_to_mods;
public function get_manually_approves_followers() {
return false;
}
@ -26,19 +87,13 @@ class Blog_User extends User {
return true;
}
public static function from_wp_user( $user_id ) {
if ( is_user_disabled( $user_id ) ) {
return new WP_Error(
'activitypub_user_not_found',
\__( 'User not found', 'activitypub' ),
array( 'status' => 404 )
);
}
$object = new static();
$object->_id = $user_id;
return $object;
/**
* Get the User-ID.
*
* @return string The User-ID.
*/
public function get_id() {
return $this->get_url();
}
/**
@ -204,10 +259,6 @@ class Blog_User extends User {
return \gmdate( 'Y-m-d\TH:i:s\Z', $time );
}
public function get_attachment() {
return array();
}
public function get_canonical_url() {
return \home_url();
}
@ -228,6 +279,14 @@ class Blog_User extends User {
return get_rest_url_by_path( 'collections/moderators' );
}
public function get_public_key() {
return array(
'id' => $this->get_id() . '#main-key',
'owner' => $this->get_id(),
'publicKeyPem' => Signature::get_public_key_for( $this->get__id() ),
);
}
public function get_posting_restricted_to_mods() {
if ( 'Group' === $this->get_type() ) {
return true;
@ -235,4 +294,78 @@ class Blog_User extends User {
return null;
}
/**
* Returns the Inbox-API-Endpoint.
*
* @return string The Inbox-Endpoint.
*/
public function get_inbox() {
return get_rest_url_by_path( sprintf( 'actors/%d/inbox', $this->get__id() ) );
}
/**
* Returns the Outbox-API-Endpoint.
*
* @return string The Outbox-Endpoint.
*/
public function get_outbox() {
return get_rest_url_by_path( sprintf( 'actors/%d/outbox', $this->get__id() ) );
}
/**
* Returns the Followers-API-Endpoint.
*
* @return string The Followers-Endpoint.
*/
public function get_followers() {
return get_rest_url_by_path( sprintf( 'actors/%d/followers', $this->get__id() ) );
}
/**
* Returns the Following-API-Endpoint.
*
* @return string The Following-Endpoint.
*/
public function get_following() {
return get_rest_url_by_path( sprintf( 'actors/%d/following', $this->get__id() ) );
}
public function get_endpoints() {
$endpoints = null;
if ( ACTIVITYPUB_SHARED_INBOX_FEATURE ) {
$endpoints = array(
'sharedInbox' => get_rest_url_by_path( 'inbox' ),
);
}
return $endpoints;
}
/**
* Returns a user@domain type of identifier for the user.
*
* @return string The Webfinger-Identifier.
*/
public function get_webfinger() {
return $this->get_preferred_username() . '@' . \wp_parse_url( \home_url(), \PHP_URL_HOST );
}
/**
* Returns the Featured-API-Endpoint.
*
* @return string The Featured-Endpoint.
*/
public function get_featured() {
return get_rest_url_by_path( sprintf( 'actors/%d/collections/featured', $this->get__id() ) );
}
public function get_indexable() {
if ( \get_option( 'blog_public', 1 ) ) {
return true;
} else {
return false;
}
}
}

View File

@ -2,7 +2,7 @@
namespace Activitypub\Model;
use Activitypub\Collection\Users;
use Activitypub\Transformer\Post as Post_Transformer;
use Activitypub\Transformer\Factory;
/**
* ActivityPub Post Class
@ -32,10 +32,14 @@ class Post {
*/
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
public function __construct( $post, $post_author = null ) {
_deprecated_function( __CLASS__, '1.0.0', '\Activitypub\Transformer\Post' );
_deprecated_function( __METHOD__, '1.0.0', '\Activitypub\Transformer\Factory::get_transformer' );
$transformer = Factory::get_transformer( $post );
if ( ! \is_wp_error( $transformer ) ) {
$this->post = $post;
$this->object = Post_Transformer::transform( $post )->to_object();
$this->object = $transformer->to_object();
}
}
/**

View File

@ -4,8 +4,9 @@ namespace Activitypub\Model;
use WP_Query;
use WP_Error;
use Activitypub\Signature;
use Activitypub\Collection\Users;
use Activitypub\Model\Blog;
use Activitypub\Activity\Actor;
use Activitypub\Collection\Users;
use function Activitypub\is_user_disabled;
use function Activitypub\get_rest_url_by_path;
@ -32,19 +33,6 @@ class User extends Actor {
*/
protected $featured;
/**
* Moderators endpoint.
*
* @see https://join-lemmy.org/docs/contributors/05-federation.html
*
* @var string
*/
protected $moderators;
public function get_type() {
return 'Person';
}
/**
* If the User is discoverable.
*
@ -72,14 +60,9 @@ class User extends Actor {
*/
protected $webfinger;
/**
* Restrict posting to mods
*
* @see https://join-lemmy.org/docs/contributors/05-federation.html
*
* @var boolean
*/
protected $posting_restricted_to_mods = null;
public function get_type() {
return 'Person';
}
public static function from_wp_user( $user_id ) {
if ( is_user_disabled( $user_id ) ) {
@ -193,7 +176,7 @@ class User extends Actor {
* @return string The Inbox-Endpoint.
*/
public function get_inbox() {
return get_rest_url_by_path( sprintf( 'users/%d/inbox', $this->get__id() ) );
return get_rest_url_by_path( sprintf( 'actors/%d/inbox', $this->get__id() ) );
}
/**
@ -202,7 +185,7 @@ class User extends Actor {
* @return string The Outbox-Endpoint.
*/
public function get_outbox() {
return get_rest_url_by_path( sprintf( 'users/%d/outbox', $this->get__id() ) );
return get_rest_url_by_path( sprintf( 'actors/%d/outbox', $this->get__id() ) );
}
/**
@ -211,7 +194,7 @@ class User extends Actor {
* @return string The Followers-Endpoint.
*/
public function get_followers() {
return get_rest_url_by_path( sprintf( 'users/%d/followers', $this->get__id() ) );
return get_rest_url_by_path( sprintf( 'actors/%d/followers', $this->get__id() ) );
}
/**
@ -220,7 +203,7 @@ class User extends Actor {
* @return string The Following-Endpoint.
*/
public function get_following() {
return get_rest_url_by_path( sprintf( 'users/%d/following', $this->get__id() ) );
return get_rest_url_by_path( sprintf( 'actors/%d/following', $this->get__id() ) );
}
/**
@ -229,7 +212,7 @@ class User extends Actor {
* @return string The Featured-Endpoint.
*/
public function get_featured() {
return get_rest_url_by_path( sprintf( 'users/%d/collections/featured', $this->get__id() ) );
return get_rest_url_by_path( sprintf( 'actors/%d/collections/featured', $this->get__id() ) );
}
public function get_endpoints() {
@ -296,10 +279,6 @@ class User extends Actor {
return $this->get_preferred_username() . '@' . \wp_parse_url( \home_url(), \PHP_URL_HOST );
}
public function get_resource() {
return $this->get_webfinger();
}
public function get_canonical_url() {
return $this->get_url();
}

View File

@ -12,13 +12,13 @@ use Activitypub\Collection\Users as User_Collection;
use function Activitypub\is_activitypub_request;
/**
* ActivityPub Followers REST-Class
* ActivityPub Actors REST-Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/#followers
*/
class Users {
class Actors {
/**
* Initialize the class, registering WordPress hooks
*/
@ -32,7 +32,7 @@ class Users {
public static function register_routes() {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)',
'/(users|actors)/(?P<user_id>[\w\-\.]+)',
array(
array(
'methods' => WP_REST_Server::READABLE,
@ -45,7 +45,7 @@ class Users {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)/remote-follow',
'/(users|actors)/(?P<user_id>[\w\-\.]+)/remote-follow',
array(
array(
'methods' => WP_REST_Server::READABLE,

View File

@ -1,13 +1,12 @@
<?php
namespace Activitypub\Rest;
use WP_Error;
use WP_REST_Server;
use WP_REST_Response;
use Activitypub\Transformer\Post;
use Activitypub\Activity\Actor;
use Activitypub\Activity\Base_Object;
use Activitypub\Collection\Users as User_Collection;
use Activitypub\Transformer\Factory;
use function Activitypub\esc_hashtag;
use function Activitypub\is_single_user;
@ -35,7 +34,7 @@ class Collection {
public static function register_routes() {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)/collections/tags',
'/(users|actors)/(?P<user_id>[\w\-\.]+)/collections/tags',
array(
array(
'methods' => WP_REST_Server::READABLE,
@ -48,7 +47,7 @@ class Collection {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)/collections/featured',
'/(users|actors)/(?P<user_id>[\w\-\.]+)/collections/featured',
array(
array(
'methods' => WP_REST_Server::READABLE,
@ -104,7 +103,7 @@ class Collection {
$response = array(
'@context' => Base_Object::JSON_LD_CONTEXT,
'id' => get_rest_url_by_path( sprintf( 'users/%d/collections/tags', $user->get__id() ) ),
'id' => get_rest_url_by_path( sprintf( 'actors/%d/collections/tags', $user->get__id() ) ),
'type' => 'Collection',
'totalItems' => is_countable( $tags ) ? count( $tags ) : 0,
'items' => array(),
@ -162,14 +161,20 @@ class Collection {
$response = array(
'@context' => Base_Object::JSON_LD_CONTEXT,
'id' => get_rest_url_by_path( sprintf( 'users/%d/collections/featured', $user_id ) ),
'id' => get_rest_url_by_path( sprintf( 'actors/%d/collections/featured', $user_id ) ),
'type' => 'OrderedCollection',
'totalItems' => is_countable( $posts ) ? count( $posts ) : 0,
'orderedItems' => array(),
);
foreach ( $posts as $post ) {
$response['orderedItems'][] = Post::transform( $post )->to_object()->to_array( false );
$transformer = Factory::get_transformer( $post );
if ( \is_wp_error( $transformer ) ) {
continue;
}
$response['orderedItems'][] = $transformer->to_object()->to_array( false );
}
$rest_response = new WP_REST_Response( $response, 200 );

View File

@ -29,7 +29,7 @@ class Comment {
public static function register_routes() {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/comments/(?P<comment_id>\d+)/remote-reply',
'/(users|actors)/(?P<comment_id>\d+)/remote-reply',
array(
array(
'methods' => WP_REST_Server::READABLE,

View File

@ -32,7 +32,7 @@ class Followers {
public static function register_routes() {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)/followers',
'/(users|actors)/(?P<user_id>[\w\-\.]+)/followers',
array(
array(
'methods' => WP_REST_Server::READABLE,
@ -74,13 +74,13 @@ class Followers {
$json->{'@context'} = \Activitypub\get_context();
$json->id = get_rest_url_by_path( sprintf( 'users/%d/followers', $user->get__id() ) );
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/followers', $user->get__id() ) );
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
$json->actor = $user->get_id();
$json->type = 'OrderedCollectionPage';
$json->totalItems = $data['total']; // phpcs:ignore
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/followers', $user->get__id() ) ); // phpcs:ignore
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/followers', $user->get__id() ) ); // phpcs:ignore
$json->first = \add_query_arg( 'page', 1, $json->partOf ); // phpcs:ignore
$json->last = \add_query_arg( 'page', \ceil ( $json->totalItems / $per_page ), $json->partOf ); // phpcs:ignore

View File

@ -31,7 +31,7 @@ class Following {
public static function register_routes() {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)/following',
'/(users|actors)/(?P<user_id>[\w\-\.]+)/following',
array(
array(
'methods' => \WP_REST_Server::READABLE,
@ -67,12 +67,12 @@ class Following {
$json->{'@context'} = \Activitypub\get_context();
$json->id = get_rest_url_by_path( sprintf( 'users/%d/following', $user->get__id() ) );
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/following', $user->get__id() ) );
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
$json->actor = $user->get_id();
$json->type = 'OrderedCollectionPage';
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/following', $user->get__id() ) ); // phpcs:ignore
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/following', $user->get__id() ) ); // phpcs:ignore
$items = apply_filters( 'activitypub_rest_following', array(), $user ); // phpcs:ignore

View File

@ -48,7 +48,7 @@ class Inbox {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)/inbox',
'/(users|actors)/(?P<user_id>[\w\-\.]+)/inbox',
array(
array(
'methods' => WP_REST_Server::CREATABLE,
@ -90,10 +90,10 @@ class Inbox {
$json = new \stdClass();
$json->{'@context'} = get_context();
$json->id = get_rest_url_by_path( sprintf( 'users/%d/inbox', $user->get__id() ) );
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/inbox', $user->get__id() ) );
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
$json->type = 'OrderedCollectionPage';
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/inbox', $user->get__id() ) ); // phpcs:ignore
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/inbox', $user->get__id() ) ); // phpcs:ignore
$json->totalItems = 0; // phpcs:ignore
$json->orderedItems = array(); // phpcs:ignore
$json->first = $json->partOf; // phpcs:ignore

View File

@ -5,9 +5,9 @@ use stdClass;
use WP_Error;
use WP_REST_Server;
use WP_REST_Response;
use Activitypub\Transformer\Post;
use Activitypub\Activity\Activity;
use Activitypub\Collection\Users as User_Collection;
use Activitypub\Transformer\Factory;
use function Activitypub\get_context;
use function Activitypub\get_rest_url_by_path;
@ -34,7 +34,7 @@ class Outbox {
public static function register_routes() {
\register_rest_route(
ACTIVITYPUB_REST_NAMESPACE,
'/users/(?P<user_id>[\w\-\.]+)/outbox',
'/(users|actors)/(?P<user_id>[\w\-\.]+)/outbox',
array(
array(
'methods' => WP_REST_Server::READABLE,
@ -72,11 +72,11 @@ class Outbox {
$json = new stdClass();
$json->{'@context'} = get_context();
$json->id = get_rest_url_by_path( sprintf( 'users/%d/outbox', $user_id ) );
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) );
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
$json->actor = $user->get_id();
$json->type = 'OrderedCollectionPage';
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/outbox', $user_id ) ); // phpcs:ignore
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) ); // phpcs:ignore
$json->totalItems = 0; // phpcs:ignore
if ( $user_id > 0 ) {
@ -111,7 +111,13 @@ class Outbox {
);
foreach ( $posts as $post ) {
$post = Post::transform( $post )->to_object();
$transformer = Factory::get_transformer( $post );
if ( \is_wp_error( $transformer ) ) {
continue;
}
$post = $transformer->to_object();
$activity = new Activity();
$activity->set_type( 'Create' );
$activity->set_object( $post );

View File

@ -5,7 +5,7 @@ use stdClass;
use WP_Error;
use WP_REST_Response;
use Activitypub\Signature;
use Activitypub\Model\Application_User;
use Activitypub\Model\Application;
/**
* ActivityPub Server REST-Class
@ -47,7 +47,7 @@ class Server {
* @return WP_REST_Response The JSON profile of the Application Actor.
*/
public static function application_actor() {
$user = new Application_User();
$user = new Application();
$json = $user->to_array();
@ -62,6 +62,9 @@ class Server {
*
* @see WP_REST_Request
*
* @see https://www.w3.org/wiki/SocialCG/ActivityPub/Primer/Authentication_Authorization#Authorized_fetch
* @see https://swicg.github.io/activitypub-http-signature/#authorized-fetch
*
* @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client.
* Usually a WP_REST_Response or WP_Error.
* @param array $handler Route handler used for the request.
@ -80,7 +83,8 @@ class Server {
if (
! \str_starts_with( $route, '/' . ACTIVITYPUB_REST_NAMESPACE ) ||
\str_starts_with( $route, '/' . \trailingslashit( ACTIVITYPUB_REST_NAMESPACE ) . 'webfinger' ) ||
\str_starts_with( $route, '/' . \trailingslashit( ACTIVITYPUB_REST_NAMESPACE ) . 'nodeinfo' )
\str_starts_with( $route, '/' . \trailingslashit( ACTIVITYPUB_REST_NAMESPACE ) . 'nodeinfo' ) ||
\str_starts_with( $route, '/' . \trailingslashit( ACTIVITYPUB_REST_NAMESPACE ) . 'application' )
) {
return $response;
}
@ -102,17 +106,12 @@ class Server {
return $response;
}
// POST-Requets are always signed
if ( 'GET' !== $request->get_method() ) {
$verified_request = Signature::verify_http_signature( $request );
if ( \is_wp_error( $verified_request ) ) {
return new WP_Error(
'activitypub_signature_verification',
$verified_request->get_error_message(),
array( 'status' => 401 )
);
}
} elseif ( 'GET' === $request->get_method() && ACTIVITYPUB_AUTHORIZED_FETCH ) { // GET-Requests are only signed in secure mode
if (
// POST-Requests are always signed
'GET' !== $request->get_method() ||
// GET-Requests only require a signature in secure mode
( 'GET' === $request->get_method() && ACTIVITYPUB_AUTHORIZED_FETCH )
) {
$verified_request = Signature::verify_http_signature( $request );
if ( \is_wp_error( $verified_request ) ) {
return new WP_Error(

View File

@ -1,6 +1,7 @@
<?php
namespace Activitypub\Transformer;
use WP_Error;
use WP_Post;
use WP_Comment;
@ -30,9 +31,9 @@ abstract class Base {
*
* @param WP_Post|WP_Comment $wp_object The WordPress object
*
* @return Base_Object
* @return Base
*/
public static function transform( $object ) {
public static function transform( $object ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound
return new static( $object );
}

View File

@ -6,12 +6,13 @@ use WP_Comment_Query;
use Activitypub\Webfinger;
use Activitypub\Comment as Comment_Utils;
use Activitypub\Model\Blog_User;
use Activitypub\Model\Blog;
use Activitypub\Collection\Users;
use Activitypub\Transformer\Base;
use function Activitypub\is_single_user;
use function Activitypub\get_rest_url_by_path;
use function Activitypub\get_comment_ancestors;
/**
* WordPress Comment Transformer
@ -69,7 +70,7 @@ class Comment extends Base {
$this->get_locale() => $this->get_content(),
)
);
$path = sprintf( 'users/%d/followers', intval( $comment->comment_author ) );
$path = sprintf( 'actors/%d/followers', intval( $comment->comment_author ) );
$object->set_to(
array(
@ -90,7 +91,7 @@ class Comment extends Base {
*/
protected function get_attributed_to() {
if ( is_single_user() ) {
$user = new Blog_User();
$user = new Blog();
return $user->get_url();
}
@ -218,6 +219,23 @@ class Comment extends Base {
return apply_filters( 'activitypub_extract_mentions', array(), $this->wp_object->comment_content, $this->wp_object );
}
/**
* Gets the ancestors of the comment, but only the ones that are ActivityPub comments.
*
* @return array The list of ancestors.
*/
protected function get_comment_ancestors() {
$ancestors = get_comment_ancestors( $this->wp_object );
// Now that we have the full tree of ancestors, only return the ones received from the fediverse
return array_filter(
$ancestors,
function ( $comment_id ) {
return \get_comment_meta( $comment_id, 'protocol', true ) === 'activitypub';
}
);
}
/**
* Collect all other Users that participated in this comment-thread
* to send them a notification about the new reply.
@ -232,22 +250,14 @@ class Comment extends Base {
return $mentions;
}
$comment_query = new WP_Comment_Query(
array(
'post_id' => $this->wp_object->comment_post_ID,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'meta_query' => array(
array(
'key' => 'protocol',
'value' => 'activitypub',
),
),
)
);
$ancestors = $this->get_comment_ancestors();
if ( ! $ancestors ) {
return $mentions;
}
if ( $comment_query->comments ) {
foreach ( $comment_query->comments as $comment ) {
if ( ! empty( $comment->comment_author_url ) ) {
foreach ( $ancestors as $comment_id ) {
$comment = \get_comment( $comment_id );
if ( $comment && ! empty( $comment->comment_author_url ) ) {
$acct = Webfinger::uri_to_acct( $comment->comment_author_url );
if ( $acct && ! is_wp_error( $acct ) ) {
$acct = str_replace( 'acct:', '@', $acct );
@ -255,7 +265,6 @@ class Comment extends Base {
}
}
}
}
return $mentions;
}

View File

@ -11,7 +11,11 @@ use Activitypub\Transformer\Attachment;
* Transformer Factory
*/
class Factory {
public static function get_transformer( $object ) {
/**
* @param mixed $object The object to transform
* @return \Activitypub\Transformer|\WP_Error The transformer to use, or an error.
*/
public static function get_transformer( $object ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound
if ( ! \is_object( $object ) ) {
return new WP_Error( 'invalid_object', __( 'Invalid object', 'activitypub' ) );
}
@ -41,7 +45,7 @@ class Factory {
* return $transformer;
* }, 10, 3 );
*
* @param Activitypub\Transformer\Base $transformer The transformer to use.
* @param Base $transformer The transformer to use.
* @param mixed $object The object to transform.
* @param string $object_class The class of the object to transform.
*

View File

@ -3,13 +3,13 @@ namespace Activitypub\Transformer;
use WP_Post;
use Activitypub\Shortcodes;
use Activitypub\Model\Blog_User;
use Activitypub\Model\Blog;
use Activitypub\Transformer\Base;
use Activitypub\Collection\Users;
use Activitypub\Activity\Base_Object;
use function Activitypub\esc_hashtag;
use function Activitypub\is_single_user;
use function Activitypub\get_enclosures;
use function Activitypub\get_rest_url_by_path;
use function Activitypub\site_supports_blocks;
@ -70,7 +70,7 @@ class Post extends Base {
$this->get_locale() => $this->get_content(),
)
);
$path = sprintf( 'users/%d/followers', intval( $post->post_author ) );
$path = sprintf( 'actors/%d/followers', intval( $post->post_author ) );
$object->set_to(
array(
@ -116,7 +116,7 @@ class Post extends Base {
* @return string The User-URL.
*/
protected function get_attributed_to() {
$blog_user = new Blog_User();
$blog_user = new Blog();
if ( is_single_user() ) {
return $blog_user->get_url();
@ -139,14 +139,34 @@ class Post extends Base {
protected function get_attachment() {
// Once upon a time we only supported images, but we now support audio/video as well.
// We maintain the image-centric naming for backwards compatibility.
$max_media = \intval( \apply_filters( 'activitypub_max_image_attachments', \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) ) );
$max_media = \intval(
\apply_filters(
'activitypub_max_image_attachments',
\get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS )
)
);
if ( site_supports_blocks() && \has_blocks( $this->wp_object->post_content ) ) {
$media = $this->get_block_attachments( $max_media );
} else {
$media = $this->get_classic_editor_images( $max_media );
$media = array(
'audio' => array(),
'video' => array(),
'image' => array(),
);
$id = $this->wp_object->ID;
// list post thumbnail first if this post has one
if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) {
$media['image'][] = array( 'id' => \get_post_thumbnail_id( $id ) );
}
$media = $this->get_enclosures( $media );
if ( site_supports_blocks() && \has_blocks( $this->wp_object->post_content ) ) {
$media = $this->get_block_attachments( $media, $max_media );
} else {
$media = $this->get_classic_editor_images( $media, $max_media );
}
$media = self::filter_media_by_object_type( $media, \get_post_format( $this->wp_object ), $this->wp_object );
$unique_ids = \array_unique( \array_column( $media, 'id' ) );
$media = \array_intersect_key( $media, $unique_ids );
$media = \array_slice( $media, 0, $max_media );
@ -157,35 +177,21 @@ class Post extends Base {
/**
* Get media attachments from blocks. They will be formatted as ActivityPub attachments, not as WP attachments.
*
* @param array $media The media array grouped by type.
* @param int $max_media The maximum number of attachments to return.
*
* @return array The attachments.
*/
protected function get_block_attachments( $max_media ) {
protected function get_block_attachments( $media, $max_media ) {
// max media can't be negative or zero
if ( $max_media <= 0 ) {
return array();
}
$id = $this->wp_object->ID;
$media = array(
'image' => array(),
'audio' => array(),
'video' => array(),
);
// list post thumbnail first if this post has one
if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) {
$media['image'][] = array( 'id' => \get_post_thumbnail_id( $id ) );
}
if ( $max_media > 0 ) {
$blocks = \parse_blocks( $this->wp_object->post_content );
$media = self::get_media_from_blocks( $blocks, $media );
}
return self::filter_media_by_object_type( $media, \get_post_format( $this->wp_object ) );
return $media;
}
/**
@ -202,6 +208,7 @@ class Post extends Base {
if ( $max_images <= 0 ) {
return array();
}
$images = array();
$query = new \WP_Query(
array(
@ -214,6 +221,7 @@ class Post extends Base {
'posts_per_page' => $max_images,
)
);
foreach ( $query->get_posts() as $attachment ) {
if ( ! \in_array( $attachment->ID, $images, true ) ) {
$images[] = array( 'id' => $attachment->ID );
@ -249,7 +257,7 @@ class Post extends Base {
// This linter warning is a false positive - we have to
// re-count each time here as we modify $images.
// phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found
while ( $tags->next_tag( 'img' ) && ( \count( $images ) < $max_images ) ) {
while ( $tags->next_tag( 'img' ) && ( \count( $images ) <= $max_images ) ) {
$src = $tags->get_attribute( 'src' );
// If the img source is in our uploads dir, get the
@ -292,34 +300,68 @@ class Post extends Base {
* Get post images from the classic editor.
* Note that audio/video attachments are only supported in the block editor.
*
* @param array $media The media array grouped by type.
* @param int $max_images The maximum number of images to return.
*
* @return array The attachments.
*/
protected function get_classic_editor_images( $max_images ) {
protected function get_classic_editor_images( $media, $max_images ) {
// max images can't be negative or zero
if ( $max_images <= 0 ) {
return array();
}
$id = $this->wp_object->ID;
$images = array();
// list post thumbnail first if this post has one
if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) {
$images[] = \get_post_thumbnail_id( $id );
}
if ( \count( $images ) < $max_images ) {
if ( \count( $media['image'] ) <= $max_images ) {
if ( \class_exists( '\WP_HTML_Tag_Processor' ) ) {
$images = \array_merge( $images, $this->get_classic_editor_image_embeds( $max_images ) );
$media['image'] = \array_merge( $media['image'], $this->get_classic_editor_image_embeds( $max_images ) );
} else {
$images = \array_merge( $images, $this->get_classic_editor_image_attachments( $max_images ) );
$media['image'] = \array_merge( $media['image'], $this->get_classic_editor_image_attachments( $max_images ) );
}
}
return $images;
return $media;
}
/**
* Get enclosures for a post.
*
* @param array $media The media array grouped by type.
*
* @return array The media array extended with enclosures.
*/
public function get_enclosures( $media ) {
$enclosures = get_enclosures( $this->wp_object->ID );
if ( ! $enclosures ) {
return $media;
}
foreach ( $enclosures as $enclosure ) {
// check if URL is an attachment
$attachment_id = \attachment_url_to_postid( $enclosure['url'] );
if ( $attachment_id ) {
$enclosure['id'] = $attachment_id;
$enclosure['url'] = \wp_get_attachment_url( $attachment_id );
$enclosure['mediaType'] = \get_post_mime_type( $attachment_id );
}
$mime_type = $enclosure['mediaType'];
$mime_type_parts = \explode( '/', $mime_type );
switch ( $mime_type_parts[0] ) {
case 'image':
$media['image'][] = $enclosure;
break;
case 'audio':
$media['audio'][] = $enclosure;
break;
case 'video':
$media['video'][] = $enclosure;
break;
}
}
return $media;
}
/**
@ -331,7 +373,6 @@ class Post extends Base {
* @return array The image IDs.
*/
protected static function get_media_from_blocks( $blocks, $media ) {
foreach ( $blocks as $block ) {
// recurse into inner blocks
if ( ! empty( $block['innerBlocks'] ) ) {
@ -398,18 +439,18 @@ class Post extends Base {
* Filter media IDs by object type.
*
* @param array $media The media array grouped by type.
* @param array $type The object type.
* @param string $type The object type.
*
* @return array The filtered media IDs.
*/
protected static function filter_media_by_object_type( $media, $type ) {
$type = \apply_filters( 'filter_media_by_object_type', \strtolower( $type ) );
protected static function filter_media_by_object_type( $media, $type, $wp_object ) {
$type = \apply_filters( 'filter_media_by_object_type', \strtolower( $type ), $wp_object );
if ( ! empty( $media[ $type ] ) ) {
return $media[ $type ];
}
return array_merge( array(), ...array_values( $media ) );
return array_filter( array_merge( array(), ...array_values( $media ) ) );
}
/**
@ -420,6 +461,10 @@ class Post extends Base {
* @return array The ActivityPub Attachment.
*/
public static function wp_attachment_to_activity_attachment( $media ) {
if ( ! isset( $media['id'] ) ) {
return $media;
}
$id = $media['id'];
$attachment = array();
$mime_type = \get_post_mime_type( $id );
@ -427,14 +472,14 @@ class Post extends Base {
// switching on image/audio/video
switch ( $mime_type_parts[0] ) {
case 'image':
$image_size = 'full';
$image_size = 'large';
/**
* Filter the image URL returned for each post.
*
* @param array|false $thumbnail The image URL, or false if no image is available.
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*/
$thumbnail = apply_filters(
'activitypub_get_image',
@ -488,16 +533,16 @@ class Post extends Base {
* Return details about an image attachment.
*
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*
* @return array|false Array of image data, or boolean false if no image is available.
*/
protected static function get_wordpress_attachment( $id, $image_size = 'full' ) {
protected static function get_wordpress_attachment( $id, $image_size = 'large' ) {
/**
* Hook into the image retrieval process. Before image retrieval.
*
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*/
do_action( 'activitypub_get_image_pre', $id, $image_size );
@ -507,7 +552,7 @@ class Post extends Base {
* Hook into the image retrieval process. After image retrieval.
*
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*/
do_action( 'activitypub_get_image_post', $id, $image_size );
@ -536,7 +581,7 @@ class Post extends Base {
}
// Default to Article.
$object_type = 'Article';
$object_type = 'Note';
$post_format = 'standard';
if ( \get_theme_support( 'post-formats' ) ) {
@ -547,18 +592,12 @@ class Post extends Base {
switch ( $post_type ) {
case 'post':
switch ( $post_format ) {
case 'aside':
case 'status':
case 'quote':
case 'note':
case 'gallery':
case 'image':
case 'video':
case 'audio':
$object_type = 'Note';
case 'standard':
case '':
$object_type = 'Article';
break;
default:
$object_type = 'Article';
$object_type = 'Note';
break;
}
break;
@ -566,7 +605,7 @@ class Post extends Base {
$object_type = 'Page';
break;
default:
$object_type = 'Article';
$object_type = 'Note';
break;
}
@ -593,6 +632,16 @@ class Post extends Base {
return $cc;
}
public function get_audience() {
if ( is_single_user() ) {
return null;
} else {
$blog = new Blog();
return $blog->get_id();
}
}
/**
* Returns a list of Tags, used in the Post.
*
@ -708,6 +757,8 @@ class Post extends Base {
*/
do_action( 'activitypub_before_get_content', $post );
add_filter( 'render_block_core/embed', array( self::class, 'revert_embed_links' ), 10, 2 );
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$post = $this->wp_object;
$content = $this->get_post_content_template();
@ -792,4 +843,21 @@ class Post extends Base {
*/
return apply_filters( 'activitypub_post_locale', $lang, $post_id, $this->wp_object );
}
/**
* Transform Embed blocks to block level link.
*
* Remote servers will simply drop iframe elements, rendering incomplete content.
*
* @see https://www.w3.org/TR/activitypub/#security-sanitizing-content
* @see https://www.w3.org/wiki/ActivityPub/Primer/HTML
*
* @param string $block_content The block content (html)
* @param object $block The block object
*
* @return string A block level link
*/
public static function revert_embed_links( $block_content, $block ) {
return '<p><a href="' . esc_url( $block['attrs']['url'] ) . '">' . $block['attrs']['url'] . '</a></p>';
}
}

View File

@ -28,10 +28,12 @@ class Enable_Mastodon_Apps {
public static function init() {
\add_filter( 'mastodon_api_account_followers', array( self::class, 'api_account_followers' ), 10, 2 );
\add_filter( 'mastodon_api_account', array( self::class, 'api_account_add_followers' ), 20, 2 );
\add_filter( 'mastodon_api_account', array( self::class, 'api_account_external' ), 10, 2 );
\add_filter( 'mastodon_api_account', array( self::class, 'api_account_external' ), 15, 2 );
\add_filter( 'mastodon_api_search', array( self::class, 'api_search' ), 40, 2 );
\add_filter( 'mastodon_api_search', array( self::class, 'api_search_by_url' ), 40, 2 );
\add_filter( 'mastodon_api_get_posts_query_args', array( self::class, 'api_get_posts_query_args' ) );
\add_filter( 'mastodon_api_statuses', array( self::class, 'api_statuses_external' ), 10, 2 );
\add_filter( 'mastodon_api_status_context', array( self::class, 'api_get_replies' ), 10, 23 );
}
/**
@ -102,11 +104,11 @@ class Enable_Mastodon_Apps {
* @return Enable_Mastodon_Apps\Entity\Account The filtered Account
*/
public static function api_account_add_followers( $account, $user_id ) {
if ( ! $account instanceof Account || ! is_numeric( $user_id ) ) {
if ( ! $account instanceof Account ) {
return $account;
}
$user = Users::get_by_id( $user_id );
$user = Users::get_by_various( $user_id );
if ( ! $user || is_wp_error( $user ) ) {
return $account;
@ -130,7 +132,7 @@ class Enable_Mastodon_Apps {
$account->acct = $user->get_preferred_username();
$account->note = $user->get_summary();
$account->followers_count = Followers::count_followers( $user_id );
$account->followers_count = Followers::count_followers( $user->get__id() );
return $account;
}
@ -143,7 +145,7 @@ class Enable_Mastodon_Apps {
* @return Enable_Mastodon_Apps\Entity\Account The filtered Account
*/
public static function api_account_external( $user_data, $user_id ) {
if ( $user_data || is_numeric( $user_id ) ) {
if ( $user_data || ( is_numeric( $user_id ) && $user_id ) ) {
// Only augment.
return $user_data;
}
@ -201,12 +203,38 @@ class Enable_Mastodon_Apps {
$account->header = $data['image']['url'];
$account->header_static = $data['image']['url'];
}
if ( ! isset( $data['published'] ) ) {
$data['published'] = 'now';
}
$account->created_at = new DateTime( $data['published'] );
return $account;
}
public static function api_search_by_url( $search_data, $request ) {
$p = \wp_parse_url( $request->get_param( 'q' ) );
if ( ! $p || ! isset( $p['host'] ) ) {
return $search_data;
}
$object = Http::get_remote_object( $request->get_param( 'q' ), true );
if ( is_wp_error( $object ) || ! isset( $object['attributedTo'] ) ) {
return $search_data;
}
$account = self::get_account_for_actor( $object['attributedTo'] );
if ( ! $account ) {
return $search_data;
}
$status = self::activity_to_status( $object, $account );
if ( $status ) {
$search_data['statuses'][] = $status;
}
return $search_data;
}
public static function api_search( $search_data, $request ) {
$user_id = \get_current_user_id();
if ( ! $user_id ) {
@ -254,7 +282,7 @@ class Enable_Mastodon_Apps {
return $search_data;
}
public function api_get_posts_query_args( $args ) {
public static function api_get_posts_query_args( $args ) {
if ( isset( $args['author'] ) && is_string( $args['author'] ) ) {
$uri = Webfinger_Util::resolve( $args['author'] );
if ( $uri && ! is_wp_error( $uri ) ) {
@ -266,47 +294,19 @@ class Enable_Mastodon_Apps {
return $args;
}
public static function api_statuses_external( $statuses, $args ) {
if ( ! isset( $args['activitypub'] ) ) {
return $statuses;
}
$data = get_remote_metadata_by_actor( $args['activitypub'] );
if ( ! $data || is_wp_error( $data ) || ! isset( $data['outbox'] ) ) {
return $statuses;
}
$response = Http::get( $data['outbox'], true );
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
return $statuses;
}
$outbox = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! $outbox || is_wp_error( $outbox ) || ! isset( $outbox['first'] ) ) {
return $statuses;
}
$account = self::get_account_for_actor( $args['activitypub'] );
if ( ! $account ) {
return $statuses;
}
$response = Http::get( $outbox['first'], true );
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
return $statuses;
}
$posts = json_decode( wp_remote_retrieve_body( $response ), true );
$activitypub_statuses = array_map(
function ( $item ) use ( $account ) {
private static function activity_to_status( $item, $account ) {
if ( isset( $item['object'] ) ) {
$object = $item['object'];
} else {
$object = $item;
}
if ( ! isset( $object['type'] ) || 'Note' !== $object['type'] ) {
return null;
}
$status = new Status();
$status->id = Mastodon_API::remap_url( $object['id'] );
$status->id = $object['id'];
$status->created_at = new DateTime( $object['published'] );
$status->content = $object['content'];
$status->account = $account;
@ -318,8 +318,12 @@ class Enable_Mastodon_Apps {
if ( ! empty( $object['visibility'] ) ) {
$status->visibility = $object['visibility'];
}
if ( ! empty( $object['url'] ) ) {
$status->url = $object['url'];
$status->uri = $object['url'];
} else {
$status->uri = $object['id'];
}
if ( ! empty( $object['attachment'] ) ) {
$status->media_attachments = array_map(
@ -336,12 +340,15 @@ class Enable_Mastodon_Apps {
$attachment = array_merge( $default_attachment, $attachment );
$media_attachment = new Media_Attachment();
$media_attachment->id = Mastodon_API::remap_url( $attachment['url'], $attachment );
$media_attachment->id = $attachment['url'];
$media_attachment->type = strtok( $attachment['mediaType'], '/' );
$media_attachment->url = $attachment['url'];
$media_attachment->preview_url = $attachment['url'];
$media_attachment->description = $attachment['name'];
if ( $attachment['blurhash'] ) {
$media_attachment->blurhash = $attachment['blurhash'];
}
if ( $attachment['width'] > 0 && $attachment['height'] > 0 ) {
$media_attachment->meta = array(
'original' => array(
'width' => $attachment['width'],
@ -349,7 +356,7 @@ class Enable_Mastodon_Apps {
'size' => $attachment['width'] . 'x' . $attachment['height'],
'aspect' => $attachment['width'] / $attachment['height'],
),
);
);}
return $media_attachment;
},
$object['attachment']
@ -357,10 +364,99 @@ class Enable_Mastodon_Apps {
}
return $status;
}
public static function api_statuses_external( $statuses, $args ) {
if ( ! isset( $args['activitypub'] ) ) {
return $statuses;
}
$data = get_remote_metadata_by_actor( $args['activitypub'] );
if ( ! $data || is_wp_error( $data ) || ! isset( $data['outbox'] ) ) {
return $statuses;
}
$outbox = Http::get_remote_object( $data['outbox'], true );
if ( is_wp_error( $outbox ) || ! isset( $outbox['first'] ) ) {
return $statuses;
}
$account = self::get_account_for_actor( $args['activitypub'] );
if ( ! $account ) {
return $statuses;
}
$limit = 10;
if ( isset( $args['posts_per_page'] ) ) {
$limit = $args['posts_per_page'];
}
if ( $limit > 40 ) {
$limit = 40;
}
$activitypub_statuses = array();
$url = $outbox['first'];
$tries = 0;
while ( $url ) {
if ( ++$tries > 3 ) {
break;
}
$posts = Http::get_remote_object( $url, true );
if ( is_wp_error( $posts ) ) {
return $statuses;
}
$new_statuses = array_map(
function ( $item ) use ( $account, $args ) {
if ( $args['exclude_replies'] ) {
if ( isset( $item['object']['inReplyTo'] ) && $item['object']['inReplyTo'] ) {
return null;
}
}
return self::activity_to_status( $item, $account );
},
$posts['orderedItems']
);
$activitypub_statuses = array_merge( $activitypub_statuses, array_filter( $new_statuses ) );
$url = $posts['next'];
return $activitypub_statuses;
if ( count( $activitypub_statuses ) >= $limit ) {
break;
}
}
return array_slice( $activitypub_statuses, 0, $limit );
}
public static function api_get_replies( $context, $post_id, $url ) {
$meta = Http::get_remote_object( $url, true );
if ( is_wp_error( $meta ) || ! isset( $meta['replies']['first']['next'] ) ) {
return $context;
}
$replies_url = $meta['replies']['first']['next'];
$replies = Http::get_remote_object( $replies_url, true );
if ( is_wp_error( $replies ) || ! isset( $replies['items'] ) ) {
return $context;
}
foreach ( $replies['items'] as $url ) {
$response = Http::get( $url, true );
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
continue;
}
$status = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! $status || is_wp_error( $status ) ) {
continue;
}
$account = self::get_account_for_actor( $status['attributedTo'] );
$status = self::activity_to_status( $status, $account );
if ( $status ) {
$context['descendants'][ $status->id ] = $status;
}
}
return $context;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Activitypub\Integration;
class Jetpack {
public static function init() {
\add_filter( 'jetpack_sync_post_meta_whitelist', [ __CLASS__, 'add_sync_meta' ] );
}
public static function add_sync_meta( $whitelist ) {
if ( ! is_array( $whitelist ) ) {
return $whitelist;
}
$activitypub_meta_keys = [
'activitypub_user_id',
'activitypub_inbox',
'activitypub_actor_json',
];
return \array_merge( $whitelist, $activitypub_meta_keys );
}
}

View File

@ -3,7 +3,7 @@ Contributors: automattic, pfefferle, mediaformat, mattwiebe, akirk, jeherve, nur
Tags: OStatus, fediverse, activitypub, activitystream
Requires at least: 5.5
Tested up to: 6.5
Stable tag: 2.3.1
Stable tag: 2.4.0
Requires PHP: 5.6
License: MIT
License URI: http://opensource.org/licenses/MIT
@ -133,6 +133,32 @@ For reasons of data protection, it is not possible to see the followers of other
== Changelog ==
= 2.4.0 =
* Added: A core/embed block filter to transform iframes to links
* Added: Basic support of incoming `Announce`s
* Added: Improve attachment handling
* Added: Notifications: Introduce general class and use it for new follows
* Added: Always fall back to `get_by_username` if one of the above fail
* Added: Notification support for Jetpack
* Added: EMA: Support for fetching external statuses without replies
* Added: EMA: Remote context
* Added: EMA: Allow searching for URLs
* Added: EMA: Ensuring numeric ids is now done in EMA directly
* Added: Podcast support
* Added: Follower count to "At a Glance" dashboard widget
* Improved: Use `Note` as default Object-Type, instead of `Article`
* Improved: Improve `AUTHORIZED_FETCH`
* Improved: Only send Mentions to comments in the direct hierarchy
* Improved: Improve transformer
* Improved: Improve Lemmy compatibility
* Improved: Updated JS dependencies
* Fixed: EMA: Add missing static keyword and try to lookup if the id is 0
* Fixed: Blog-wide account when WordPress is in subdirectory
* Fixed: Funkwhale URLs
* Fixed: Prevent infinite loops in `get_comment_ancestors`
* Fixed: Better Content-Negotiation handling
= 2.3.1 =
* Added: Enable Mastodon Apps: Add remote outbox fetching

View File

@ -1,5 +1,5 @@
<?php
$user = new \Activitypub\Model\Blog_User();
$user = new \Activitypub\Model\Blog();
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client

View File

@ -1,36 +1,23 @@
<?php
$comment = \get_comment( \get_query_var( 'c', null ) ); // phpcs:ignore
$transformer = \Activitypub\Transformer\Factory::get_transformer( $comment );
$object = \Activitypub\Transformer\Factory::get_transformer( $comment );
$json = \array_merge( array( '@context' => \Activitypub\get_context() ), $object->to_object()->to_array() );
// filter output
$json = \apply_filters( 'activitypub_json_comment_array', $json );
if ( \is_wp_error( $transformer ) ) {
\wp_die(
\esc_html( $transformer->get_error_message() ),
404
);
}
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_json_comment_pre' );
$options = 0;
// JSON_PRETTY_PRINT added in PHP 5.4
if ( \get_query_var( 'pretty' ) ) {
$options |= \JSON_PRETTY_PRINT; // phpcs:ignore
}
$options |= \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT;
/*
* Options to be passed to json_encode()
*
* @param int $options The current options flags
*/
$options = \apply_filters( 'activitypub_json_comment_options', $options );
\header( 'Content-Type: application/activity+json' );
echo \wp_json_encode( $json, $options );
echo $transformer->to_object()->to_json(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client
*/
\do_action( 'activitypub_json_comment_comment' );
\do_action( 'activitypub_json_comment_post' );

View File

@ -1,8 +1,15 @@
<?php
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$post = \get_post();
$transformer = \Activitypub\Transformer\Factory::get_transformer( $post );
if ( \is_wp_error( $transformer ) ) {
\wp_die(
esc_html( $transformer->get_error_message() ),
404
);
}
$post_object = \Activitypub\Transformer\Factory::get_transformer( $post )->to_object();
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
@ -10,7 +17,7 @@ $post_object = \Activitypub\Transformer\Factory::get_transformer( $post )->to_ob
\do_action( 'activitypub_json_post_pre' );
\header( 'Content-Type: application/activity+json' );
echo $post_object->to_json(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $transformer->to_object()->to_json(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client

View File

@ -52,7 +52,7 @@
</th>
<td>
<label for="activitypub_blog_user_identifier">
<input class="blog-user-identifier" name="activitypub_blog_user_identifier" id="activitypub_blog_user_identifier" type="text" value="<?php echo esc_attr( \get_option( 'activitypub_blog_user_identifier', \Activitypub\Model\Blog_User::get_default_username() ) ); ?>" />
<input class="blog-user-identifier" name="activitypub_blog_user_identifier" id="activitypub_blog_user_identifier" type="text" value="<?php echo esc_attr( \get_option( 'activitypub_blog_user_identifier', \Activitypub\Model\Blog::get_default_username() ) ); ?>" />
@<?php echo esc_html( \wp_parse_url( \home_url(), PHP_URL_HOST ) ); ?>
</label>
<p class="description">

View File

@ -19,7 +19,7 @@
<?php
if ( ! \Activitypub\is_user_disabled( \Activitypub\Collection\Users::BLOG_USER_ID ) ) :
$blog_user = new \Activitypub\Model\Blog_User();
$blog_user = new \Activitypub\Model\Blog();
?>
<div class="box">
<h3><?php \esc_html_e( 'Blog profile', 'activitypub' ); ?></h3>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpunit" version="^9.5.21" installed="9.5.21" location="./tools/phpunit" copy="true"/>
<phar name="phpcs" version="^3.7.1" installed="3.7.1" location="./tools/phpcs" copy="true"/>
<phar name="phpcbf" version="^3.7.1" installed="3.7.1" location="./tools/phpcbf" copy="true"/>
<phar name="behat/behat" version="^3.13.0" installed="3.13.0" location="./tools/behat" copy="true"/>
<phar name="wp-cli/wp-cli" version="^2.9.0" installed="2.9.0" location="./tools/wp-cli" copy="true"/>
</phive>

View File

@ -1,7 +0,0 @@
Copyright <YEAR> <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,95 +0,0 @@
# authLDAP
[![Join the chat at https://gitter.im/heiglandreas/authLdap](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/heiglandreas/authLdap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Use your existing LDAP as authentication-backend for your wordpress!
[![Build Status](https://github.com/heiglandreas/authLdap/actions/workflows/tests.yml/badge.svg)](https://github.com/heiglandreas/authLdap/actions/workflows/tests.yml)
[![WordPress Stats](https://img.shields.io/wordpress/plugin/dt/authldap.svg)](https://wordpress.org/plugins/authldap/stats/)
[![WordPress Version](https://img.shields.io/wordpress/plugin/v/authldap.svg)](https://wordpress.org/plugins/authldap/)
[![WordPress testet](https://img.shields.io/wordpress/v/authldap.svg)](https://wordpress.org/plugins/authldap/)
[![Code Climate](https://codeclimate.com/github/heiglandreas/authLdap/badges/gpa.svg)](https://codeclimate.com/github/heiglandreas/authLdap)
[![codecov](https://codecov.io/gh/heiglandreas/authLdap/branch/master/graph/badge.svg?token=AYAhEeWtRQ)](https://codecov.io/gh/heiglandreas/authLdap)
So what are the differences to other Wordpress-LDAP-Authentication-Plugins?
* **Flexible**: You are totaly free in which LDAP-backend to use. Due to the extensive configuration you can
freely decide how to do the authentication of your users. It simply depends on your
filters
* **Independent**: As soon as a user logs in, it is added/updated to the Wordpress' user-database
to allow wordpress to always use the correct data. You only have to administer your users once.
* **Failsafe**: Due to the users being created in Wordpress' User-database they can
also log in when the LDAP-backend currently is gone.
* **Role-Aware**: You can map Wordpress' roles to values of an existing LDAP-attribute.
## How does the plugin work?
Well, as a matter of fact it is rather simple. The plugin verifies, that the user
seeking authentification can bind to the LDAP using the provided password.
If that is so, the user is either created or updated in the wordpress-user-database.
This update includes the provided password (so the wordpress can authenticate users
even without the LDAP), the users name according to the authLDAP-preferences and
the status of the user depending on the groups-settings of the authLDAP-preferences
Writing this plugin would not have been as easy as it has been, without the
wonderfull plugin of Alistair Young from http://www.weblogs.uhi.ac.uk/sm00ay/?p=45
## Configuration
### Usage Settings
* **Enable Authentication via LDAP** Whether you want to enable authLdap for login or not
* **debug authLdap** When you have problems with authentication via LDAP you can enable a debugging mode here.
* **Save entered Password** Decide whether passwords will be cached in your wordpress-installation. **Attention:** Without the cache your users will not be able to log into your site when your LDAP is down!
### Server Settings
* **LDAP Uri** This is the URI where your ldap-backend can be reached. More information are actually on the Configuration page
* **Filter** This is the real McCoy! The filter you define here specifies how a user will be found. Before applying the filter a %s will be replaced with the given username. This means, when a user logs in using foobar as username the following happens:
* **uid=%1$s** check for any LDAP-Entry that has an attribute uid with value foobar
* **(&(objectclass=posixAccount)(|(uid=%1$s)(mail=%1$s)))** check for any LDAP-Entry that has an attribute objectclass with value posixAccout and either a UID- or a mail-attribute with value foobar
This filter is rather powerfull if used wisely.
### Creating Users
* **Name-Attribute** Which Attribute from the LDAP contains the Full or the First name of the user trying to log in. This defaults to name
* **Second Name Attribute** If the above Name-Attribute only contains the First Name of the user you can here specify an Attribute that contains the second name. This field is empty by default
* **User-ID Attribute** This field will be used as login-name for wordpress. Please give the Attribute, that is used to identify the user. This should be the same as you used in the above Filter-Option. This field defaults to uid
* **Mail Attribute** Which Attribute holds the eMail-Address of the user? If more than one eMail-Address are stored in the LDAP, only the first given is used. This field defaults to mail
* **Web-Attribute** If your users have a personal page (URI) stored in the LDAP, it can be provided here. This field is empty by default
### User-Groups for Roles
* **Group-Attribute** This is the attribute that defines the Group-ID that can be matched against the Groups defined further down This field defaults to gidNumber.
* **Group-Filter** Here you can add the filter for selecting groups for the currentlly logged in user The Filter should contain the string %s which will be replaced by the login-name of the currently logged in
## FAQ
<dl>
<dt>Can I change a users password with this plugin?</dt>
<dd>Short Answer: <strong>No</strong>!<br>Long Answer: As the users credentials are not
only used for a wordpress-site when you authenticate against an LDAP but for
many other services also chances are great that there is a centralized place
where password-changes shall be made. We'll later allow inclusion of a link
to such a place but currently it's not available. And as password-hashing and
where to store it requires deeper insight into the LDAP-Server then most users
have and admins are willing to give, password changes are out of scope of this
plugin. If you know exactyl what you do, you might want to have a look at
<a href="https://github.com/heiglandreas/authLdap/issues/54#issuecomment-125851029">
issue 54</a>
wherer a way of adding it is described!
</dd>
<dt>Can I add a user to the LDAP when she creates a user-account on wordpress?</dt>
<dd>Short Answer: <strong>No</strong>!<br>Long Answer: Even though that is technically possible
it's not in the scope of this plugin. As creating a user in an LDAP often involves
an administrative process that has already been implemented in your departments
administration it doesn't make sense to rebuild that - in most cases highly
individual - process in this plugin. If you know exactly what you do, have a look at
<a href="https://github.com/heiglandreas/authLdap/issues/65">issue 65</a>
where <a href="https://github.com/wtfiwtz">wtfiwtz</a> shows how to implement that feature.
</dd>
</dl>

View File

@ -1,18 +0,0 @@
# Security-Policy
## Supported Versions
| Version | Supported |
| ------- |--------------------|
| 2.x | :white_check_mark: |
| 1.x | :x: |
## Reporting a Vulnerability
* Check our security.txt file for details on how to contact us
* Contact us before publicly disclosing the issue anywhere else
This plugin is developed as OpenSource under the MIT licence.
There is no money earned from it. Therefore we are not able to
provide any bug-bounties whatsoever. You will be mentioned in the
release notes of a fix-release though.

View File

@ -1,13 +0,0 @@
.row {
overflow: hidden;
padding-top: 10px;
}
.element {
float: right;
text-align: left;
}
.authldap-options input[type=text] {
width: 100%;
}

View File

@ -1,946 +0,0 @@
<?php
/*
Plugin Name: AuthLDAP
Plugin URI: https://github.com/heiglandreas/authLdap
Description: This plugin allows you to use your existing LDAP as authentication base for WordPress
Version: 2.6.0
Author: Andreas Heigl <andreas@heigl.org>
Author URI: http://andreas.heigl.org
License: MIT
License URI: https://opensource.org/licenses/MIT
*/
// phpcs:disable PSR1.Files.SideEffects
use Org_Heigl\AuthLdap\LdapList;
use Org_Heigl\AuthLdap\LdapUri;
use Org_Heigl\AuthLdap\Manager\Ldap;
use Org_Heigl\AuthLdap\UserRoleHandler;
use Org_Heigl\AuthLdap\Wrapper\LdapFactory;
require_once __DIR__ . '/src/Wrapper/LdapInterface.php';
require_once __DIR__ . '/src/Exception/Error.php';
require_once __DIR__ . '/src/Exception/InvalidLdapUri.php';
require_once __DIR__ . '/src/Exception/Error.php';
require_once __DIR__ . '/src/Exception/InvalidLdapUri.php';
require_once __DIR__ . '/src/Exception/MissingValidLdapConnection.php';
require_once __DIR__ . '/src/Exception/SearchUnsuccessfull.php';
require_once __DIR__ . '/src/Manager/Ldap.php';
require_once __DIR__ . '/src/Wrapper/Ldap.php';
require_once __DIR__ . '/src/Wrapper/LdapFactory.php';
require_once __DIR__ . '/src/LdapList.php';
require_once __DIR__ . '/src/LdapUri.php';
require_once __DIR__ . '/src/UserRoleHandler.php';
function authLdap_debug($message)
{
if (authLdap_get_option('Debug')) {
error_log('[AuthLDAP] ' . $message, 0);
}
}
function authLdap_addmenu()
{
if (!is_multisite()) {
add_options_page(
'AuthLDAP',
'AuthLDAP',
'manage_options',
basename(__FILE__),
'authLdap_options_panel'
);
} else {
add_submenu_page(
'settings.php',
'AuthLDAP',
'AuthLDAP',
'manage_options',
'authldap',
'authLdap_options_panel'
);
}
}
function authLdap_get_post($name, $default = '')
{
return isset($_POST[$name]) ? $_POST[$name] : $default;
}
function authLdap_options_panel()
{
// inclusde style sheet
wp_enqueue_style('authLdap-style', plugin_dir_url(__FILE__) . 'authLdap.css');
if (($_SERVER['REQUEST_METHOD'] == 'POST') && array_key_exists('ldapOptionsSave', $_POST)) {
if (!isset($_POST['authLdapNonce'])) {
die("Go away!");
}
if (!wp_verify_nonce($_POST['authLdapNonce'],'authLdapNonce')) {
die("Go away!");
}
$new_options = [
'Enabled' => authLdap_get_post('authLDAPAuth', false),
'CachePW' => authLdap_get_post('authLDAPCachePW', false),
'URI' => authLdap_get_post('authLDAPURI'),
'URISeparator' => authLdap_get_post('authLDAPURISeparator'),
'StartTLS' => authLdap_get_post('authLDAPStartTLS', false),
'Filter' => authLdap_get_post('authLDAPFilter'),
'NameAttr' => authLdap_get_post('authLDAPNameAttr'),
'SecName' => authLdap_get_post('authLDAPSecName'),
'UidAttr' => authLdap_get_post('authLDAPUidAttr'),
'MailAttr' => authLdap_get_post('authLDAPMailAttr'),
'WebAttr' => authLdap_get_post('authLDAPWebAttr'),
'Groups' => authLdap_get_post('authLDAPGroups', []),
'GroupSeparator' => authLdap_get_post('authLDAPGroupSeparator', ','),
'Debug' => authLdap_get_post('authLDAPDebug', false),
'GroupBase' => authLdap_get_post('authLDAPGroupBase'),
'GroupAttr' => authLdap_get_post('authLDAPGroupAttr'),
'GroupFilter' => authLdap_get_post('authLDAPGroupFilter'),
'DefaultRole' => authLdap_get_post('authLDAPDefaultRole'),
'GroupEnable' => authLdap_get_post('authLDAPGroupEnable', false),
'GroupOverUser' => authLdap_get_post('authLDAPGroupOverUser', false),
'DoNotOverwriteNonLdapUsers' => authLdap_get_post('authLDAPDoNotOverwriteNonLdapUsers', false),
'UserRead' => authLdap_get_post('authLDAPUseUserAccount', false),
];
if (authLdap_set_options($new_options)) {
echo "<div class='updated'><p>Saved Options!</p></div>";
} else {
echo "<div class='error'><p>Could not save Options!</p></div>";
}
}
// Do some initialization for the admin-view
$authLDAP = authLdap_get_option('Enabled');
$authLDAPCachePW = authLdap_get_option('CachePW');
$authLDAPURI = authLdap_get_option('URI');
$authLDAPURISeparator = authLdap_get_option('URISeparator');
$authLDAPStartTLS = authLdap_get_option('StartTLS');
$authLDAPFilter = authLdap_get_option('Filter');
$authLDAPNameAttr = authLdap_get_option('NameAttr');
$authLDAPSecName = authLdap_get_option('SecName');
$authLDAPMailAttr = authLdap_get_option('MailAttr');
$authLDAPUidAttr = authLdap_get_option('UidAttr');
$authLDAPWebAttr = authLdap_get_option('WebAttr');
$authLDAPGroups = authLdap_get_option('Groups');
$authLDAPGroupSeparator = authLdap_get_option('GroupSeparator');
$authLDAPDebug = authLdap_get_option('Debug');
$authLDAPGroupBase = authLdap_get_option('GroupBase');
$authLDAPGroupAttr = authLdap_get_option('GroupAttr');
$authLDAPGroupFilter = authLdap_get_option('GroupFilter');
$authLDAPDefaultRole = authLdap_get_option('DefaultRole');
$authLDAPGroupEnable = authLdap_get_option('GroupEnable');
$authLDAPGroupOverUser = authLdap_get_option('GroupOverUser');
$authLDAPDoNotOverwriteNonLdapUsers = authLdap_get_option('DoNotOverwriteNonLdapUsers');
$authLDAPUseUserAccount = authLdap_get_option('UserRead');
$tChecked = ($authLDAP) ? ' checked="checked"' : '';
$tDebugChecked = ($authLDAPDebug) ? ' checked="checked"' : '';
$tPWChecked = ($authLDAPCachePW) ? ' checked="checked"' : '';
$tGroupChecked = ($authLDAPGroupEnable) ? ' checked="checked"' : '';
$tGroupOverUserChecked = ($authLDAPGroupOverUser) ? ' checked="checked"' : '';
$tStartTLSChecked = ($authLDAPStartTLS) ? ' checked="checked"' : '';
$tDoNotOverwriteNonLdapUsers = ($authLDAPDoNotOverwriteNonLdapUsers) ? ' checked="checked"' : '';
$tUserRead = ($authLDAPUseUserAccount) ? ' checked="checked"' : '';
$roles = new WP_Roles();
$action = $_SERVER['REQUEST_URI'];
if (!extension_loaded('ldap')) {
echo '<div class="warning">The LDAP-Extension is not available on your '
. 'WebServer. Therefore Everything you can alter here does not '
. 'make any sense!</div>';
}
include dirname(__FILE__) . '/view/admin.phtml';
}
/**
* get a LDAP server object
*
* throws exception if there is a problem connecting
*
* @conf boolean authLDAPDebug true, if debugging should be turned on
* @conf string authLDAPURI LDAP server URI
*
* @return Org_Heigl\AuthLdap\LdapList LDAP server object
*/
function authLdap_get_server()
{
static $_ldapserver = null;
if (is_null($_ldapserver)) {
$authLDAPDebug = authLdap_get_option('Debug');
$authLDAPURI = explode(
authLdap_get_option('URISeparator', ' '),
authLdap_get_option('URI')
);
$authLDAPStartTLS = authLdap_get_option('StartTLS');
//$authLDAPURI = 'ldap:/foo:bar@server/trallala';
authLdap_debug('connect to LDAP server');
require_once dirname(__FILE__) . '/src/LdapList.php';
$_ldapserver = new LdapList();
foreach ($authLDAPURI as $uri) {
$_ldapserver->addLdap(new Ldap(
new LdapFactory(),
LdapUri::fromString($uri),
$authLDAPStartTLS
));
}
}
return $_ldapserver;
}
/**
* This method authenticates a user using either the LDAP or, if LDAP is not
* available, the local database
*
* For this we store the hashed passwords in the WP_Database to ensure working
* conditions even without an LDAP-Connection
*
* @param null|WP_User|WP_Error
* @param string $username
* @param string $password
* @param boolean $already_md5
* @return boolean true, if login was successfull or false, if it wasn't
* @conf boolean authLDAP true, if authLDAP should be used, false if not. Defaults to false
* @conf string authLDAPFilter LDAP filter to use to find correct user, defaults to '(uid=%s)'
* @conf string authLDAPNameAttr LDAP attribute containing user (display) name, defaults to 'name'
* @conf string authLDAPSecName LDAP attribute containing second name, defaults to ''
* @conf string authLDAPMailAttr LDAP attribute containing user e-mail, defaults to 'mail'
* @conf string authLDAPUidAttr LDAP attribute containing user id (the username we log on with), defaults to 'uid'
* @conf string authLDAPWebAttr LDAP attribute containing user website, defaults to ''
* @conf string authLDAPDefaultRole default role for authenticated user, defaults to ''
* @conf boolean authLDAPGroupEnable true, if we try to map LDAP groups to Wordpress roles
* @conf boolean authLDAPGroupOverUser true, if LDAP Groups have precedence over existing user roles
*/
function authLdap_login($user, $username, $password, $already_md5 = false)
{
// don't do anything when authLDAP is disabled
if (!authLdap_get_option('Enabled')) {
authLdap_debug(
'LDAP disabled in AuthLDAP plugin options (use the first option in the AuthLDAP options to enable it)'
);
return $user;
}
// If the user has already been authenticated (only in that case we get a
// WP_User-Object as $user) we skip LDAP-authentication and simply return
// the existing user-object
if ($user instanceof WP_User) {
authLdap_debug(sprintf(
'User %s has already been authenticated - skipping LDAP-Authentication',
$user->get('nickname')
));
return $user;
}
authLdap_debug("User '$username' logging in");
if ($username == 'admin') {
authLdap_debug('Doing nothing for possible local user admin');
return $user;
}
global $wpdb, $error;
try {
$authLDAP = authLdap_get_option('Enabled');
$authLDAPFilter = authLdap_get_option('Filter');
$authLDAPNameAttr = authLdap_get_option('NameAttr');
$authLDAPSecName = authLdap_get_option('SecName');
$authLDAPMailAttr = authLdap_get_option('MailAttr');
$authLDAPUidAttr = authLdap_get_option('UidAttr');
$authLDAPWebAttr = authLdap_get_option('WebAttr');
$authLDAPDefaultRole = authLdap_get_option('DefaultRole');
$authLDAPGroupEnable = authLdap_get_option('GroupEnable');
$authLDAPGroupOverUser = authLdap_get_option('GroupOverUser');
$authLDAPUseUserAccount = authLdap_get_option('UserRead');
if (!$username) {
authLdap_debug('Username not supplied: return false');
return false;
}
if (!$password) {
authLdap_debug('Password not supplied: return false');
$error = __('<strong>Error</strong>: The password field is empty.');
return false;
}
// First check for valid values and set appropriate defaults
if (!$authLDAPFilter) {
$authLDAPFilter = '(uid=%s)';
}
if (!$authLDAPNameAttr) {
$authLDAPNameAttr = 'name';
}
if (!$authLDAPMailAttr) {
$authLDAPMailAttr = 'mail';
}
if (!$authLDAPUidAttr) {
$authLDAPUidAttr = 'uid';
}
// If already_md5 is TRUE, then we're getting the user/password from the cookie. As we don't want
// to store LDAP passwords in any
// form, we've already replaced the password with the hashed username and LDAP_COOKIE_MARKER
if ($already_md5) {
if ($password == md5($username) . md5($ldapCookieMarker)) {
authLdap_debug('cookie authentication');
return true;
}
}
// Remove slashes as noted on https://github.com/heiglandreas/authLdap/issues/108
$password = stripslashes_deep($password);
// No cookie, so have to authenticate them via LDAP
$result = false;
try {
authLdap_debug('about to do LDAP authentication');
$result = authLdap_get_server()->Authenticate($username, $password, $authLDAPFilter);
} catch (Exception $e) {
authLdap_debug('LDAP authentication failed with exception: ' . $e->getMessage());
return false;
}
// Make optional querying from the admin account #213
if (!authLdap_get_option('UserRead')) {
// Rebind with the default credentials after the user has been loged in
// Otherwise the credentials of the user trying to login will be used
// This fixes #55
authLdap_get_server()->bind();
}
if (true !== $result) {
authLdap_debug('LDAP authentication failed');
// TODO what to return? WP_User object, true, false, even an WP_Error object...
// all seem to fall back to normal wp user authentication
return;
}
authLdap_debug('LDAP authentication successful');
$attributes = array_values(
array_filter(
apply_filters(
'authLdap_filter_attributes',
[
$authLDAPNameAttr,
$authLDAPSecName,
$authLDAPMailAttr,
$authLDAPWebAttr,
$authLDAPUidAttr,
]
)
)
);
try {
$attribs = authLdap_get_server()->search(
sprintf($authLDAPFilter, $username),
$attributes
);
// First get all the relevant group informations so we can see if
// whether have been changes in group association of the user
if (!isset($attribs[0]['dn'])) {
authLdap_debug('could not get user attributes from LDAP');
throw new UnexpectedValueException('dn has not been returned');
}
if (!isset($attribs[0][strtolower($authLDAPUidAttr)][0])) {
authLdap_debug('could not get user attributes from LDAP');
throw new UnexpectedValueException('The user-ID attribute has not been returned');
}
$dn = $attribs[0]['dn'];
$realuid = $attribs[0][strtolower($authLDAPUidAttr)][0];
} catch (Exception $e) {
authLdap_debug('Exception getting LDAP user: ' . $e->getMessage());
return false;
}
$uid = authLdap_get_uid($realuid);
// This fixes #172
if (true == authLdap_get_option('DoNotOverwriteNonLdapUsers', false)) {
if (!get_user_meta($uid, 'authLDAP')) {
return null;
}
}
$roles = [];
// we only need this if either LDAP groups are disabled or
// if the WordPress role of the user overrides LDAP groups
if (!$authLDAPGroupEnable || $authLDAPGroupOverUser) {
$userRoles = authLdap_user_role($uid);
if ($userRoles !== []) {
$roles = array_merge($roles, $userRoles);
}
// TODO, this needs to be revised, it seems, like authldap is taking only the first role
// even if in WP there are assigned multiple.
}
// do LDAP group mapping if needed
// (if LDAP groups override worpress user role, $role is still empty)
if (empty($roles) && $authLDAPGroupEnable) {
$mappedRoles = authLdap_groupmap($realuid, $dn);
if ($mappedRoles !== []) {
$roles = $mappedRoles;
authLdap_debug('role from group mapping: ' . json_encode($roles));
}
}
// if we don't have a role yet, use default role
if (empty($roles) && !empty($authLDAPDefaultRole)) {
authLdap_debug('no role yet, set default role');
$roles[] = $authLDAPDefaultRole;
}
if (empty($roles)) {
// Sorry, but you are not in any group that is allowed access
trigger_error('no group found');
authLdap_debug('user is not in any group that is allowed access');
return false;
} else {
$wp_roles = new WP_Roles();
// not sure if this is needed, but it can't hurt
// Get rid of unexisting roles.
foreach ($roles as $k => $v) {
if (!$wp_roles->is_role($v)) {
unset($k);
}
}
// check if single role or an empty array provided
if (empty($roles)) {
trigger_error('no group found');
authLdap_debug('role is invalid');
return false;
}
}
// from here on, the user has access!
// now, lets update some user details
$user_info = [];
$user_info['user_login'] = $realuid;
$user_info['user_email'] = '';
$user_info['user_nicename'] = '';
// first name
if (isset($attribs[0][strtolower((string) $authLDAPNameAttr)][0])) {
$user_info['first_name'] = $attribs[0][strtolower((string) $authLDAPNameAttr)][0];
}
// last name
if (isset($attribs[0][strtolower((string) $authLDAPSecName)][0])) {
$user_info['last_name'] = $attribs[0][strtolower((string) $authLDAPSecName)][0];
}
// mail address
if (isset($attribs[0][strtolower((string) $authLDAPMailAttr)][0])) {
$user_info['user_email'] = $attribs[0][strtolower((string) $authLDAPMailAttr)][0];
}
// website
if (isset($attribs[0][strtolower((string) $authLDAPWebAttr)][0])) {
$user_info['user_url'] = $attribs[0][strtolower((string) $authLDAPWebAttr)][0];
}
// display name, nickname, nicename
if (array_key_exists('first_name', $user_info)) {
$user_info['display_name'] = $user_info['first_name'];
$user_info['nickname'] = $user_info['first_name'];
$user_info['user_nicename'] = sanitize_title_with_dashes($user_info['first_name']);
if (array_key_exists('last_name', $user_info)) {
$user_info['display_name'] .= ' ' . $user_info['last_name'];
$user_info['nickname'] .= ' ' . $user_info['last_name'];
$user_info['user_nicename'] .= '_' . sanitize_title_with_dashes($user_info['last_name']);
}
}
$user_info['user_nicename'] = substr($user_info['user_nicename'], 0, 50);
// optionally store the password into the wordpress database
if (authLdap_get_option('CachePW')) {
// Password will be hashed inside wp_update_user or wp_insert_user
$user_info['user_pass'] = $password;
} else {
// clear the password
$user_info['user_pass'] = '';
}
// add uid if user exists
if ($uid) {
// found user in the database
authLdap_debug('The LDAP user has an entry in the WP-Database');
$user_info['ID'] = $uid;
unset($user_info['display_name'], $user_info['nickname']);
$userid = wp_update_user($user_info);
} else {
// new wordpress account will be created
authLdap_debug('The LDAP user does not have an entry in the WP-Database, a new WP account will be created');
$userid = wp_insert_user($user_info);
}
// if the user exists, wp_insert_user will update the existing user record
if (is_wp_error($userid)) {
authLdap_debug('Error creating user : ' . $userid->get_error_message());
trigger_error('Error creating user: ' . $userid->get_error_message());
return $userid;
}
// Update user roles.
$user = new \WP_User($userid);
/**
* Add hook for custom User-Role assignment
*
* @param WP_User $user This user-object will be returned. Can be modified as necessary in the actions.
* @param array $roles
*/
do_action('authldap_user_roles', $user, $roles);
/**
* Add hook for custom updates
*
* @param int $userid User ID.
* @param array $attribs [0] Attributes retrieved from LDAP for the user.
*/
do_action('authLdap_login_successful', $userid, $attribs[0]);
authLdap_debug('user id = ' . $userid);
// flag the user as an ldap user so we can hide the password fields in the user profile
update_user_meta($userid, 'authLDAP', true);
// return a user object upon positive authorization
return $user;
} catch (Exception $e) {
authLdap_debug($e->getMessage() . '. Exception thrown in line ' . $e->getLine());
trigger_error($e->getMessage() . '. Exception thrown in line ' . $e->getLine());
}
}
/**
* Get user's user id
*
* Returns null if username not found
*
* @param string $username username
* @param string user id, null if not found
*/
function authLdap_get_uid($username)
{
global $wpdb;
// find out whether the user is already present in the database
$uid = $wpdb->get_var(
$wpdb->prepare(
"SELECT ID FROM {$wpdb->users} WHERE user_login = %s",
$username
)
);
if ($uid) {
authLdap_debug("Existing user, uid = {$uid}");
return $uid;
} else {
return null;
}
}
/**
* Get the user's current role
*
* Returns empty string if not found.
*
* @param int $uid wordpress user id
* @return array roles, empty if none found
*/
function authLdap_user_role($uid)
{
global $wpdb, $wp_roles;
if (!$uid) {
return [];
}
/** @var array<string, bool> $usercapabilities */
$usercapabilities = get_user_meta($uid, "{$wpdb->prefix}capabilities", true);
if (!is_array($usercapabilities)) {
return [];
}
/** @var array<string, array{name: string, capabilities: array<mixed>} $editable_roles */
$editable_roles = $wp_roles->roles;
// By using this approach we are now using the order of the roles from the WP_Roles object
// and not from the capabilities any more.
$userroles = array_keys(array_intersect_key($editable_roles, $usercapabilities));
authLdap_debug(sprintf("Existing user's roles: %s", implode(', ', $userroles)));
return $userroles;
}
/**
* Get LDAP groups for user and map to role
*
* @param string $username
* @param string $dn
* @return array role, empty array if no mapping found, first or all role(s) found otherwise
* @conf array authLDAPGroups, associative array, role => ldap_group
* @conf string authLDAPGroupBase, base dn to look up groups
* @conf string authLDAPGroupAttr, ldap attribute that holds name of group
* @conf string authLDAPGroupFilter, LDAP filter to find groups. can contain %s and %dn% placeholders
*/
function authLdap_groupmap($username, $dn)
{
$authLDAPGroups = authLdap_sort_roles_by_capabilities(
authLdap_get_option('Groups')
);
$authLDAPGroupBase = authLdap_get_option('GroupBase');
$authLDAPGroupAttr = authLdap_get_option('GroupAttr');
$authLDAPGroupFilter = authLdap_get_option('GroupFilter');
$authLDAPGroupSeparator = authLdap_get_option('GroupSeparator');
if (!$authLDAPGroupAttr) {
$authLDAPGroupAttr = 'gidNumber';
}
if (!$authLDAPGroupFilter) {
$authLDAPGroupFilter = '(&(objectClass=posixGroup)(memberUid=%s))';
}
if (!$authLDAPGroupSeparator) {
$authLDAPGroupSeparator = ',';
}
if (!is_array($authLDAPGroups) || count(array_filter(array_values($authLDAPGroups))) == 0) {
authLdap_debug('No group names defined');
return [];
}
try {
// To allow searches based on the DN instead of the uid, we replace the
// string %dn% with the users DN.
$authLDAPGroupFilter = str_replace(
'%dn%',
ldap_escape($dn, '', LDAP_ESCAPE_FILTER),
$authLDAPGroupFilter
);
authLdap_debug('Group Filter: ' . json_encode($authLDAPGroupFilter));
authLdap_debug('Group Base: ' . $authLDAPGroupBase);
$groups = authLdap_get_server()->search(
sprintf($authLDAPGroupFilter, ldap_escape($username, '', LDAP_ESCAPE_FILTER)),
[$authLDAPGroupAttr],
$authLDAPGroupBase
);
} catch (Exception $e) {
authLdap_debug('Exception getting LDAP group attributes: ' . $e->getMessage());
return [];
}
$grp = [];
for ($i = 0; $i < $groups ['count']; $i++) {
if ($authLDAPGroupAttr == "dn") {
$grp[] = $groups[$i]['dn'];
} else {
for ($k = 0; $k < $groups[$i][strtolower($authLDAPGroupAttr)]['count']; $k++) {
$grp[] = $groups[$i][strtolower($authLDAPGroupAttr)][$k];
}
}
}
authLdap_debug('LDAP groups: ' . json_encode($grp));
// Check whether the user is member of one of the groups that are
// allowed acces to the blog. If the user is not member of one of
// The groups throw her out! ;-)
$roles = [];
foreach ($authLDAPGroups as $key => $val) {
$currentGroup = explode($authLDAPGroupSeparator, $val);
// Remove whitespaces around the group-ID
$currentGroup = array_map('trim', $currentGroup);
if (0 < count(array_intersect($currentGroup, $grp))) {
$roles[] = $key;
}
}
// Default: If the user is member of more than one group only the first one
// will be taken into account!
// This filter allows you to return multiple user roles. WordPress
// supports this functionality, but not natively via UI from Users
// overview (you need to use a plugin). However, it's still widely used,
// for example, by WooCommerce, etc. Use if you know what you're doing.
if (apply_filters('authLdap_allow_multiple_roles', false) === false && count($roles) > 1) {
$roles = array_slice($roles, 0, 1);
}
authLdap_debug("Roles from LDAP group: " . json_encode($roles));
return $roles;
}
/**
* This function disables the password-change fields in the users preferences.
*
* It does not make sense to authenticate via LDAP and then allow the user to
* change the password only in the wordpress database. And changing the password
* LDAP-wide can not be the scope of Wordpress!
*
* Whether the user is an LDAP-User or not is determined using the authLDAP-Flag
* of the users meta-informations
*
* @return false, if the user whose prefs are viewed is an LDAP-User, true if
* he isn't
* @conf boolean authLDAP
*/
function authLdap_show_password_fields($return, $user)
{
if (!$user) {
return true;
}
if (get_user_meta($user->ID, 'authLDAP')) {
return false;
}
return $return;
}
/**
* This function disables the password reset for a user.
*
* It does not make sense to authenticate via LDAP and then allow the user to
* reset the password only in the wordpress database. And changing the password
* LDAP-wide can not be the scope of Wordpress!
*
* Whether the user is an LDAP-User or not is determined using the authLDAP-Flag
* of the users meta-informations
*
* @author chaplina (https://github.com/chaplina)
* @conf boolean authLDAP
* @return false, if the user is an LDAP-User, true if he isn't
*/
function authLdap_allow_password_reset($return, $userid)
{
if (!(isset($userid))) {
return true;
}
if (get_user_meta($userid, 'authLDAP')) {
return false;
}
return $return;
}
/**
* Sort the given roles by number of capabilities
*
* @param array $roles
*
* @return array
*/
function authLdap_sort_roles_by_capabilities($roles)
{
global $wpdb;
$myRoles = get_option($wpdb->get_blog_prefix() . 'user_roles');
authLdap_debug(print_r($roles, true));
uasort($myRoles, 'authLdap_sortByCapabilitycount');
$return = [];
foreach ($myRoles as $key => $role) {
if (isset($roles[$key])) {
$return[$key] = $roles[$key];
}
}
authLdap_debug(print_r($return, true));
return $return;
}
/**
* Sort according to the number of capabilities
*
* @param $a
* @param $b
*/
function authLdap_sortByCapabilitycount($a, $b)
{
if (count($a['capabilities']) > count($b['capabilities'])) {
return -1;
}
if (count($a['capabilities']) < count($b['capabilities'])) {
return 1;
}
return 0;
}
/**
* Load AuthLDAP Options
*
* Sets and stores defaults if options are not up to date
*/
function authLdap_load_options($reload = false)
{
static $options = null;
// the current version for options
$option_version_plugin = 1;
$optionFunction = 'get_option';
if (is_multisite()) {
$optionFunction = 'get_site_option';
}
if (is_null($options) || $reload) {
$options = $optionFunction('authLDAPOptions', []);
}
// check if option version has changed (or if it's there at all)
if (!isset($options['Version']) || ($options['Version'] != $option_version_plugin)) {
// defaults for all options
$options_default = [
'Enabled' => false,
'CachePW' => false,
'URI' => '',
'URISeparator' => ' ',
'Filter' => '', // '(uid=%s)'
'NameAttr' => '', // 'name'
'SecName' => '',
'UidAttr' => '', // 'uid'
'MailAttr' => '', // 'mail'
'WebAttr' => '',
'Groups' => [],
'Debug' => false,
'GroupAttr' => '', // 'gidNumber'
'GroupFilter' => '', // '(&(objectClass=posixGroup)(memberUid=%s))'
'DefaultRole' => '',
'GroupEnable' => true,
'GroupOverUser' => true,
'Version' => $option_version_plugin,
'DoNotOverwriteNonLdapUsers' => false,
];
// check if we got a version
if (!isset($options['Version'])) {
// we just changed to the new option format
// read old options, then delete them
$old_option_new_option = [
'authLDAP' => 'Enabled',
'authLDAPCachePW' => 'CachePW',
'authLDAPURI' => 'URI',
'authLDAPFilter' => 'Filter',
'authLDAPNameAttr' => 'NameAttr',
'authLDAPSecName' => 'SecName',
'authLDAPUidAttr' => 'UidAttr',
'authLDAPMailAttr' => 'MailAttr',
'authLDAPWebAttr' => 'WebAttr',
'authLDAPGroups' => 'Groups',
'authLDAPDebug' => 'Debug',
'authLDAPGroupAttr' => 'GroupAttr',
'authLDAPGroupFilter' => 'GroupFilter',
'authLDAPDefaultRole' => 'DefaultRole',
'authLDAPGroupEnable' => 'GroupEnable',
'authLDAPGroupOverUser' => 'GroupOverUser',
];
foreach ($old_option_new_option as $old_option => $new_option) {
$value = get_option($old_option, null);
if (!is_null($value)) {
$options[$new_option] = $value;
}
delete_option($old_option);
}
delete_option('authLDAPCookieMarker');
delete_option('authLDAPCookierMarker');
}
// set default for all options that are missing
foreach ($options_default as $key => $default) {
if (!isset($options[$key])) {
$options[$key] = $default;
}
}
// set new version and save
$options['Version'] = $option_version_plugin;
update_option('authLDAPOptions', $options);
}
return $options;
}
/**
* Get an individual option
*/
function authLdap_get_option($optionname, $default = null)
{
$options = authLdap_load_options();
if (isset($options[$optionname]) && $options[$optionname]) {
return $options[$optionname];
}
if (null !== $default) {
return $default;
}
//authLdap_debug('option name invalid: ' . $optionname);
return null;
}
/**
* Set new options
*/
function authLdap_set_options($new_options = [])
{
// initialize the options with what we currently have
$options = authLdap_load_options();
// set the new options supplied
foreach ($new_options as $key => $value) {
$options[$key] = $value;
}
// store options
$optionFunction = 'update_option';
if (is_multisite()) {
$optionFunction = 'update_site_option';
}
if ($optionFunction('authLDAPOptions', $options)) {
// reload the option cache
authLdap_load_options(true);
return true;
}
// could not set options
return false;
}
/**
* Do not send an email after changing the password or the email of the user!
*
* @param boolean $result The initial resturn value
* @param array $user The old userdata
* @param array $newUserData The changed userdata
*
* @return bool
*/
function authLdap_send_change_email($result, $user, $newUserData)
{
if (get_user_meta($user['ID'], 'authLDAP')) {
return false;
}
return $result;
}
$hook = is_multisite() ? 'network_' : '';
add_action($hook . 'admin_menu', 'authLdap_addmenu');
add_filter('show_password_fields', 'authLdap_show_password_fields', 10, 2);
add_filter('allow_password_reset', 'authLdap_allow_password_reset', 10, 2);
add_filter('authenticate', 'authLdap_login', 10, 3);
/** This only works from WP 4.3.0 on */
add_filter('send_password_change_email', 'authLdap_send_change_email', 10, 3);
add_filter('send_email_change_email', 'authLdap_send_change_email', 10, 3);
$handler = new UserRoleHandler();
add_action('authldap_user_roles', [$handler, 'addRolesToUser'], 10, 2);

View File

@ -1,289 +0,0 @@
<?php
declare(strict_types=1);
use Behat\Behat\Tester\Exception\PendingException;
use Behat\Behat\Context\Context;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Psr7\Response;
use Org_Heigl\AuthLdap\OptionFactory;
use Org_Heigl\AuthLdap\Options;
use Webmozart\Assert\Assert;
class FeatureContext implements Context
{
private ?Response $res = null;
/**
* Initializes context.
*
* Every scenario gets its own context instance.
* You can also pass arbitrary arguments to the
* context constructor through behat.yml.
*/
public function __construct()
{
exec('wp --allow-root core install --url=localhost --title=Example --admin_user=localadmin --admin_password=P@ssw0rd --admin_email=info@example.com');
exec('wp --allow-root plugin activate authldap');
}
/**
* @Given a default configuration
*/
public function aDefaultConfiguration()
{
$options = new Options();
$options->set(Options::URI, 'ldap://cn=admin,dc=example,dc=org:insecure@openldap:389/dc=example,dc=org');
$options->set(Options::ENABLED, true);
$options->set(Options::FILTER, 'uid=%1$s');
$options->set(Options::DEFAULT_ROLE, 'subscriber');
$options->set(Options::DEBUG, true);
$options->set(Options::NAME_ATTR, 'cn');
exec(sprintf(
'wp --allow-root option update --format=json authLDAPOptions \'%1$s\'',
json_encode($options->toArray())
));
}
/**
* @Given configuration value :arg1 is set to :arg2
*/
public function configurationValueIsSetTo($arg1, $arg2)
{
exec(sprintf(
'wp --allow-root option patch update authLDAPOptions %1$s %2$s --format=json',
$arg1,
"'" . json_encode($arg2) . "'"
));
}
/**
* @Given an LDAP user :arg1 with name :arg2, password :arg3 and email :arg4 exists
*/
public function anLdapUserWithNamePasswordAndEmailExists($arg1, $arg2, $arg3, $arg4)
{
exec(sprintf(
'ldapadd -x -H %1$s -D "%2$s" -w %3$s <<LDIF
%4$s
LDIF',
'ldap://openldap',
'cn=admin,dc=example,dc=org',
'insecure',
<<<LDIF
dn: uid=$arg1,dc=example,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: simpleSecurityObject
uid: $arg1
cn: $arg2
sn: $arg2
userPassword: $arg3
mail: $arg4
LDIF
));
exec(sprintf(
'ldappasswd -H ldap://openldap:389 -x -D "uid=admin,dc=example,dc=org" -w "%3$s" -s "%2$s" "uid=%1$s,dc=example,dc=org"',
$arg1,
$arg3,
'insecure'
));
}
/**
* @Given an LDAP group :arg1 exists
*/
public function anLdapGroupExists($arg1)
{
exec(sprintf(
'ldapadd -x -H %1$s -D "%2$s" -w %3$s <<LDIF
%4$s
LDIF',
'ldap://openldap',
'cn=admin,dc=example,dc=org',
'insecure',
<<<LDIF
dn: cn=$arg1,dc=example,dc=org
objectClass: groupOfUniqueNames
cn: $arg1
uniqueMember: cn=admin,dc=example,dc=org
LDIF
));
}
/**
* @Given a WordPress user :arg1 with name :arg2 and email :arg3 exists
*/
public function aWordpressUserWithNameAndEmailExists($arg1, $arg2, $arg3)
{
exec(sprintf(
'wp --allow-root user create %1$s %3$s --display_name=%2$s --porcelain',
$arg1,
$arg2,
$arg3
));
}
/**
* @Given a WordPress role :arg1 exists
*/
public function aWordpressRoleExists($arg1)
{
exec(sprintf(
'wp --allow-root role create %1$s %1$s',
$arg1,
));
}
/**
* @Given WordPress user :arg1 has role :arg2
*/
public function wordpressUserHasRole($arg1, $arg2)
{
exec(sprintf(
'wp --allow-root user add-role %1$s %2$s',
$arg1,
$arg2
));
}
/**
* @When LDAP user :arg1 logs in with password :arg2
*/
public function ldapUserLogsInWithPassword($arg1, $arg2)
{
// curl -i 'http://localhost/wp-login.php' -X POST -H 'Cookie: wordpress_test_cookie=test' --data-raw 'log=localadmin&pwd=P%40ssw0rd'
$client = new Client();
$this->res = $client->post('http://wp/wp-login.php', [
'cookies' => CookieJar::fromArray([
'wordpress_test_cookie' => 'test',
'XDEBUG_SESSION' => 'PHPSTORM',
], 'http://wp'),
'form_params' => [
'log' => $arg1,
'pwd' => $arg2,
],
'allow_redirects' => false
]);
}
/**
* @Then the login suceeds
*/
public function theLoginSuceeds()
{
Assert::isInstanceOf($this->res, Response::class);
Assert::eq( $this->res->getStatusCode(), 302);
Assert::startsWith($this->res->getHeader('Location')[0], 'http://localhost/wp-admin');
}
/**
* @Then a new WordPress user :arg1 was created with name :arg2 and email :arg3
*/
public function aNewWordpressUserWasCreatedWithNameAndEmail($arg1, $arg2, $arg3)
{
exec(sprintf(
'wp --allow-root user get %1$s --format=json 2> /dev/null',
$arg1,
), $output, $result);
Assert::eq(0, $result);
$user = json_decode($output[0], true);
Assert::eq($user['user_email'], $arg3);
Assert::eq($user['display_name'], $arg2);
Assert::greaterThan(
new DateTimeImmutable($user['user_registered']),
(new DateTimeImmutable())->sub(new DateInterval('PT1M')),
);
}
/**
* @Then the WordPress user :arg1 is member of role :arg2
*/
public function theWordpressUserIsMemberOfRole($arg1, $arg2)
{
exec(sprintf(
'wp --allow-root user get %1$s --format=json 2> /dev/null',
$arg1,
), $output, $result);
Assert::eq(0, $result);
$user = json_decode($output[0], true);
$roles = array_map(function($item): string {
return trim($item);
}, explode(',', $user['roles']));
Assert::inArray($arg2, $roles);
}
/**
* @Given LDAP user :arg1 is member of LDAP group :arg2
*/
public function ldapUserIsMemberOfLdapGroup($arg1, $arg2)
{
exec(sprintf(
'ldapmodify -x -H %1$s -D "%2$s" -w %3$s 2>&1 <<LDIF
%4$s
LDIF',
'ldap://openldap',
'cn=admin,dc=example,dc=org',
'insecure',
<<<LDIF
dn: cn=$arg2,dc=example,dc=org
changetype: modify
add: uniqueMember
uniqueMember: uid=$arg1,dc=example,dc=org
LDIF
));
}
/**
* @Given a WordPress user :arg1 does not exist
*/
public function aWordpressUserDoesNotExist($arg1)
{
exec(sprintf(
'wp --allow-root user delete --yes %1$s',
$arg1,
));
}
/**
* @Given configuration value :arg1 is set to :arg2 and :arg3
*/
public function configurationValueIsSetToAnd($arg1, $arg2, $arg3)
{
$roles = [];
foreach ([$arg2, $arg3] as $arg) {
$access = explode('=', $arg);
$roles[$access[0]] = $access[1];
}
exec(sprintf(
'echo %2$s | wp --allow-root option patch update authLDAPOptions %1$s --format=json',
$arg1,
"'" . json_encode($roles) . "'"
), $result);
}
/**
* @Then the WordPress user :arg1 is not member of role :arg2
*/
public function theWordpressUserIsNotMemberOfRole($arg1, $arg2)
{
exec(sprintf(
'wp --allow-root user get %1$s --format=json 2> /dev/null',
$arg1,
), $output, $result);
Assert::eq(0, $result);
$user = json_decode($output[0], true);
$roles = array_map(function($item): string {
return trim($item);
}, explode(',', $user['roles']));
Assert::false(in_array($arg2, $roles));
}
}

View File

@ -1,63 +0,0 @@
Feature: Log in without group assignment
Scenario: Login without group assignment with
Given a default configuration
And configuration value "GroupEnable" is set to "false"
And configuration value "DefaultRole" is set to "subscriber"
And an LDAP user "ldapuser" with name "LDAP User", password "P@ssw0rd" and email "ldapuser@example.com" exists
And an LDAP group "ldapgroup" exists
And LDAP user "ldapuser" is member of LDAP group "ldapgroup"
And a WordPress user "wordpressuser" with name "WordPress_User" and email "wordpressuser@example.com" exists
And a WordPress role "wordpressrole" exists
And WordPress user "wordpressuser" has role "wordpressrole"
And a WordPress user "ldapuser" does not exist
When LDAP user "ldapuser" logs in with password "P@ssw0rd"
Then the login suceeds
And a new WordPress user "ldapuser" was created with name "LDAP User" and email "ldapuser@example.com"
And the WordPress user "ldapuser" is member of role "subscriber"
Scenario: Login with group assignment to multiple groups where only first wordpress group is used
Given a default configuration
And configuration value "GroupEnable" is set to "true"
And configuration value "DefaultRole" is set to "subscriber"
And configuration value "Groups" is set to "administrator=ldapgroup" and "editor=ldapgroup"
And configuration value "GroupAttr" is set to "cn"
And configuration value "GroupFilter" is set to "uniquemember=%dn%"
And configuration value "GroupOverUser" is set to "true"
And an LDAP user "ldapuser" with name "LDAP User", password "P@ssw0rd" and email "ldapuser@example.com" exists
And an LDAP group "ldapgroup" exists
And LDAP user "ldapuser" is member of LDAP group "ldapgroup"
And a WordPress user "wordpressuser" with name "WordPress_User" and email "wordpressuser@example.com" exists
And a WordPress role "wordpressrole" exists
And WordPress user "wordpressuser" has role "wordpressrole"
And a WordPress user "ldapuser" does not exist
When LDAP user "ldapuser" logs in with password "P@ssw0rd"
Then the login suceeds
And a new WordPress user "ldapuser" was created with name "LDAP User" and email "ldapuser@example.com"
And the WordPress user "ldapuser" is member of role "administrator"
And the WordPress user "ldapuser" is not member of role "editor"
And the WordPress user "ldapuser" is not member of role "subscriber"
Scenario: Second Login with group assignment to multiple groups where only first wordpress group is used.
Given a default configuration
And configuration value "GroupEnable" is set to "true"
And configuration value "DefaultRole" is set to "subscriber"
And configuration value "Groups" is set to "administrator=ldapgroup" and "editor=ldapgroup"
And configuration value "GroupAttr" is set to "cn"
And configuration value "GroupFilter" is set to "uniquemember=%dn%"
And configuration value "GroupOverUser" is set to "false"
And an LDAP user "ldapuser" with name "LDAP User", password "P@ssw0rd" and email "ldapuser@example.com" exists
And an LDAP group "ldapgroup" exists
And LDAP user "ldapuser" is member of LDAP group "ldapgroup"
And a WordPress user "wordpressuser" with name "WordPress_User" and email "wordpressuser@example.com" exists
And a WordPress role "wordpressrole" exists
And WordPress user "wordpressuser" has role "wordpressrole"
And a WordPress user "ldapuser" does not exist
And LDAP user "ldapuser" logs in with password "P@ssw0rd"
And WordPress user "ldapuser" has role "wordpressrole"
And the WordPress user "ldapuser" is member of role "wordpressrole"
When LDAP user "ldapuser" logs in with password "P@ssw0rd"
Then the login suceeds
And the WordPress user "ldapuser" is member of role "administrator"
And the WordPress user "ldapuser" is member of role "wordpressrole"
And the WordPress user "ldapuser" is not member of role "editor"
And the WordPress user "ldapuser" is not member of role "subscriber"

View File

@ -1,22 +0,0 @@
<?xml version="1.0"?>
<ruleset name="Custom Standard" namespace="MyProject\CS\Standard">
<description>authLdap codestyle</description>
<file>./src</file>
<file>./authLdap.php</file>
<file>./tests</file>
<arg name="colors"/>
<arg value="sp"/>
<autoload>./vendor/autoload.php</autoload>
<rule ref="PSR12">
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
</rule>
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="tabIndent" value="true"/>
</properties>
</rule>
</ruleset>

View File

@ -1,166 +0,0 @@
=== authLdap ===
Contributors: heiglandreas
Tags: ldap, auth, authentication, active directory, AD, openLDAP, Open Directory
Requires at least: 2.5.0
Tested up to: 6.4.0
Requires PHP: 7.4
Stable tag: trunk
License: MIT
License URI: https://opensource.org/licenses/MIT
Use your existing LDAP flexible as authentication backend for WordPress
== Description ==
Use your existing LDAP as authentication-backend for your wordpress!
So what are the differences to other Wordpress-LDAP-Authentication-Plugins?
* Flexible: You are totaly free in which LDAP-backend to use. Due to the extensive configuration you can freely decide how to do the authentication of your users. It simply depends on your filters
* Independent: As soon as a user logs in, it is added/updated to the Wordpress' user-database to allow wordpress to always use the correct data. You only have to administer your users once.
* Failsafe: Due to the users being created in Wordpress' User-database they can also log in when the LDAP-backend currently is gone.
* Role-Aware: You can map Wordpress' roles to values of an existing LDAP-attribute.
For more Information on the configuration have a look at https://github.com/heiglandreas/authLdap
== Installation ==
1. Upload the extracted folder `authLdap` to the `/wp-content/plugins/` directory
2. Activate the plugin through the 'Plugins' menu in WordPress
3. Configure the Plugin via the 'authLdap'-Configuration-Page.
== Frequently Asked Questions ==
= Where can I find more Informations about the plugin? =
Go to https://github.com/heiglandreas/authLdap
= Where can I report issues with the plugin? =
Please use the issuetracker at https://github.com/heiglandreas/authLdap/issues
= Where can I report sensitive security issues with the plugin? =
In essence: Report a security vulnerability at https://github.com/heiglandreas/authLdap/security/advisories/new
Please see https://github.com/heiglandreas/authLdap/blob/master/SECURITY.md for more details
== Changelog ==
= 2.6.0 =
* Fix reducing assigned WordPress roles to single role on login when WordPress roles shall be kept
* Add Behavioural testing and first 3 scenarios
= 2.5.9 =
* Adds information about security-contacts
* Addresses CVE-2023-41655
= 2.5.8 =
* Fix regression from 2.5.7
= 2.5.7 =
* Fix regressions from 2.5.4
* Fix CI system
= 2.5.4 =
* Update Tested up to
= 2.5.3 =
* Fix issue with broken role-assignement in combination with WooCommerce
* Fix spelling issue
* Allow DN as role-definition
= 2.5.0 =
* Ignore the order of capabilities to tell the role. In addition the filter `editable_roles` can be used to limit the roles
= 2.4.11 =
* Fix issue with running on PHP8.1
= 2.4.9 =
* Improve group-assignement UI
= 2.4.8 =
* Make textfields in settings-page wider
= 2.4.7 =
* Replace deprecated function
* Fix undefined index
* Add filter for retrieving other params at login (authLdap_filter_attributes)
* Add do_action after successfull login (authLdap_login_successful)
= 2.4.0 =
* Allow to use environment variables for LDAP-URI configuration
= 2.3.0 =
* Allow to not overwrite existing WordPress-Users with LDAP-Users as that can be a security issue.
= 2.1.0 =
* Add search-base for groups. This might come in handy for multisite-instances
= 2.0.0 =
* This new release adds Multi-Site support. It will no longer be possible to use this plugin just in one subsite of a multisite installation!
* Adds a warning screen to the config-section when no LDAPextension could be found
* Fixes an issue with the max-length of the username
= 1.5.1 =
* Fixes an issue with escaped backslashes and quotes
= 1.5.0 =
* Allows parts of the LDAP-URI to be URLEncoded
* Drops support for PHP 5.4
= 1.4.20 =
* Allows multiple LDAP-servers to be queried (given that they use the same attributes)
* Fixes issue with URL-Encoded informations (see https://github.com/heiglandreas/authLdap/issues/108)
= 1.4.19 =
* Adds support for TLS
= 1.4.14 =
* Update to showing password-fields check (thanks to @chaplina)
= 1.4.13 =
* Removed generation of default email-address (thanks to @henryk)
* Fixes password-hashing when caching passwords (thanks to @litinoveweedle)
* Removes the possibility to reset a password for LDAP-based users (thanks to @chaplina)
* Removes the password-change-Email from 4.3 on (thanks to @litinoveweedle)
* Fixes double authentication-attempt (that resulted in failed authentication) (thanks to @litinoveweedle)
= 1.4.10 =
* Cleanup by removing deprecated code
* Fixes issues with undefined variables
* Enables internal option-versioning
* Setting users nickname initially to the realname instead of the uid
* Fixes display of password-change possibility in users profile-page
= 1.4.9 =
* Fixed an issue with changing display name on every login
* Use proper way of looking up user-roles in setups w/o DB-prefix
= 1.4.8 =
* Updated version string
= 1.4.7 =
* Use default user to retrieve group menberships and not logging in user.
* return the UID from the LDAP instead of the value given by the user
* remove unnecessary checkbox
* Adds a testsuite
* Fixes PSR2 violations
[…]
= 1.2.1 =
* Fixed an issue with group-ids
* Moved the code to GitHub (https://github.com/heiglandreas/authLdap)
= 1.1.0 =
* Changed the login-process. Now users that are not allowed to login due to
missing group-memberships are not created within your blog as was the standard
until Version 1.0.3 - Thanks to alex@tayts.com
* Changed the default mail-address that is created when no mail-address can be
retrieved from the LDAP from me@example.com to $username@example.com so that
a new user can be created even though the mail address already exists in your
blog - Also thanks to alex@tayts.com
* Added support for WordPress-Table-prefixes as the capabilities of a user
are interlany stored in a field that is named "$tablePrefix_capabilities" -
again thanks to alex@tayts.com and also to sim0n of silicium.mine.nu

View File

@ -1,6 +0,0 @@
Contact: mailto://andreas@heigl.net
Contact: https://github.com/heiglandreas/authLdap/security/advisories/new
Expires: 2026-09-07T10:00:00.000Z
Encryption: https://andreas.heigl.org/publickey/
Encryption: https://heigl.org/.well-known/openpgpkey/hu/sfqdema7hgdj146cwzo4rxgsoujxis31
Preferred-Languages: en,de

View File

@ -1,24 +0,0 @@
<?php
/**
* Copyright Andrea Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Exception;
use Exception;
class Error extends Exception
{
public function __construct($message, $line = null)
{
parent::__construct($message);
if ($line) {
$this -> line = $line;
}
}
}

View File

@ -1,74 +0,0 @@
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Exception;
use RuntimeException;
use function sprintf;
class InvalidLdapUri extends RuntimeException
{
public static function cannotparse(string $ldapUri): self
{
return new self(sprintf(
'%1$s seems not to be a valid URI',
$ldapUri
));
}
public static function wrongSchema(string $uri): self
{
return new self(sprintf(
'%1$s does not start with a valid schema',
$uri
));
}
public static function noSchema(string $uri): self
{
return new self(sprintf(
'%1$s does not provide a schema',
$uri
));
}
public static function noEnvironmentVariableSet(string $uri): self
{
return new self(sprintf(
'The environment variable %1$s does not provide a URI',
$uri
));
}
public static function noServerProvided(string $uri): self
{
return new self(sprintf(
'The LDAP-URI %1$s does not provide a server',
$uri
));
}
public static function noSearchBaseProvided(string $uri): self
{
return new self(sprintf(
'The LDAP-URI %1$s does not provide a search-base',
$uri
));
}
public static function invalidSearchBaseProvided(string $uri): self
{
return new self(sprintf(
'The LDAP-URI %1$s does not provide a valid search-base',
$uri
));
}
}

View File

@ -1,23 +0,0 @@
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Exception;
use RuntimeException;
class MissingValidLdapConnection extends Error
{
public static function get(): self
{
return new self(sprintf(
'No valid LDAP connection available'
));
}
}

View File

@ -1,24 +0,0 @@
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Exception;
use RuntimeException;
class SearchUnsuccessfull extends RuntimeException
{
public static function fromSearchFilter(string $filter): self
{
return new self(sprintf(
'Search for %1$s was not successfull',
$filter
));
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licensed under the MIT-license. For details see the included file LICENSE.md
*/
namespace Org_Heigl\AuthLdap\Exception;
use RuntimeException;
class UnknownOption extends RuntimeException
{
public static function withKey(string $key): self
{
return new self(sprintf(
'An option "%1$s" is not known',
$key
));
}
}

View File

@ -1,93 +0,0 @@
<?php
/**
* Copyright (c) Andreas Heigl<andreas@heigl.org>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author Andreas Heigl<andreas@heigl.org>
* @copyright Andreas Heigl
* @license http://www.opensource.org/licenses/mit-license.php MIT-License
* @since 07.07.2016
* @link http://github.com/heiglandreas/authLDAP
*/
namespace Org_Heigl\AuthLdap;
use Exception;
use Org_Heigl\AuthLdap\Exception\Error;
use Org_Heigl\AuthLdap\Exception\SearchUnsuccessfull;
use Org_Heigl\AuthLdap\Manager\Ldap;
class LdapList
{
/**
* @var Ldap[]
*/
protected $items = [];
public function addLdap(Ldap $ldap)
{
$this->items[] = $ldap;
}
public function authenticate($username, $password, $filter = '(uid=%s)')
{
/** @var Ldap $item */
foreach ($this->items as $key => $item) {
if (! $item->authenticate($username, $password, $filter)) {
unset($this->items[$key]);
continue;
}
return true;
}
return false;
}
public function bind()
{
$allFailed = true;
foreach ($this->items as $key => $item) {
try {
$item->bind();
} catch (\Exception $e) {
unset($this->items[$key]);
continue;
}
$allFailed = false;
}
if ($allFailed) {
throw new Error('No bind successfull');
}
return true;
}
public function search($filter, $attributes = array('uid'), $base = '')
{
foreach ($this->items as $item) {
try {
$result = $item->search($filter, $attributes, $base);
return $result;
} catch (Exception $e) {
}
}
throw SearchUnsuccessfull::fromSearchFilter($filter);
}
}

View File

@ -1,179 +0,0 @@
<?php
/**
* Copyright (c) Andreas Heigl<andreas@heigl.org>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author Andreas Heigl<andreas@heigl.org>
* @copyright Andreas Heigl
* @license http://www.opensource.org/licenses/mit-license.php MIT-License
* @since 19.07.2020
* @link http://github.com/heiglandreas/authLDAP
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap;
use Org_Heigl\AuthLdap\Exception\InvalidLdapUri;
use function array_map;
use function error_get_last;
use function getenv;
use function is_array;
use function is_string;
use function parse_url;
use function preg_replace_callback;
use function rawurlencode;
use function strlen;
use function strpos;
use function substr;
use function trim;
use function urldecode;
final class LdapUri
{
private $server;
private $scheme;
private $port = 389;
private string $baseDn;
private $username = '';
private $password = '';
private function __construct(string $uri)
{
if (!preg_match('/^(ldap|ldaps|env)/', $uri)) {
throw InvalidLdapUri::wrongSchema($uri);
}
if (strpos($uri, 'env:') === 0) {
$newUri = getenv(substr($uri, 4));
if (false === $newUri) {
throw InvalidLdapUri::noEnvironmentVariableSet($uri);
}
$uri = (string) $newUri;
}
$uri = $this->injectEnvironmentVariables($uri);
$array = parse_url($uri);
if (!is_array($array)) {
throw InvalidLdapUri::cannotparse($uri);
}
$url = array_map(static function ($item) {
if (is_int($item)) {
return $item;
}
return urldecode($item);
}, $array);
if (!isset($url['scheme'])) {
throw InvalidLdapUri::noSchema($uri);
}
if (0 !== strpos($url['scheme'], 'ldap')) {
throw InvalidLdapUri::wrongSchema($uri);
}
if (!isset($url['host'])) {
throw InvalidLdapUri::noServerProvided($uri);
}
if (!isset($url['path'])) {
throw InvalidLdapUri::noSearchBaseProvided($uri);
}
if (1 === strlen($url['path'])) {
throw InvalidLdapUri::invalidSearchBaseProvided($uri);
}
$this->server = $url['host'];
$this->scheme = $url['scheme'];
$this->baseDn = substr($url['path'], 1);
if (isset($url['user'])) {
$this->username = $url['user'];
}
if ('' === trim($this->username)) {
$this->username = 'anonymous';
}
if (isset($url['pass'])) {
$this->password = $url['pass'];
}
if ($this->scheme === 'ldaps' && $this->port === 389) {
$this->port = 636;
}
// When someone sets the port in the URL we overwrite whatever is set.
// We have to assume they know what they are doing!
if (isset($url['port'])) {
$this->port = $url['port'];
}
}
public static function fromString(string $uri): LdapUri
{
return new LdapUri($uri);
}
private function injectEnvironmentVariables(string $base): string
{
return preg_replace_callback('/%env:([^%]+)%/', static function (array $matches) {
return rawurlencode(getenv($matches[1]));
}, $base);
}
public function toString(): string
{
return $this->scheme . '://' . $this->server . ':' . $this->port;
}
public function __toString()
{
return $this->toString();
}
public function getUsername(): string
{
return $this->username;
}
public function getPassword(): string
{
return $this->password;
}
public function getBaseDn(): string
{
return $this->baseDn;
}
public function isAnonymous(): bool
{
if ($this->password === '') {
return true;
}
if ($this->username === 'anonymous') {
return true;
}
return false;
}
}

View File

@ -1,164 +0,0 @@
<?php
/**
* $Id: ldap.php 381646 2011-05-06 09:37:31Z heiglandreas $
*
* authLdap - Authenticate Wordpress against an LDAP-Backend.
* Copyright (c) 2008 Andreas Heigl<andreas@heigl.org>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* This file handles the basic LDAP-Tasks
*
* @author Andreas Heigl<andreas@heigl.org>
* @package authLdap
* @category authLdap
* @since 2008
*/
namespace Org_Heigl\AuthLdap\Manager;
use Org_Heigl\AuthLdap\Exception\Error;
use Org_Heigl\AuthLdap\Exception\MissingValidLdapConnection;
use Org_Heigl\AuthLdap\LdapUri;
use Org_Heigl\AuthLdap\Wrapper\LdapFactory;
use Org_Heigl\AuthLdap\Wrapper\LdapInterface;
class Ldap
{
/**
* This property contains the connection handle to the ldap-server
*
* @var LdapInterface|null
*/
private ?LdapInterface $connection;
private LdapUri $uri;
private LdapFactory $factory;
private $starttls;
public function __construct(LdapFactory $factory, LdapUri $uri, $starttls = false)
{
$this->starttls = $starttls;
$this->uri = $uri;
$this->factory = $factory;
$this->connection = null;
}
/**
* Connect to the given LDAP-Server
*/
public function connect(): self
{
$this->disconnect();
$this->connection = $this->factory->createFromLdapUri($this->uri->toString());
$this->connection->setOption(LDAP_OPT_PROTOCOL_VERSION, 3);
$this->connection->setOption(LDAP_OPT_REFERRALS, 0);
//if configured try to upgrade encryption to tls for ldap connections
if ($this->starttls) {
$this->connection->startTls();
}
return $this;
}
/**
* Disconnect from a resource if one is available
*/
public function disconnect(): self
{
if (null !== $this->connection) {
$this->connection->unbind();
}
$this->connection = null;
return $this;
}
/**
* Bind to an LDAP-Server with the given credentials
*
* @throws Error
*/
public function bind(): self
{
if (!$this->connection) {
$this->connect();
}
if (null === $this->connection) {
throw MissingValidLdapConnection::get();
}
if ($this->uri->isAnonymous()) {
$bind = $this->connection->bind();
} else {
$bind = $this->connection->bind($this->uri->getUsername(), $this->uri->getPassword());
}
if (!$bind) {
throw new Error('bind was not successfull: ' . $this->connection->error());
}
return $this;
}
/**
* This method does the actual ldap-serch.
*
* This is using the filter <var>$filter</var> for retrieving the attributes
* <var>$attributes</var>
*
* @return array<string|int, mixed>
* @throws Error
*/
public function search(string $filter, array $attributes = ['uid'], ?string $base = ''): array
{
if (null === $this->connection) {
throw new Error('No resource handle available');
}
if (!$base) {
$base = $this->uri->getBaseDn();
}
$result = $this->connection->search($base, $filter, $attributes);
if ($result === false) {
throw new Error('no result found');
}
$info = $this->connection->getEntries($result);
if ($info === false) {
throw new Error('invalid results found');
}
return $info;
}
/**
* This method authenticates the user <var>$username</var> using the
* password <var>$password</var>
*
* @param string $filter OPTIONAL This parameter defines the Filter to be used
* when searchin for the username. This MUST contain the string '%s' which
* will be replaced by the vaue given in <var>$username</var>
* @throws Error
*/
public function authenticate(string $username, string $password, string $filter = '(uid=%s)'): bool
{
$this->connect();
$this->bind();
$res = $this->search(sprintf($filter, $this->factory->escape($username, '', LDAP_ESCAPE_FILTER)));
if ($res ['count'] !== 1) {
return false;
}
$dn = $res[0]['dn'];
return $username && $password && $this->connection->bind($dn, $password);
}
}

View File

@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licensed under the MIT-license. For details see the included file LICENSE.md
*/
namespace Org_Heigl\AuthLdap;
use function json_decode;
class OptionFactory
{
public function fromJson(string $json): Options
{
$option = new Options();
$content = json_decode($json, true);
foreach ($content as $key => $value) {
$option->set($key, $value);
}
return $option;
}
}

View File

@ -1,90 +0,0 @@
<?php
declare(strict_types=1);
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licensed under the MIT-license. For details see the included file LICENSE.md
*/
namespace Org_Heigl\AuthLdap;
use Org_Heigl\AuthLdap\Exception\UnknownOption;
use function array_key_exists;
class Options
{
public const ENABLED = 'Enabled';
public const CACHE_PW = 'CachePW';
public const URI = 'URI';
public const URI_SEPARATOR = 'URISeparator';
public const FILTER = 'Filter';
public const NAME_ATTR = 'NameAttr';
public const SEC_NAME = 'SecName';
public const UID_ATTR = 'UidAttr';
public const MAIL_ATTR = 'MailAttr';
public const WEB_ATTR = 'WebAttr';
public const GROUPS = 'Groups';
public const DEBUG = 'Debug';
public const GROUP_ATTR = 'GroupAttr';
public const GROUP_FILTER = 'GroupFilter';
public const DEFAULT_ROLE = 'DefaultRole';
public const GROUP_ENABLE = 'GroupEnable';
public const GROUP_OVER_USER = 'GroupOverUser';
public const VERSION = 'Version';
public const DO_NOT_OVERWRITE_NON_LDAP_USERS = 'DoNotOverwriteNonLdapUsers';
private array $settings = [
'Enabled' => false,
'CachePW' => false,
'URI' => '',
'URISeparator' => ' ',
'Filter' => '', // '(uid=%s)'
'NameAttr' => '', // 'name'
'SecName' => '',
'UidAttr' => '', // 'uid'
'MailAttr' => '', // 'mail'
'WebAttr' => '',
'Groups' => [],
'Debug' => false,
'GroupAttr' => '', // 'gidNumber'
'GroupFilter' => '', // '(&(objectClass=posixGroup)(memberUid=%s))'
'DefaultRole' => '',
'GroupEnable' => true,
'GroupOverUser' => true,
'Version' => 1,
'DoNotOverwriteNonLdapUsers' => false,
];
public function get(string $key)
{
if (! array_key_exists($key, $this->settings)) {
throw UnknownOption::withKey($key);
}
return $this->settings[$key];
}
public function has(string $key): bool
{
return array_key_exists($key, $this->settings);
}
/**
* @param mixed $value
*/
public function set(string $key, $value): void
{
if (! array_key_exists($key, $this->settings)) {
throw UnknownOption::withKey($key);
}
$this->settings[$key] = $value;
}
public function toArray(): array
{
return $this->settings;
}
}

View File

@ -1,54 +0,0 @@
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap;
use WP_User;
use function array_search;
use function in_array;
use function var_dump;
class UserRoleHandler
{
/**
* @param WP_User $user
* @param string[] $roles
* @return void
*/
public function addRolesToUser(WP_User $user, $roles) : void
{
if ($roles === []) {
return;
}
if ($user->roles == $roles) {
return;
}
// Remove unused roles from existing.
foreach ($user->roles as $role) {
if (!in_array($role, $roles)) {
// Remove unused roles.
$user->remove_role($role);
continue;
}
// Remove the existing role from roles.
if (($key = array_search($role, $roles)) !== false) {
unset($roles[$key]);
}
}
// Add new ones if not already assigned.
foreach ($roles as $role) {
$user->add_role($role);
}
}
}

View File

@ -1,93 +0,0 @@
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Wrapper;
use function ldap_bind;
use function ldap_connect;
use function ldap_error;
use function ldap_escape;
use function ldap_get_entries;
use function ldap_set_option;
use function ldap_start_tls;
use function ldap_unbind;
use function var_dump;
final class Ldap implements LdapInterface
{
private $connection;
public function __construct(string $ldapUri)
{
$this->connection = ldap_connect($ldapUri);
}
public function bind($dn = null, $password = null)
{
if (null === $dn && null === $password) {
return ldap_bind($this->connection);
}
return ldap_bind($this->connection, $dn, $password);
}
public function unbind()
{
return ldap_unbind($this->connection);
}
public function setOption($option, $value)
{
return ldap_set_option($this->connection, $option, $value);
}
public function startTls()
{
return ldap_start_tls($this->connection);
}
public function error()
{
return ldap_error($this->connection);
}
public function errno()
{
return ldap_errno($this->connection);
}
public function search(
$base,
$filter,
array $attributes = [],
$attributes_only = 0,
$sizelimit = -1,
$timelimit = -1
) {
return ldap_search(
$this->connection,
$base,
$filter,
$attributes,
$attributes_only,
$sizelimit,
$timelimit
);
}
public function getEntries($search_result)
{
return ldap_get_entries($this->connection, $search_result);
}
public static function escape(string $value, string $ignore = '', int $flags = 0): string
{
return ldap_escape($value, $ignore, $flags);
}
}

View File

@ -1,24 +0,0 @@
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Wrapper;
class LdapFactory
{
public function createFromLdapUri(string $ldapUri): LdapInterface
{
return new Ldap($ldapUri);
}
public function escape($value, $ignore = '', $flags = 0): string
{
return Ldap::escape($value, $ignore, $flags);
}
}

View File

@ -1,39 +0,0 @@
<?php
/**
* Copyright Andreas Heigl <andreas@heigl.org>
*
* Licenses under the MIT-license. For details see the included file LICENSE.md
*/
declare(strict_types=1);
namespace Org_Heigl\AuthLdap\Wrapper;
interface LdapInterface
{
public function bind($dn = null, $password = null);
public function unbind();
public function setOption($option, $value);
public function startTls();
public function error();
public function errno();
public function search(
$base,
$filter,
array $attributes = [],
$attributes_only = 0,
$sizelimit = -1,
$timelimit = -1
);
public function getEntries($search_result);
public static function escape(string $value, string $ignore = '', int $flags = 0): string;
}

View File

@ -1,454 +0,0 @@
<?php
/**
* Copyright (c)2014-2014 heiglandreas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIBILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category
* @author Andreas Heigl<andreas@heigl.org>
* @copyright ©2014-2014 Andreas Heigl
* @license http://www.opesource.org/licenses/mit-license.php MIT-License
* @version 0.0
* @since 19.12.14
* @link https://github.com/heiglandreas/authLdap
*/
?><div class="wrap">
<?php if (! extension_loaded('ldap')) : ?>
<div class="error"><strong>Caveat:</strong> The LDAP-extension is not loaded!
Without that extension it is not possible to query an LDAP-Server! Please have a look
at <a href="http://php.net/manual/install.php">the PHP-Installation page</a>
</div>
<?php endif ?>
<h2>AuthLDAP Options</h2>
<form class="authldap-options" method="post" id="authLDAP_options" action="<?php echo $action;?>">
<input name="authLdapNonce" type="hidden" value="<?php echo wp_create_nonce('authLdapNonce'); ?>" />
<h3 class="title">General Usage of authLDAP</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th>
<label for="authLDAPAuth">Enable Authentication via LDAP?</label>
</th>
<td>
<input type="checkbox" name="authLDAPAuth" id="authLDAPAuth" value="1"<?php echo $tChecked; ?>/>
</td>
</tr>
<tr>
<th>
<label for="authLDAPDebug">Debug AuthLDAP?</label>
</th>
<td>
<input type="checkbox" name="authLDAPDebug" id="authLDAPDebug" value="1"<?php echo $tDebugChecked; ?>/>
</td>
</tr>
<tr>
<th>
<label for="authLDAPDoNotOverwriteNonLdapUsers">Do not authenticate existing WordPress-Users</label>
</th>
<td>
<input type="checkbox" name="authLDAPDoNotOverwriteNonLdapUsers" id="authLDAPDoNotOverwriteNonLdapUsers" value="1"<?php echo $tDoNotOverwriteNonLdapUsers; ?>/>
<p class="description">
Shall we prohibit authenticating already in WordPress created users using LDAP? If you enable this, LDAP-Users with the same user-ID
as existing WordPress-Users can no longer take over the WordPress-Users account. This also means that LDAP-Users with the same User-ID as existing
WordPress-Users will <strong>not</strong> be able to authenticate anymore! Accounts that have been taken over already will not be affected by this setting.
</p>
<p class="description">This should only be checked if you know what you are doing!</p>
</td>
</tr>
<tr>
<th>
<label for="authLDAPCachePW">Save entered passwords in the wordpress user table?</label>
</th>
<td>
<input type="checkbox" name="authLDAPCachePW" id="authLDAPCachePW" value="1"<?php echo $tPWChecked; ?>/>
</td>
</tr>
<tr>
<th>
<label for="authLDAPGroupEnable">Map LDAP Groups to wordpress Roles?</label>
</th>
<td>
<input type="checkbox" name="authLDAPGroupEnable" id="authLDAPGroupEnable" value="1"<?php echo $tGroupChecked; ?>/>
<p class="description">
Search LDAP for user's groups and map to Wordpress Roles.
</p>
</td>
</tr>
</table>
</fieldset>
<h3 class="title">General Server Settings</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th>
<label for="authLDAPURI">LDAP URI</label>
</th>
<td>
<input type="text" name="authLDAPURI" id="authLDAPURI" placeholder="LDAP-URI"
class="regular-text" value="<?php echo $authLDAPURI; ?>"/>
<p class="description">
The <abbr title="Uniform Ressource Identifier">URI</abbr>
for connecting to the LDAP-Server. This usualy takes the form
<var>&lt;scheme&gt;://&lt;user&gt;:&lt;password&gt;@&lt;server&gt;/&lt;path&gt;</var>
according to RFC 1738.</p>
<p class="description">
In this case it schould be something like
<var>ldap://uid=adminuser,dc=example,c=com:secret@ldap.example.com/dc=basePath,dc=example,c=com</var>.
</p>
<p class="description">
If your LDAP accepts anonymous login, you can ommit the user and
password-Part of the URI
</p>
<p class="description">
You can use the pseudo-schema <em>env</em> to provide your LDAP-URI from an environment-variable. So if you have your
LDAP-URI in a variable called <code>LDAP_URI</code> you can enter <code>env:LDAP_URI</code> in this field and at runtime the
appropriate value will be taken from the Environment-variable <code>LDAP_URI</code>. If the varialbe is not set, then the value will be empty.
</p>
<p class="description">
You can also provide different parts of the LDP-URI from environment variables by providing
<code>%env:[VARIABLENAME]%</code> within your LDAP-URI. So if you want to provide the
password from an Environment-variable <code>LDAP_PASSWORD</code> your LDAP-URI looks like
<code>ldap://uid=adminuser,dc=example,c=com:%env:LDAP_PASSWORD%@ldap.example.com/dc=basePath,dc=example,c=com</code>
</p>
<p class="description">
<strong>Caveat!</strong><br/>
If you are using Environment-variables for parts of the LDAP-URL then those <strong>must not</strong> be URL-Encoded!<br/>
Otherwise the different parts <strong>must</strong> be URL-Encoded!
</p>
</td>
</tr>
<tr>
<th>
<label for="authLDAPURISeparator">LDAP URI-Separator</label>
</th>
<td>
<input type="text" name="authLDAPURISeparator" id="authLDAPURISeparator" placeholder="LDAP-URI Separator"
class="regular-text" value="<?php echo $authLDAPURISeparator; ?>"/>
<p class="description">
A separator that separates multiple LDAP-URIs from one another.
You can use that feature to try to authenticate against multiple LDAP-Servers
as long as they all have the same attribute-settings. The first LDAP-Server the user can
authenticate against will be used to handle the user.
</td>
</tr>
<tr>
<th>
<label for="authLDAPStartTLS" class="description">StartTLS</label>
</th>
<td>
<input type="checkbox" name="authLDAPStartTLS" id="authLDAPStartTLS" value="1"<?php echo $tStartTLSChecked; ?>/>
<p class="description">
Use StartTLS for encryption of ldap connections. This setting is not to be used in combination with ldaps connections (ldap:// only).
</p>
</td>
<tr>
<th scope="row">
<label for="authLDAPFilter" class="description">Filter</label>
</th>
<td>
<input type="text" name="authLDAPFilter" id="authLDAPFilter" placeholder="(uid=%s)"
class="regular-text" value="<?php echo $authLDAPFilter; ?>"/>
<p class="description">
Please provide a valid filter that can be used for querying the
<abbr title="Lightweight Directory Access Protocol">LDAP</abbr>
for the correct user. For more information on this
feature have a look at <a href="http://andreas.heigl.org/cat/dev/wp/authldap">http://andreas.heigl.org/cat/dev/wp/authldap</a>
</p>
<p class="description">
This field <strong>should</strong> include the string <code>%s</code>
that will be replaced with the username provided during log-in
</p>
<p class="description">
If you leave this field empty it defaults to <strong>(uid=%s)</strong>
</p>
</td>
</tr>
</table>
</fieldset>
<h3 class="title">Settings for creating new Users</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th scope="row">
<label for="authLDAPUseUserAccount">User-Read</label>
</th>
<td>
<input type="checkbox" name="authLDAPUseUserAccount" id="authLDAPUseUserAccount" value="1"<?php echo $tUserRead; ?>/><br />
<p class="description">
If checked the plugin will use the user's account to query their own information. If not it will use the admin account.
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPNameAttr">Name-Attribute</label>
</th>
<td>
<input type="text" name="authLDAPNameAttr" id="authLDAPNameAttr" placeholder="name"
class="regular-text" value="<?php echo $authLDAPNameAttr; ?>"/><br />
<p class="description">
Which Attribute from the LDAP contains the Full or the First name
of the user trying to log in.
</p>
<p class="description">
This defaults to <strong>name</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPSecName">Second Name Attribute</label>
</th>
<td>
<input type="text" name="authLDAPSecName" id="authLDAPSecName" placeholder=""
class="regular-text" value="<?php echo $authLDAPSecName; ?>" />
<p class="description">
If the above Name-Attribute only contains the First Name of the
user you can here specify an Attribute that contains the second name.
</p>
<p class="description">
This field is empty by default
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPUidAttr">User-ID Attribute</label>
</th>
<td>
<input type="text" name="authLDAPUidAttr" id="authLDAPUidAttr" placeholder="uid"
class="regular-text" value="<?php echo $authLDAPUidAttr; ?>" />
<p class="description">
Please give the Attribute, that is used to identify the user. This
should be the same as you used in the above <em>Filter</em>-Option
</p>
<p class="description">
This field defaults to <strong>uid</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPMailAttr">Mail Attribute</label>
</th>
<td>
<input type="text" name="authLDAPMailAttr" id="authLDAPMailAttr" placeholder="mail"
class="regular-text" value="<?php echo $authLDAPMailAttr; ?>" />
<p class="description">
Which Attribute holds the eMail-Address of the user?
</p>
<p class="description">
If more than one eMail-Address are stored in the LDAP, only the first given is used
</p>
<p class="description">
This field defaults to <strong>mail</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPWebAttr">Web-Attribute</label>
</th>
<td>
<input type="text" name="authLDAPWebAttr" id="authLDAPWebAttr" placeholder=""
class="regular-text" value="<?php echo $authLDAPWebAttr; ?>" />
<p class="description">
If your users have a personal page (URI) stored in the LDAP, it can
be provided here.
</p>
<p class="description">
This field is empty by default
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPDefaultRole">Default Role</label>
</th>
<td>
<select name="authLDAPDefaultRole" id="authLDAPDefaultRole">
<option value="" <?php echo ( $authLDAPDefaultRole == '' ? 'selected="selected"' : '' ); ?>>
None (deny access)
</option>
<?php foreach ($roles->get_names() as $group => $vals) : ?>
<option value="<?php echo $group; ?>" <?php echo ( $authLDAPDefaultRole == $group ? 'selected="selected"' : '' ); ?>>
<?php echo $vals; ?>
</option>
<?php endforeach; ?>
</select>
<p class="description">
Here you can select the default role for users.
If you enable LDAP Groups below, they will take precedence over the Default Role.
</p>
<p class="description">
Existing users will retain their roles unless overriden by LDAP Groups below.
</p>
</td>
</tr>
</table>
</fieldset>
<div id="authldaprolemapping">
<h3 class="title">Groups for Roles</h3>
<fieldset class="options">
<table class="form-table">
<tr>
<th>
<label for="authLDAPGroupOverUser">LDAP Groups override role of existing users?</label>
</th>
<td>
<input type="checkbox" name="authLDAPGroupOverUser" id="authLDAPGroupOverUser" value="1"<?php echo $tGroupOverUserChecked; ?>/>
<p class="description">
If role determined by LDAP Group differs from existing Wordpress User's role, use LDAP Group.
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupBase">Group-Base</label>
</th>
<td>
<input type="text" name="authLDAPGroupBase" id="authLDAPGroupBase" placeholder=""
class="regular-text" value="<?php echo $authLDAPGroupBase; ?>" />
<p class="description">
This is the base dn to lookup groups.
</p>
<p class="description">
If empty the base dn of the LDAP URI will be used
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupAttr">Group-Attribute</label>
</th>
<td>
<input type="text" name="authLDAPGroupAttr" id="authLDAPGroupAttr" placeholder="gidNumber"
class="regular-text" value="<?php echo $authLDAPGroupAttr; ?>" />
<p class="description">
This is the attribute that defines the Group-ID that can be matched
against the Groups defined further down
</p>
<p class="description">
This field defaults to <strong>gidNumber</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupSeparator">Group-Separator</label>
</th>
<td>
<input type="text" name="authLDAPGroupSeparator" id="authLDAPGroupSeparator" placeholder=","
class="regular-text" value="<?php echo $authLDAPGroupSeparator; ?>" />
<p class="description">
This attribute defines the separator used for the Group-IDs listed in the
Groups defined further down. This is useful if the value of Group-Attribute
listed above can contain a comma (for example, when using the memberof attribute)
</p>
<p class="description">
This field defaults to <strong>, (comma)</strong>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="authLDAPGroupFilter">Group-Filter</label>
</th>
<td>
<input type="text" name="authLDAPGroupFilter" id="authLDAPGroupFilter"
placeholder="(&amp;(objectClass=posixGroup)(memberUid=%s))"
class="regular-text" value="<?php echo $authLDAPGroupFilter; ?>" />
<p class="description">
Here you can add the filter for selecting groups for ther
currentlly logged in user
</p>
<p class="description">
The Filter should contain the string <code>%s</code> which will be replaced by
the login-name of the currently logged in user
</p>
<p class="description">
Alternatively the string <code>%dn%</code> will be replaced by the
DN of the currently logged in user. This can be helpfull if
group-memberships are defined with DNs rather than UIDs
</p>
<p class="description">This field defaults to
<strong>(&amp;(objectClass=posixGroup)(memberUid=%s))</strong>
</p>
</td>
</tr>
</table>
</fieldset>
<h3 class="title">Role - group mapping</h3>
<fieldset class="options">
<p class="description">You can set multiple values per role by separating them with a coma</p>
<p class="description">The values are empty by default</p>
<table class="form-table">
<thead>
<th scope="row">Assign this WordPress-Role</th>
<th style="width:auto;">to members of this/these LDAP-Groups</th>
</thead>
<tbody>
<?php
foreach ($roles->get_names() as $group => $vals) :
$aGroup=$authLDAPGroups[$group]; ?>
<tr>
<th scope="row" style="width:auto; min-width: 200px;">
<label for="authLDAPGroups[<?php echo $group; ?>]">
<?php echo $vals; ?>
</label>
</th>
<td>
<input type="text" name="authLDAPGroups[<?php echo $group; ?>]" id="authLDAPGroups[<?php echo $group; ?>]"
value="<?php echo $aGroup; ?>" />
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</fieldset>
</div>
<fieldset class="buttons">
<p class="submit">
<input type="submit" name="ldapOptionsSave" class="button button-primary" value="Save Changes" />
</p>
</fieldset>
</form>
</div>
<script type="text/javascript">
elem = document.getElementById('authLDAPGroupEnable');
if(! elem.checked) {
document.getElementById('authldaprolemapping').setAttribute('style', 'display:none;');
}
elem.addEventListener('change', function(e){
if(! e.target.checked) {
document.getElementById('authldaprolemapping').setAttribute('style', 'display:none;');
} else {
document.getElementById('authldaprolemapping').removeAttribute('style');
}
});
</script>

View File

@ -1,577 +0,0 @@
<?php
// Event schedules failed
if ( !wp_next_scheduled ( 'cau_set_schedule_mail' ) ) {
echo '<div id="message" class="error"><p><b>'.__( 'Companion Auto Update was not able to set the event for sending you emails, please re-activate the plugin in order to set the event', 'companion-auto-update' ).'.</b></p></div>';
}
// Database requires an update
if ( cau_incorrectDatabaseVersion() ) {
echo '<div id="message" class="error"><p><b>'.__( 'Companion Auto Update Database Update', 'companion-auto-update' ).' &ndash;</b>
'.__( 'We need you to update to the latest database version', 'companion-auto-update' ).'. <a href="'.cau_url( 'status' ).'&run=db_update" class="button button-alt" style="background: #FFF;">'.__( 'Run updater now', 'companion-auto-update' ).'</a></p></div>';
}
// Update log DB is empty
if ( cau_updateLogDBisEmpty() ) {
echo '<div id="message" class="error"><p><b>'.__( 'Companion Auto Update Database Update', 'companion-auto-update' ).' &ndash;</b>
'.__( 'We need to add some information to your database', 'companion-auto-update' ).'. <a href="'.cau_url( 'status' ).'&run=db_info_update" class="button button-alt" style="background: #FFF;">'.__( 'Run updater now', 'companion-auto-update' ).'</a></p></div>';
}
// Save settings
if( isset( $_POST['submit'] ) ) {
check_admin_referer( 'cau_save_settings' );
global $wpdb;
$table_name = $wpdb->prefix . "auto_updates";
// Auto updater
$plugins = isset( $_POST['plugins'] ) ? sanitize_text_field( $_POST['plugins'] ) : '';
$themes = isset( $_POST['themes'] ) ? sanitize_text_field( $_POST['themes'] ) : '';
$minor = isset( $_POST['minor'] ) ? sanitize_text_field( $_POST['minor'] ) : '';
$major = isset( $_POST['major'] ) ? sanitize_text_field( $_POST['major'] ) : '';
$translations = isset( $_POST['translations'] ) ? sanitize_text_field( $_POST['translations'] ) : '';
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'plugins'", $plugins ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'themes'", $themes ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'minor'", $minor ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'major'", $major ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'translations'", $translations ) );
// Emails
$send = isset( $_POST['cau_send'] ) ? sanitize_text_field( $_POST['cau_send'] ) : '';
$sendupdate = isset( $_POST['cau_send_update'] ) ? sanitize_text_field( $_POST['cau_send_update'] ) : '';
$sendoutdated = isset( $_POST['cau_send_outdated'] ) ? sanitize_text_field( $_POST['cau_send_outdated'] ) : '';
$wpemails = isset( $_POST['wpemails'] ) ? sanitize_text_field( $_POST['wpemails'] ) : '';
$email = isset( $_POST['cau_email'] ) ? sanitize_text_field( $_POST['cau_email'] ) : '';
$html_or_text = isset( $_POST['html_or_text'] ) ? sanitize_text_field( $_POST['html_or_text'] ) : 'html';
$dbupdateemails = isset( $_POST['dbupdateemails'] ) ? sanitize_text_field( $_POST['dbupdateemails'] ) : '';
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'email'", $email ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'send'", $send ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'sendupdate'", $sendupdate ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'sendoutdated'", $sendoutdated ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'wpemails'", $wpemails ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'html_or_text'", $html_or_text ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'dbupdateemails'", $dbupdateemails ) );
// Advanced
$allow_editor = isset( $_POST['allow_editor'] ) ? sanitize_text_field( $_POST['allow_editor'] ) : '';
$allow_author = isset( $_POST['allow_author'] ) ? sanitize_text_field( $_POST['allow_author'] ) : '';
$advanced_info_emails = isset( $_POST['advanced_info_emails'] ) ? sanitize_text_field( $_POST['advanced_info_emails'] ) : '';
$plugin_links_emails = isset( $_POST['plugin_links_emails'] ) ? sanitize_text_field( $_POST['plugin_links_emails'] ) : '';
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'allow_editor'", $allow_editor ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'allow_author'", $allow_author ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'advanced_info_emails'", $advanced_info_emails ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'plugin_links_emails'", $plugin_links_emails ) );
// Delay
$update_delay = isset( $_POST['update_delay'] ) ? sanitize_text_field( $_POST['update_delay'] ) : '';
$update_delay_days = isset( $_POST['update_delay_days'] ) ? sanitize_text_field( $_POST['update_delay_days'] ) : '';
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'update_delay'", $update_delay ) );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = %s WHERE name = 'update_delay_days'", $update_delay_days ) );
// Intervals
// Set variables
$plugin_sc = sanitize_text_field( $_POST['plugin_schedule'] );
$theme_sc = sanitize_text_field( $_POST['theme_schedule'] );
$core_sc = sanitize_text_field( $_POST['core_schedule'] );
$schedule_mail = sanitize_text_field( $_POST['update_notifications'] );
$outdated_notifier = sanitize_text_field( $_POST['outdated_notifier'] );
// First clear schedules
wp_clear_scheduled_hook( 'wp_update_plugins' );
wp_clear_scheduled_hook( 'wp_update_themes' );
wp_clear_scheduled_hook( 'wp_version_check' );
wp_clear_scheduled_hook( 'cau_set_schedule_mail' );
wp_clear_scheduled_hook( 'cau_custom_hooks_plugins' );
wp_clear_scheduled_hook( 'cau_custom_hooks_themes' );
wp_clear_scheduled_hook( 'cau_log_updater' );
wp_clear_scheduled_hook( 'cau_outdated_notifier' );
// Then set the new times
// Plugins
if( $plugin_sc == 'daily' ) {
$date = date( 'Y-m-d' );
$hours = sanitize_text_field( $_POST['plugin_schedule-sethour'] );
$minutes = sanitize_text_field( $_POST['plugin_schedule-setminutes'] );
$seconds = date( 's' );
$fullDate = $date.' '.$hours.':'.$minutes.':'.$seconds;
$pluginSetTime = strtotime( $fullDate );
wp_schedule_event( $pluginSetTime, $plugin_sc, 'wp_update_plugins' );
wp_schedule_event( $pluginSetTime, $plugin_sc, 'cau_custom_hooks_plugins' );
wp_schedule_event( ( $pluginSetTime - 1800 ), $plugin_sc, 'cau_log_updater' );
} else {
wp_schedule_event( time(), $plugin_sc, 'wp_update_plugins' );
wp_schedule_event( time(), $plugin_sc, 'cau_custom_hooks_plugins' );
wp_schedule_event( ( time() - 1800 ), $plugin_sc, 'cau_log_updater' );
}
// Themes
if( $theme_sc == 'daily' ) {
$dateT = date( 'Y-m-d' );
$hoursT = sanitize_text_field( $_POST['theme_schedule-sethour'] );
$minutesT = sanitize_text_field( $_POST['theme_schedule-setminutes'] );
$secondsT = date( 's' );
$fullDateT = $dateT.' '.$hoursT.':'.$minutesT.':'.$secondsT;
$themeSetTime = strtotime( $fullDateT );
wp_schedule_event( $themeSetTime, $theme_sc, 'wp_update_themes' );
wp_schedule_event( $themeSetTime, $theme_sc, 'cau_custom_hooks_themes' );
} else {
wp_schedule_event( time(), $theme_sc, 'wp_update_themes' );
wp_schedule_event( time(), $theme_sc, 'cau_custom_hooks_themes' );
}
// Core
if( $core_sc == 'daily' ) {
$dateC = date( 'Y-m-d' );
$hoursC = sanitize_text_field( $_POST['core_schedule-sethour'] );
$minutesC = sanitize_text_field( $_POST['core_schedule-setminutes'] );
$secondsC = date( 's' );
$fullDateC = $dateC.' '.$hoursC.':'.$minutesC.':'.$secondsC;
$coreSetTime = strtotime( $fullDateC );
wp_schedule_event( $coreSetTime, $core_sc, 'wp_version_check' );
} else {
wp_schedule_event( time(), $core_sc, 'wp_version_check' );
}
// Update notifications
if( $schedule_mail == 'daily' ) {
$dateT = date( 'Y-m-d' );
$hoursT = sanitize_text_field( $_POST['update_notifications-sethour'] );
$minutesT = sanitize_text_field( $_POST['update_notifications-setminutes'] );
$secondsT = date( 's' );
$fullDateT = $dateT.' '.$hoursT.':'.$minutesT.':'.$secondsT;
$emailSetTime = strtotime( $fullDateT );
wp_schedule_event( $emailSetTime, $schedule_mail, 'cau_set_schedule_mail' );
} else {
wp_schedule_event( time(), $schedule_mail, 'cau_set_schedule_mail' );
}
// Outdated notifications
if( $outdated_notifier == 'daily' ) {
$dateT = date( 'Y-m-d' );
$hoursT = sanitize_text_field( $_POST['outdated_notifier-sethour'] );
$minutesT = sanitize_text_field( $_POST['outdated_notifier-setminutes'] );
$secondsT = date( 's' );
$fullDateT = $dateT.' '.$hoursT.':'.$minutesT.':'.$secondsT;
$emailSetTime = strtotime( $fullDateT );
wp_schedule_event( $emailSetTime, $outdated_notifier, 'cau_outdated_notifier' );
} else {
wp_schedule_event( time(), $outdated_notifier, 'cau_outdated_notifier' );
}
echo '<div id="message" class="updated"><p><b>'.__( 'Settings saved.' ).'</b></p></div>';
}
// Welcome screen for first time viewers
if( isset( $_GET['welcome'] ) ) {
echo '<div class="welcome-to-cau welcome-bg" style="margin-bottom: 0px;">
<div class="welcome-image">
</div><div class="welcome-content">
<h3>'.__( 'Welcome to Companion Auto Update', 'companion-auto-update' ).'</h3>
<br />
<p><strong>'.__( 'You\'re set and ready to go', 'companion-auto-update' ).'</strong></p>
<p>'.__( 'The plugin is all set and ready to go with the recommended settings, but if you\'d like you can change them below.' ).'</p>
<br />
<p><strong>'.__( 'Get Started' ).': </strong> <a href="'.cau_url( 'pluginlist' ).'">'.__( 'Update filter', 'companion-auto-update' ).'</a> &nbsp; | &nbsp;
<strong>'.__( 'More Actions' ).': </strong> <a href="http://codeermeneer.nl/cau_poll/" target="_blank">'.__('Give feedback', 'companion-auto-update').'</a> - <a href="https://translate.wordpress.org/projects/wp-plugins/companion-auto-update/" target="_blank">'.__( 'Help us translate', 'companion-auto-update' ).'</a></p>
</div>
</div>';
}
$cs_hooks_p = wp_get_schedule( 'cau_custom_hooks_plugins' );
$cs_hooks_t = wp_get_schedule( 'cau_custom_hooks_themes' );
?>
<div class="cau-dashboard cau-column-wide">
<form method="POST">
<div class="welcome-to-cau update-bg cau-dashboard-box">
<h2 class="title"><?php _e('Auto Updater', 'companion-auto-update');?></h2>
<table class="form-table">
<tr>
<td>
<fieldset>
<?php
$plugins_on = ( cau_get_db_value( 'plugins' ) == 'on' ) ? "CHECKED" : "";
$themes_on = ( cau_get_db_value( 'themes' ) == 'on' ) ? "CHECKED" : "";
$minor_on = ( cau_get_db_value( 'minor' ) == 'on' ) ? "CHECKED" : "";
$major_on = ( cau_get_db_value( 'major' ) == 'on' ) ? "CHECKED" : "";
$translations_on = ( cau_get_db_value( 'translations' ) == 'on' ) ? "CHECKED" : "";
echo "<p><input id='plugins' name='plugins' type='checkbox' {$plugins_on}/><label for='plugins'>".__( 'Auto update plugins?', 'companion-auto-update' )."</label></p>";
echo "<p><input id='themes' name='themes' type='checkbox' {$themes_on}/><label for='themes'>".__( 'Auto update themes?', 'companion-auto-update' )."</label></p>";
echo "<p><input id='minor' name='minor' type='checkbox' {$minor_on}/><label for='minor'>".__( 'Auto update minor core updates?', 'companion-auto-update' )." <code class='majorMinorExplain'>6.0.0 > 6.0.1</code></label></p>";
echo "<p><input id='major' name='major' type='checkbox' {$major_on}/><label for='major'>".__( 'Auto update major core updates?', 'companion-auto-update' )." <code class='majorMinorExplain'>6.0.0 > 6.1.0</code></label></p>";
echo "<p><input id='translations' name='translations' type='checkbox' {$translations_on}/><label for='translations'>".__( 'Auto update translation files?', 'companion-auto-update' )."</label></p>";
?>
</fieldset>
</td>
</tr>
</table>
</div>
<div class="welcome-to-cau email-bg cau-dashboard-box">
<h2 class="title"><?php _e( 'Email Notifications', 'companion-auto-update' );?></h2>
<?php
$db_email = cau_get_db_value( 'email' );
$toemail = ( $db_email == '' ) ? get_option( 'admin_email' ) : $db_email;
$hot = cau_get_db_value( 'html_or_text' );
?>
<table class="form-table">
<tr>
<th scope="row"><?php _e( 'Update notifications', 'companion-auto-update' );?></th>
<td>
<p>
<input id="cau_send_update" name="cau_send_update" type="checkbox" <?php if( cau_get_db_value( 'sendupdate' ) == 'on' ) { echo 'checked'; } ?> />
<label for="cau_send_update"><?php _e( 'Send me emails when something has been updated.', 'companion-auto-update' );?></label>
</p>
<p>
<input id="cau_send" name="cau_send" type="checkbox" <?php if( cau_get_db_value( 'send' ) == 'on' ) { echo 'checked'; } ?> />
<label for="cau_send"><?php _e( 'Send me emails when an update is available.', 'companion-auto-update' );?></label>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Check for outdated software', 'companion-auto-update' );?></th>
<td>
<p>
<input id="cau_send_outdated" name="cau_send_outdated" type="checkbox" <?php if( cau_get_db_value( 'sendoutdated' ) == 'on' ) { echo 'checked'; } ?> />
<label for="cau_send_outdated"><?php _e( 'Be notified of plugins that have not been tested with the 3 latest major versions of WordPress.', 'companion-auto-update' );?></label>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Email Address', 'companion-auto-update' );?></th>
<td>
<p>
<label for="cau_email"><?php _e( 'To', 'companion-auto-update' ); ?>:</label>
<input type="text" name="cau_email" id="cau_email" class="regular-text" placeholder="<?php echo get_option( 'admin_email' ); ?>" value="<?php echo esc_html( $toemail ); ?>" />
</p>
<p class="description"><?php _e('Seperate email addresses using commas.', 'companion-auto-update');?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Use HTML in emails?', 'companion-auto-update' );?></th>
<td>
<p>
<select id='html_or_text' name='html_or_text'>
<option value='html' <?php if( $hot == 'html' ) { echo "SELECTED"; } ?>><?php _e( 'Use HTML', 'companion-auto-update' ); ?></option>
<option value='text' <?php if( $hot == 'text' ) { echo "SELECTED"; } ?>><?php _e( 'Use plain text', 'companion-auto-update' ); ?></option>
</select>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Show more info in emails', 'companion-auto-update' );?></th>
<td>
<p>
<label for="advanced_info_emails"><input name="advanced_info_emails" type="checkbox" id="advanced_info_emails" <?php if( cau_get_db_value( 'advanced_info_emails' ) == 'on' ) { echo "CHECKED"; } ?>> <?php _e( 'Show the time of the update', 'companion-auto-update' ); ?></label>
</p>
<p>
<label for="plugin_links_emails"><input name="plugin_links_emails" type="checkbox" id="plugin_links_emails" <?php if( cau_get_db_value( 'plugin_links_emails' ) == 'on' ) { echo "CHECKED"; } ?>> <?php _e( 'Show links to WordPress.org pages', 'companion-auto-update' ); ?></label>
</p>
</td>
</tr>
<tr>
<th scope="row">
<?php _e( 'WordPress notifications', 'companion-auto-update' );?>
<span class='cau_tooltip'><span class="dashicons dashicons-editor-help"></span>
<span class='cau_tooltip_text'>
<?php _e( 'Core notifications are handled by WordPress and not by this plugin. You can only disable them, changing your email address in the settings above will not affect these notifications.', 'companion-auto-update' );?>
</span>
</span>
</th>
<td>
<p>
<input id="wpemails" name="wpemails" type="checkbox" <?php if( cau_get_db_value( 'wpemails' ) == 'on' ) { echo 'checked'; } ?> />
<label for="wpemails"><?php _e( 'By default WordPress sends an email when a core update has occurred. Uncheck this box to disable these emails.', 'companion-auto-update' ); ?></label>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Database update required', 'companion-auto-update' );?></th>
<td>
<p>
<input id="dbupdateemails" name="dbupdateemails" type="checkbox" <?php if( cau_get_db_value( 'dbupdateemails' ) == 'on' ) { echo 'checked'; } ?> />
<label for="dbupdateemails"><?php _e( 'Sometimes we\'ll need your help updating our database version to the latest version, check this box to allow us to send you an email about this.', 'companion-auto-update' ); ?></label>
</p>
</td>
</tr>
</table>
</div>
<div class="welcome-to-cau interval-bg cau-dashboard-box" style="overflow: hidden;">
<h2 class="title"><?php _e( 'Intervals', 'companion-auto-update' );?></h2>
<?php
function cau_show_interval_selection( $identiefier, $schedule ) {
// Get the info
$setValue = wp_get_schedule( $schedule );
$setTime = wp_next_scheduled( $schedule );
$setHour = date( 'H' , $setTime );
$setMinutes = date( 'i' , $setTime );
// Show interval selection
echo "<p>";
echo "<select name='$identiefier' id='$identiefier' class='schedule_interval wide interval_scheduler' data-timeblock='$identiefier'>";
foreach ( cau_wp_get_schedules() as $key => $value ) {
echo "<option "; if( $setValue == $key ) { echo "selected "; } echo "value='".$key."'>".$value."</option>";
}
echo "</select>";
echo "</p>";
// Set the time when daily is selected
echo "<div class='timeblock-$identiefier' style='display: none;'>";
echo "<div class='cau_schedule_input'>
<input type='number' min='0' max='23' name='".$identiefier."-sethour' value='$setHour' maxlength='2' >
</div><div class='cau_schedule_input_div'>
:
</div><div class='cau_schedule_input'>
<input type='number' min='0' max='59' name='".$identiefier."-setminutes' value='$setMinutes' maxlength='2' >
</div><div class='cau_shedule_notation'>
<span class='cau_tooltip'><span class='dashicons dashicons-editor-help'></span>
<span class='cau_tooltip_text'>".__( 'At what time should the updater run? Only works when set to <u>daily</u>.', 'companion-auto-update' )." - ".__( 'Time notation: 24H', 'companion-auto-update' )."</span>
</span>
</div>";
echo "</div>";
}
?>
<div class="welcome-column">
<h4><?php _e( 'Plugin update interval', 'companion-auto-update' );?></h4>
<?php cau_show_interval_selection( 'plugin_schedule', 'wp_update_plugins' ); ?>
</div>
<div class="welcome-column">
<h4><?php _e( 'Theme update interval', 'companion-auto-update' );?></h4>
<?php cau_show_interval_selection( 'theme_schedule', 'wp_update_themes' ); ?>
</div>
<div class="welcome-column">
<h4><?php _e( 'Core update interval', 'companion-auto-update' );?></h4>
<?php cau_show_interval_selection( 'core_schedule', 'wp_version_check' ); ?>
</div>
<p></p>
<div class="welcome-column">
<h4><?php _e( 'Update notifications', 'companion-auto-update' );?></h4>
<?php cau_show_interval_selection( 'update_notifications', 'cau_set_schedule_mail' ); ?>
</div>
<div class="welcome-column">
<h4><?php _e( 'Outdated software', 'companion-auto-update' );?></h4>
<?php cau_show_interval_selection( 'outdated_notifier', 'cau_outdated_notifier' ); ?>
</div>
</div>
<div class="welcome-to-cau advanced-bg cau-dashboard-box">
<h2 class="title"><?php _e( 'Advanced settings', 'companion-auto-update' ); ?></h2>
<?php
// Access
$accessallowed = cau_allowed_user_rights_array();
$has_editor = in_array( 'editor', $accessallowed ) ? true : false;
$has_author = in_array( 'author', $accessallowed ) ? true : false;
// Update delays
$has_updatedelay = ( cau_get_db_value( 'update_delay' ) == 'on' ) ? true : false;
?>
<table class="form-table">
<tbody>
<tr>
<th scope="row"><label><?php _e( 'Allow access to:', 'companion-auto-update' ); ?></label></th>
<td>
<p><label for="allow_administrator"><input name="allow_administrator" type="checkbox" id="allow_administrator" disabled="" checked=""><?php _e( 'Administrator', 'companion-auto-update' ); ?></label></p>
<p><label for="allow_editor"><input name="allow_editor" type="checkbox" id="allow_editor" <?php if( $has_editor ) { echo "CHECKED"; } ?>><?php _e( 'Editor', 'companion-auto-update' ); ?></label></p>
<p><label for="allow_author"><input name="allow_author" type="checkbox" id="allow_author" <?php if( $has_author ) { echo "CHECKED"; } ?>><?php _e( 'Author', 'companion-auto-update' ); ?></label></p>
</td>
</tr>
<tr>
<th scope="row"><label><?php _e( 'Delay updates', 'companion-auto-update' ); ?></label></th>
<td>
<p><label for="update_delay"><input name="update_delay" type="checkbox" id="update_delay" <?php echo $has_updatedelay ? "CHECKED" : ""; ?> ><?php _e( 'Delay updates', 'companion-auto-update' ); ?></label></p>
</td>
</tr>
<tr id='update_delay_days_block' <?php echo !$has_updatedelay ? "class='disabled_option'" : ""; ?>>
<th scope="row"><label><?php _e( 'Number of days', 'companion-auto-update' ); ?></label></th>
<td>
<input type="number" min="0" max="31" name="update_delay_days" id="update_delay_days" class="regular-text" value="<?php echo cau_get_db_value( 'update_delay_days' ); ?>" />
<p><?php _e( 'For how many days should updates be put on hold?', 'companion-auto-update' ); ?></p>
<p><small><strong>Please note:</strong> Delaying updates does not work with WordPress updates yet.</small></p>
</td>
</tr>
</tbody>
</table>
</div>
<?php wp_nonce_field( 'cau_save_settings' ); ?>
<div class="cau_save_button">
<?php submit_button(); ?>
</div>
<div class="cau_save_button__space"></div>
<script>jQuery( '.cau-dashboard input, .cau-dashboard select, .cau-dashboard textarea' ).on( 'change', function() { jQuery('.cau_save_button').addClass( 'fixed_button' ); } );</script>
</form>
</div><div class="cau-column-small">
<div class="welcome-to-cau help-bg cau-dashboard-box">
<div class="welcome-column welcome-column.welcome-column-half">
<h3 class="support-sidebar-title"><?php _e( 'Help' ); ?></h3>
<ul class="support-sidebar-list">
<li><a href="https://codeermeneer.nl/stuffs/faq-auto-updater/" target="_blank"><?php _e( 'Frequently Asked Questions', 'companion-auto-update' ); ?></a></li>
<li><a href="https://wordpress.org/support/plugin/companion-auto-update" target="_blank"><?php _e( 'Support Forums' ); ?></a></li>
</ul>
<h3 class="support-sidebar-title"><?php _e( 'Want to contribute?', 'companion-auto-update' ); ?></h3>
<ul class="support-sidebar-list">
<li><a href="http://codeermeneer.nl/cau_poll/" target="_blank"><?php _e( 'Give feedback', 'companion-auto-update' ); ?></a></li>
<li><a href="https://codeermeneer.nl/blog/companion-auto-update-and-its-future/" target="_blank"><?php _e( 'Feature To-Do List', 'companion-auto-update' ); ?></a></li>
<li><a href="https://translate.wordpress.org/projects/wp-plugins/companion-auto-update/" target="_blank"><?php _e( 'Help us translate', 'companion-auto-update' ); ?></a></li>
</ul>
</div>
<div class="welcome-column welcome-column.welcome-column-half">
<h3 class="support-sidebar-title"><?php _e( 'Developer?', 'companion-auto-update' ); ?></h3>
<ul class="support-sidebar-list">
<li><a href="https://codeermeneer.nl/documentation/auto-update/" target="_blank"><?php _e( 'Documentation' ); ?></a></li>
</ul>
</div>
</div>
<div class="welcome-to-cau support-bg cau-dashboard-box">
<div class="welcome-column welcome-column">
<h3><?php _e('Support', 'companion-auto-update');?></h3>
<p><?php _e('Feel free to reach out to us if you have any questions or feedback.', 'companion-auto-update'); ?></p>
<p><a href="https://codeermeneer.nl/contact/" target="_blank" class="button button-primary"><?php _e( 'Contact us', 'companion-auto-update' ); ?></a></p>
<p><a href="https://codeermeneer.nl/plugins/" target="_blank" class="button button-alt"><?php _e('Check out our other plugins', 'companion-auto-update');?></a></p>
</div>
</div>
<div class="welcome-to-cau love-bg cau-show-love cau-dashboard-box">
<h3><?php _e( 'Like our plugin?', 'companion-auto-update' ); ?></h3>
<p><?php _e('Companion Auto Update is free to use. It has required a great deal of time and effort to develop and you can help support this development by making a small donation.<br />You get useful software and we get to carry on making it better.', 'companion-auto-update'); ?></p>
<a href="https://wordpress.org/support/plugin/companion-auto-update/reviews/#new-post" target="_blank" class="button button-alt button-hero">
<?php _e('Rate us (5 stars?)', 'companion-auto-update'); ?>
</a>
<a href="<?php echo cau_donateUrl(); ?>" target="_blank" class="button button-primary button-hero">
<?php _e('Donate to help development', 'companion-auto-update'); ?>
</a>
<p style="font-size: 12px; color: #BDBDBD;"><?php _e( 'Donations via PayPal. Amount can be changed.', 'companion-auto-update'); ?></p>
</div>
<div class="welcome-to-cau cau-dashboard-box">
<h3><span style='background: #EBE3F7; color: #BCADD3; padding: 1px 5px; border-radius: 3px; font-size: .8em'>Plugin Promotion</span></h3>
<h3>Keep your site fast with our Revision Manager</h3>
<p>Post Revisions are great, but will also slow down your site. Take back control over revisions with Companion Revision Manager!</p>
<a href="https://codeermeneer.nl/portfolio/plugin/companion-revision-manager/" target="_blank" class="button button-alt">Read more</a>
</div>
</div>
<style>
.disabled_option {
opacity: .5;
}
</style>
<script type="text/javascript">
jQuery( '#update_delay' ).change( function() {
jQuery( '#update_delay_days_block' ).toggleClass( 'disabled_option' );
});
jQuery( '.interval_scheduler' ).change( function() {
var selected = jQuery(this).val(); // Selected value
var timeblock = jQuery(this).data( 'timeblock' ); // Corresponding time block
if( selected == 'daily' ) {
jQuery( '.timeblock-'+timeblock ).show();
} else {
jQuery( '.timeblock-'+timeblock ).hide();
}
});
jQuery( '.interval_scheduler' ).each( function() {
var selected = jQuery(this).val(); // Selected value
var timeblock = jQuery(this).data( 'timeblock' ); // Corresponding time block
if( selected == 'daily' ) {
jQuery( '.timeblock-'+timeblock ).show();
} else {
jQuery( '.timeblock-'+timeblock ).hide();
}
});
</script>

View File

@ -1,19 +0,0 @@
<?php
if( isset( $_GET['filter'] ) ) {
$filter = $_GET['filter'];
} else {
$filter = 'all';
}
?>
<ul class="subsubsub">
<li><a <?php if( $filter == 'all' ) { echo "class='current'"; } ?> href='<?php echo cau_url( 'log&filter=all' ); ?>'><?php _e( 'View full changelog', 'companion-auto-update' ); ?></a></li> |
<li><a <?php if( $filter == 'plugins' ) { echo "class='current'"; } ?> href='<?php echo cau_url( 'log&filter=plugins' ); ?>'><?php _e( 'Plugins', 'companion-auto-update' ); ?></a></li> |
<li><a <?php if( $filter == 'themes' ) { echo "class='current'"; } ?> href='<?php echo cau_url( 'log&filter=themes' ); ?>'><?php _e( 'Themes', 'companion-auto-update' ); ?></a></li> |
<li><a <?php if( $filter == 'translations' ) { echo "class='current'"; } ?> href='<?php echo cau_url( 'log&filter=translations' ); ?>'><?php _e( 'Translations', 'companion-auto-update' ); ?></a></li>
</ul>
<div class='cau_spacing'></div>
<?php
cau_fetch_log( 'all', 'table' );

View File

@ -1,185 +0,0 @@
<?php
// Get selected filter type
if( isset( $_GET['filter'] ) ) {
$filter = sanitize_key( $_GET['filter'] );
} else {
$filter = 'plugins';
}
// Select correct database row
switch ( $filter ) {
case 'themes':
$db_table = 'notUpdateListTh';
$filter_name = __( 'Themes', 'companion-auto-update' );
$filterFunction = wp_get_themes();
break;
case 'plugins':
$db_table = 'notUpdateList';
$filter_name = __( 'Plugins', 'companion-auto-update' );
$filterFunction = get_plugins();
break;
default:
$db_table = 'notUpdateList';
$filter_name = __( 'Plugins', 'companion-auto-update' );
$filterFunction = get_plugins();
break;
}
?>
<ul class="subsubsub">
<li><a <?php if( $filter == 'plugins' ) { echo "class='current'"; } ?> href='<?php echo cau_url( 'pluginlist&filter=plugins' ); ?>'><?php _e( 'Plugins', 'companion-auto-update' ); ?></a></li> |
<li><a <?php if( $filter == 'themes' ) { echo "class='current'"; } ?> href='<?php echo cau_url( 'pluginlist&filter=themes' ); ?>'><?php _e( 'Themes', 'companion-auto-update' ); ?></a></li>
</ul>
<div style='clear: both;'></div>
<?php if( $filter == 'themes' ) { ?>
<div id="message" class="cau">
We've had to (temporarily) disable the theme filter because it was causing issues on some installations. We'll try to get it working again in a future update.
</div>
<?php } ?>
<p><?php echo sprintf( esc_html__( 'Prevent certain %s from updating automatically. %s that you select here will be skipped by Companion Auto Update and will require manual updating.', 'companion-auto-update' ), strtolower( $filter_name ), $filter_name ); ?></p>
<?php
global $wpdb;
$table_name = $wpdb->prefix."auto_updates";
// Save list
if( isset( $_POST['submit'] ) ) {
check_admin_referer( 'cau_save_pluginlist' );
$noUpdateList = '';
$i = 0;
$noUpdateCount = 0;
if( isset( $_POST['post'] ) ) {
$noUpdateCount = count( $_POST['post'] );
}
if( $noUpdateCount > 0 ) {
foreach ( $_POST['post'] as $key ) {
$noUpdateList .= sanitize_text_field( $key );
$i++;
if( $i != $noUpdateCount ) $noUpdateList .= ', ';
}
}
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = '%s' WHERE name = '%s'", $noUpdateList, $db_table ) );
echo '<div id="message" class="updated"><p><b>'.__( 'Succes', 'companion-auto-update' ).' &ndash;</b> '.sprintf( esc_html__( '%1$s %2$s have been added to the no-update-list', 'companion-auto-update' ), $noUpdateCount, strtolower( $filter_name ) ).'.</p></div>';
}
// Reset list
if( isset( $_POST['reset'] ) ) {
check_admin_referer( 'cau_save_pluginlist' );
$wpdb->query( $wpdb->prepare( "UPDATE $table_name SET onoroff = '%s' WHERE name = %s", "", $db_table ) );
echo '<div id="message" class="updated"><p><b>'.__( 'Succes', 'companion-auto-update' ).' &ndash;</b> '.sprintf( esc_html__( 'The no-update-list has been reset, all %s will be auto-updated from now on', 'companion-auto-update' ), strtolower( $filter_name ) ).'.</p></div>';
}
?>
<form method="POST">
<div class='pluginListButtons'>
<?php submit_button(); ?>
<input type='submit' name='reset' id='reset' class='button button-alt' value='<?php _e( "Reset list", "companion-auto-update" ); ?>'>
</div>
<table class="wp-list-table widefat autoupdate striped">
<thead>
<tr>
<td>&nbsp;</td>
<th class="head-plugin"><strong><?php _e( 'Name', 'companion-auto-update' ); ?></strong></th>
<th class="head-status"><strong><?php _e( 'Status', 'companion-auto-update' ); ?></strong></th>
<th class="head-description"><strong><?php _e( 'Description' ); ?></strong></th>
</tr>
</thead>
<tbody id="the-list">
<?php
foreach ( $filterFunction as $key => $value ) {
$slug = $key;
$explosion = explode( '/', $slug );
$actualSlug = array_shift( $explosion );
$slug_hash = md5( $slug[0] );
if( $filter == 'themes' ) {
$theme = wp_get_theme( $actualSlug );
$name = $theme->get( 'Name' );
$description = $theme->get( 'Description' );
} else {
foreach ( $value as $k => $v ) {
if( $k == "Name" ) $name = $v;
if( $k == "Description" ) $description = $v;
}
}
if( in_array( $actualSlug, donotupdatelist( $filter ) ) ) {
$class = 'inactive';
$checked = 'CHECKED';
$statusicon = 'no';
$statusName = 'disabled';
} else {
$class = 'active';
$checked = '';
$statusicon = 'yes';
$statusName = 'enabled';
}
echo '<tr id="post-'.$slug_hash.'" class="'.$class.'">
<th class="check-column">
<label class="screen-reader-text" for="cb-select-'.$slug_hash.'">Select '. $name .'</label>
<input id="cb-select-'.$slug_hash.'" type="checkbox" name="post[]" value="'.$actualSlug.'" '.$checked.' ><label></label>
<div class="locked-indicator"></div>
</th>
<td class="column-name">
<p style="margin-bottom: 0px;"><strong>'. $name .'</strong></p>
<small class="description" style="opacity: 0.5; margin-bottom: 3px;">'.$actualSlug.'</small>
</td>
<td class="cau_hide_on_mobile column-status">
<p><span class="nowrap">'.__( 'Auto Updater', 'companion-auto-update' ).': <span class="cau_'.$statusName.'"><span class="dashicons dashicons-'.$statusicon.'"></span></span></span></p>
</td>
<td class="cau_hide_on_mobile column-description">
<p>'.$description.'</p>
</td>
</tr>';
}
?>
</tbody>
</table>
<?php wp_nonce_field( 'cau_save_pluginlist' ); ?>
<div class='pluginListButtons'>
<?php submit_button(); ?>
<input type='submit' name='reset' id='reset' class='button button-alt' value='<?php _e( "Reset list", "companion-auto-update" ); ?>'>
</div>
</form>

View File

@ -1,2 +0,0 @@
<?php
// Currently working on this

View File

@ -1,435 +0,0 @@
<?php
// Define globals
global $wpdb;
// Define variables
$dateFormat = get_option( 'date_format' );
$dateFormat .= ' '.get_option( 'time_format' );
$table_name = $wpdb->prefix . "auto_updates";
$schedules = wp_get_schedules();
$interval_names = cau_wp_get_schedules();
// Update the database
if( isset( $_GET['run'] ) && $_GET['run'] == 'db_update' ) {
cau_manual_update();
echo '<div id="message" class="updated"><p><b>'.__( 'Database update completed' ).'</b></p></div>';
}
if( isset( $_GET['run'] ) && $_GET['run'] == 'db_info_update' ) {
cau_savePluginInformation();
echo '<div id="message" class="updated"><p><b>'.__( 'Database information update completed' ).'</b></p></div>';
}
if( isset( $_GET['ignore_report'] ) ) {
$report_to_ignore = sanitize_text_field( $_GET['ignore_report'] );
$allowedValues = array( 'seo', 'cron' );
if( !in_array( $report_to_ignore, $allowedValues ) ) {
wp_die( 'Trying to cheat eh?' );
} else {
$table_name = $wpdb->prefix . "auto_updates";
$wpdb->query( $wpdb->prepare( "UPDATE {$table_name} SET onoroff = %s WHERE name = 'ignore_$report_to_ignore'", 'yes' ) );
$__ignored = __( 'This report will now be ignored', 'companion-auto-update' );
echo "<div id='message' class='updated'><p><b>$__ignored</b></p></div>";
}
}
?>
<div class="cau_status_page">
<?php
$events = array(
0 => array(
'name' => __( 'Events', 'companion-auto-update' ),
'fields' => array(
'plugins' => __( 'Plugins', 'companion-auto-update' ),
'themes' => __( 'Themes', 'companion-auto-update' ),
'minor' => __( 'Core (Minor)', 'companion-auto-update' ),
'major' => __( 'Core (Major)', 'companion-auto-update' ),
'send' => __( 'Update available', 'companion-auto-update' ),
'sendupdate' => __( 'Successful update', 'companion-auto-update' ),
'wpemails' => __( 'Core notifications', 'companion-auto-update' ),
'update_delay' => __( 'Log updater', 'companion-auto-update' ),
),
'values' => array(
'plugins' => 'wp_update_plugins',
'themes' => 'wp_update_themes',
'minor' => 'wp_version_check',
'major' => 'wp_version_check',
'send' => 'cau_set_schedule_mail',
'sendupdate' => 'cau_set_schedule_mail',
'wpemails' => 'cau_set_schedule_mail',
'update_delay' => 'cau_log_updater',
),
'explain' => array(
'plugins' => __('Auto update plugins?', 'companion-auto-update'),
'themes' => __('Auto update themes?', 'companion-auto-update'),
'minor' => __('Auto update minor core updates?', 'companion-auto-update'),
'major' => __('Auto update major core updates?', 'companion-auto-update'),
'send' => __( 'Will notify you of available updates.', 'companion-auto-update' ),
'sendupdate' => __( 'Will notify you after successful updates.', 'companion-auto-update' ),
'wpemails' => __( 'The default WordPress notifications.', 'companion-auto-update' ),
'update_delay' => __( 'Will keep track of the update log and make sure updates are delayed when needed.', 'companion-auto-update' ),
)
),
);
$__sta = __( 'Status', 'companion-auto-update' );
$__int = __( 'Interval', 'companion-auto-update' );
$__nxt = __( 'Next', 'companion-auto-update' );
foreach( $events as $event => $info ) {
echo "<table class='cau_status_list widefat striped'>
<thead>
<tr>
<th class='cau_status_name' colspan='2'><strong>{$info['name']}</strong></th>
<th class='cau_status_active_state'><strong>{$__sta}</strong></th>
<th class='cau_status_interval'><strong>{$__int}</strong></th>
<th class='cau_status_next'><strong>{$__nxt}</strong></th>
</tr>
</thead>
<tbody id='the-list'>";
foreach ( $info['fields'] as $key => $value ) {
$is_on = ( cau_get_db_value( $key ) == 'on' && wp_get_schedule( $info['values'][$key] ) ) ? true : false;
$__status = $is_on ? 'enabled' : 'warning';
$__icon = $is_on ? 'yes-alt' : 'marker';
$__text = $is_on ? __( 'Enabled', 'companion-auto-update' ) : __( 'Disabled', 'companion-auto-update' );
$__interval = $is_on ? $interval_names[wp_get_schedule( $info['values'][$key] )] : '&dash;';
$__next = $is_on ? date_i18n( $dateFormat, wp_next_scheduled( $info['values'][$key] ) ) : '&dash;';
$__exp = !empty( $info['explain'][$key] ) ? '<br /><small>'.$info['explain'][$key].'</small>' : '';
$__nxt = __( 'Next', 'companion-auto-update' );
echo "<tr>
<td class='cau_status_icon'><span class='dashicons dashicons-$__icon cau_$__status'></span></td>
<td class='cau_status_name'><strong>$value</strong>$__exp</td>
<td class='cau_status_active_state'><span class='cau_$__status'>$__text</span></td>
<td class='cau_status_interval'>$__interval</td>
<td class='cau_status_next'><span class='cau_mobile_prefix'>$__nxt: </span>$__next</td>
</tr>";
}
echo "</tbody>
</table>";
}
?>
<table class="cau_status_list widefat striped cau_status_warnings">
<thead>
<tr>
<th class="cau_plugin_issue_name" colspan="5"><strong><?php _e( 'Status' ); ?></strong></th>
</tr>
</thead>
<tbody id="the-list">
<!-- checkAutomaticUpdaterDisabled -->
<tr>
<td class='cau_status_icon'><span class="dashicons dashicons-update"></span></td>
<td><?php _e( 'Auto updates', 'companion-auto-update' ); ?></td>
<?php if ( checkAutomaticUpdaterDisabled() ) { ?>
<td class="cau_status_active_state"><span class='cau_disabled'><span class="dashicons dashicons-no"></span> <?php _e( 'All automatic updates are disabled', 'companion-auto-update' ); ?></span></td>
<td>
<form method="POST">
<?php wp_nonce_field( 'cau_fixit' ); ?>
<button type="submit" name="fixit" class="button button-primary"><?php _e( 'Fix it', 'companion-auto-update' ); ?></button>
<a href="https://codeermeneer.nl/documentation/known-issues-fixes/#updates_disabled" target="_blank" class="button"><?php _e( 'How to fix this', 'companion-auto-update' ); ?></a>
</form>
</td>
<?php } else { ?>
<td class="cau_status_active_state"><span class='cau_enabled'><span class="dashicons dashicons-yes-alt"></span> <?php _e( 'No issues detected', 'companion-auto-update' ); ?></span></td>
<td></td>
<?php } ?>
<td></td>
</tr>
<!-- Connection with WP.org -->
<tr>
<td class='cau_status_icon'><span class="dashicons dashicons-wordpress"></span></td>
<td><?php _e( 'Connection with WordPress.org', 'companion-auto-update' ); ?></td>
<?php if( wp_http_supports( array( 'ssl' ) ) == '1' ) {
$__text = __( 'No issues detected', 'companion-auto-update' );
echo "<td colspan='3' class='cau_status_active_state'><span class='cau_enabled'><span class='dashicons dashicons-yes-alt'></span> $__text</span></td>";
} else {
$__text = __( 'Disabled', 'companion-auto-update' );
echo "<td colspan='3' class='cau_status_active_state'><span class='cau_disabled'><span class='dashicons dashicons-no'></span> $__text</span></td>";
}
?>
</tr>
<!-- ignore_seo check -->
<tr <?php if( cau_get_db_value( 'ignore_seo' ) == 'yes' ) { echo "class='report_hidden'"; } ?> >
<td class='cau_status_icon'><span class="dashicons dashicons-search"></span></td>
<td><?php _e( 'Search Engine Visibility', 'companion-auto-update' ); ?></td>
<?php if( get_option( 'blog_public' ) == 0 ) { ?>
<td colspan="2" class="cau_status_active_state">
<span class='cau_warning'><span class="dashicons dashicons-warning"></span></span>
<?php _e( 'Youve chosen to discourage Search Engines from indexing your site. Auto-updating works best on sites with more traffic, consider enabling indexing for your site.', 'companion-auto-update' ); ?>
</td>
<td>
<a href="<?php echo admin_url( 'options-reading.php' ); ?>" class="button"><?php _e( 'Fix it', 'companion-auto-update' ); ?></a>
<a href="<?php echo cau_url( 'status' ); ?>&ignore_report=seo" class="button button-alt"><?php _e( 'Ignore this report', 'companion-auto-update' ); ?></a>
</td>
<?php } else { ?>
<td colspan="3" class="cau_status_active_state"><span class='cau_enabled'><span class="dashicons dashicons-yes-alt"></span> <?php _e( 'No issues detected', 'companion-auto-update' ); ?></span></td>
<?php } ?>
</tr>
<!-- ignore_cron check -->
<tr <?php if( cau_get_db_value( 'ignore_cron' ) == 'yes' ) { echo "class='report_hidden'"; } ?> >
<td class='cau_status_icon'><span class="dashicons dashicons-admin-generic"></span></td>
<td><?php _e( 'Cronjobs', 'companion-auto-update' ); ?></td>
<?php if( checkCronjobsDisabled() ) { ?>
<td class="cau_status_active_state"><span class='cau_warning'><span class="dashicons dashicons-warning"></span> <?php _e( 'Disabled', 'companion-auto-update' ); ?></span></td>
<td><code>DISABLE_WP_CRON true</code></td>
<td>
<a href="https://codeermeneer.nl/contact/" class="button"><?php _e( 'Contact for support', 'companion-auto-update' ); ?></a>
<a href="<?php echo cau_url( 'status' ); ?>&ignore_report=cron" class="button button-alt"><?php _e( 'Ignore this report', 'companion-auto-update' ); ?></a>
</td>
<?php } else { ?>
<td colspan="3" class="cau_status_active_state"><span class='cau_enabled'><span class="dashicons dashicons-yes-alt"></span> <?php _e( 'No issues detected', 'companion-auto-update' ); ?></span></td>
<?php } ?>
</tr>
<!-- wp_version_check -->
<tr>
<td class='cau_status_icon'><span class="dashicons dashicons-wordpress-alt"></span></td>
<td>wp_version_check</td>
<?php if ( !has_filter( 'wp_version_check', 'wp_version_check' ) ) { ?>
<td colspan="2" class="cau_status_active_state"><span class='cau_disabled'><span class="dashicons dashicons-no"></span> <?php _e( 'A plugin has prevented updates by disabling wp_version_check', 'companion-auto-update' ); ?></span></td>
<td><a href="https://codeermeneer.nl/contact/" class="button"><?php _e( 'Contact for support', 'companion-auto-update' ); ?></a></td>
<?php } else { ?>
<td colspan="3" class="cau_status_active_state"><span class='cau_enabled'><span class="dashicons dashicons-yes-alt"></span> <?php _e( 'No issues detected' , 'companion-auto-update' ); ?></span></td>
<?php } ?>
</tr>
<!-- VCD -->
<tr>
<td class='cau_status_icon'><span class="dashicons dashicons-open-folder"></span></td>
<td>VCS</td>
<td colspan="3" class="cau_status_active_state"><span class='cau_<?php echo cau_test_is_vcs_checkout( ABSPATH )['status']; ?>'><span class="dashicons dashicons-<?php echo cau_test_is_vcs_checkout( ABSPATH )['icon']; ?>"></span> <?php echo cau_test_is_vcs_checkout( ABSPATH )['description']; ?></span></td>
</tr>
</tbody>
</table>
<table class="autoupdate cau_status_list widefat striped cau_status_warnings">
<thead>
<tr>
<th colspan="5"><strong><?php _e( 'Systeminfo', 'companion-auto-update' ); ?></strong></th>
</tr>
</thead>
<tbody id="the-list">
<tr>
<td class='cau_status_icon'><span class="dashicons dashicons-wordpress"></span></td>
<td>WordPress</td>
<td><?php echo get_bloginfo( 'version' ); ?></td>
<td></td>
<td></td>
</tr>
<tr <?php if( version_compare( PHP_VERSION, '5.1.0', '<' ) ) { echo "class='inactive'"; } ?>>
<td class='cau_status_icon'><span class="dashicons dashicons-media-code"></span></td>
<td>PHP</td>
<td><?php echo phpversion(); ?> <code>(Required: 5.1.0 or up)</code></td>
<td></td>
<td></td>
</tr>
<tr <?php if( cau_incorrectDatabaseVersion() ) { echo "class='inactive'"; } ?>>
<td class='cau_status_icon'><span class="dashicons dashicons-database"></span></td>
<td>Database</td>
<td><?php echo get_option( "cau_db_version" ); ?> <code>(Latest: <?php echo cau_db_version(); ?>)</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td class='cau_status_icon'><span class="dashicons dashicons-calendar"></span></td>
<td class="cau_status_name"><?php _e( 'Timezone' ); ?></td>
<td class="cau_status_active_state"><?php echo cau_get_proper_timezone(); ?> (GMT <?php echo get_option('gmt_offset'); ?>) - <?php echo date_default_timezone_get(); ?></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<?php
// If has incomptable plugins
if( cau_incompatiblePlugins() ) { ?>
<table class="cau_status_list no_column_width widefat striped cau_status_warnings">
<thead>
<tr>
<th class="cau_plugin_issue_name" colspan="4"><strong><?php _e( 'Possible plugin issues', 'companion-auto-update' ); ?></strong></th>
</tr>
</thead>
<tbody id="the-list">
<?php
foreach ( cau_incompatiblePluginlist() as $key => $value ) {
if( is_plugin_active( $key ) ) {
echo '<tr>
<td class="cau_plugin_issue_name"><strong>'.$key.'</strong></td>
<td colspan="2" class="cau_plugin_issue_explain">'.$value.'</td>
<td class="cau_plugin_issue_fixit"><a href="https://codeermeneer.nl/documentation/known-issues-fixes/#plugins" target="_blank" class="button">'.__( 'How to fix this', 'companion-auto-update' ).'</a></td>
</tr>';
}
}
?>
</tbody>
</table>
<?php } ?>
<!-- Advanced info -->
<table class="autoupdate cau_status_list widefat striped cau_status_warnings">
<thead>
<tr>
<th><strong><?php _e( 'Advanced info', 'companion-auto-update' ); ?></strong> &dash; <?php _e( 'For when you need our help fixing an issue.', 'companion-auto-update' ); ?></th>
</tr>
</thead>
<tbody id="the-list">
<tr>
<td>
<div class='button button-primary toggle_advanced_button'><?php _e( 'Toggle', 'companion-auto-update' ); ?></div>
<div class='toggle_advanced_content' style='display: none;'>
<?php
$cau_configs = $wpdb->get_results( "SELECT * FROM $table_name" );
array_push( $cau_configs, "WordPress: ".get_bloginfo( 'version' ) );
array_push( $cau_configs, "PHP: ".phpversion() );
array_push( $cau_configs, "DB: ".get_option( "cau_db_version" ).' / '.cau_db_version() );
echo "<textarea style='width: 100%; height: 750px;'>";
print_r( $cau_configs );
echo "</textarea>";
?>
</div>
</td>
</tr>
</tbody>
</table>
<script>jQuery( '.toggle_advanced_button' ).click( function() { jQuery( '.toggle_advanced_content' ).toggle(); });</script>
<!-- Delay updates -->
<table class="autoupdate cau_status_list widefat striped cau_status_warnings">
<thead>
<tr>
<th><strong><?php _e( 'Delay updates', 'companion-auto-update' ); ?></strong> &dash; <?php echo ( cau_get_db_value( 'update_delay' ) == 'on' ) ? __( 'Enabled', 'companion-auto-update' ).' ('.sprintf( esc_html__( '%s days', 'companion-auto-update' ).')', cau_get_db_value( 'update_delay_days' ) ) : __( 'Disabled', 'companion-auto-update' ); ?></th>
<th><?php _e( 'Till', 'companion-auto-update' ); ?></th>
</tr>
</thead>
<tbody id="the-list">
<?php
$updateLog = "{$wpdb->prefix}update_log";
$put_on_hold = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$updateLog} WHERE put_on_hold <> '%s'", '0' ) );
foreach ( $put_on_hold as $plugin ) {
$__name = $plugin->slug;
$__poh = $plugin->put_on_hold;
$__udd = ( cau_get_db_value( 'update_delay_days' ) != '' ) ? cau_get_db_value( 'update_delay_days' ) : '2';
$__date = date_i18n( $dateFormat, strtotime( "+".$__udd." days", $__poh ) );
echo "<tr>
<td>{$__name}</td>
<td>{$__date}</td>
</tr>";
}
echo empty( $put_on_hold ) ? "<tr><td>".__( 'No plugins have been put on hold.', 'companion-auto-update' )."</td></tr>" : "";
?>
</tbody>
</table>
</div>
<?php
// Remove the line
if( isset( $_POST['fixit'] ) ) {
check_admin_referer( 'cau_fixit' );
cau_removeErrorLine();
}
// Get wp-config location
function cau_configFile() {
// Config file
if ( file_exists( ABSPATH . 'wp-config.php') ) {
$conFile = ABSPATH . 'wp-config.php';
} else {
$conFile = dirname(ABSPATH) . '/wp-config.php';
}
return $conFile;
}
// Change the AUTOMATIC_UPDATER_DISABLED line
function cau_removeErrorLine() {
// Config file
$conFile = cau_configFile();
// Lines to check and replace
$revLine = "define('AUTOMATIC_UPDATER_DISABLED', false);"; // We could just remove the line, but replacing it will be safer
$posibleLines = array( "define( 'AUTOMATIC_UPDATER_DISABLED', true );", "define( 'AUTOMATIC_UPDATER_DISABLED', minor );" ); // The two base options
foreach ( $posibleLines as $value ) array_push( $posibleLines, strtolower( $value ) ); // Support lowercase variants
foreach ( $posibleLines as $value ) array_push( $posibleLines, str_replace( ' ', '', $value ) ); // For variants without spaces
$melding = __( "We couldn't fix the error for you. Please contact us for further support", 'companion-auto-update' ).'.';
$meldingS = 'error';
// Check for each string if it exists
foreach ( $posibleLines as $key => $string ) {
if( strpos( file_get_contents( $conFile ), $string ) !== false) {
$contents = file_get_contents( $conFile );
$contents = str_replace( $string, $revLine, $contents );
file_put_contents( $conFile, $contents );
$melding = __( "We've fixed the error for you", 'companion-auto-update' ).' :)';
$meldingS = 'updated';
}
}
echo "<div id='message' class='$meldingS'><p><strong>$melding</strong></p></div>";
}

View File

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="417pt"
viewBox="0 -46 417.81333 417"
width="417pt"
version="1.1"
id="svg4"
sodipodi:docname="check.svg"
inkscape:version="0.92.0 r15299">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1017"
id="namedview6"
showgrid="false"
inkscape:zoom="0.42446043"
inkscape:cx="278"
inkscape:cy="278"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
d="m 185.111,248.00297 c -2.2287,2.2418 -5.26943,3.49257 -8.42804,3.49257 -3.15861,0 -6.19935,-1.25077 -8.42805,-3.49257 l -67.30869,-67.31961 c -6.985172,-6.98517 -6.985172,-18.31207 0,-25.28413 l 8.42805,-8.43023 c 6.98735,-6.98518 18.30114,-6.98518 25.28632,0 l 42.02237,42.02454 113.55053,-113.552722 c 6.98736,-6.985172 18.31207,-6.985172 25.28633,0 l 8.42805,8.43023 c 6.98516,6.985175 6.98516,18.309882 0,25.284142 z m 0,0"
id="path2"
style="fill:#9178b7;fill-opacity:1;stroke-width:0.55881381"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 505 505"
style="enable-background:new 0 0 505 505;"
xml:space="preserve"
sodipodi:docname="email.svg"
inkscape:version="0.92.0 r15299"><metadata
id="metadata43"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs41" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview39"
showgrid="false"
inkscape:zoom="0.6608998"
inkscape:cx="-110.05455"
inkscape:cy="410.34145"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1"
borderlayer="true" /><path
style="fill:#ded1f2;fill-opacity:1;stroke-width:1.194754"
d="m 54.471192,356.14658 c 0,-166.66819 135.007198,-301.675388 301.675388,-301.675388 166.5487,0 301.67538,135.007198 301.67538,301.675388 0,166.66817 -135.12668,301.67538 -301.67538,301.67538 -166.66819,0 -301.675388,-135.00721 -301.675388,-301.67538 z"
id="path2"
inkscape:connector-curvature="0" /><g
id="g8"
transform="scale(1.3026177)" /><g
id="g10"
transform="scale(1.3026177)" /><g
id="g12"
transform="scale(1.3026177)" /><g
id="g14"
transform="scale(1.3026177)" /><g
id="g16"
transform="scale(1.3026177)" /><g
id="g18"
transform="scale(1.3026177)" /><g
id="g20"
transform="scale(1.3026177)" /><g
id="g22"
transform="scale(1.3026177)" /><g
id="g24"
transform="scale(1.3026177)" /><g
id="g26"
transform="scale(1.3026177)" /><g
id="g28"
transform="scale(1.3026177)" /><g
id="g30"
transform="scale(1.3026177)" /><g
id="g32"
transform="scale(1.3026177)" /><g
id="g34"
transform="scale(1.3026177)" /><g
id="g36"
transform="scale(1.3026177)" /><path
inkscape:connector-curvature="0"
d="m 281.76716,529.19554 c 27.99462,9.77382 58.38437,-1.99616 72.99376,-26.55557 L 241.14037,462.9714 c -3.82831,28.32342 12.63218,56.45033 40.62679,66.22414 z m 0,0"
id="path4"
style="fill:#9178b7;fill-opacity:1;stroke-width:1.53536594" /><path
inkscape:connector-curvature="0"
d="m 454.97461,381.50764 c -0.0736,-0.0257 -0.11887,-0.0415 -0.18687,-0.0653 -59.67543,-20.8346 -91.29336,-86.33378 -70.45084,-146.03188 5.72511,-16.39813 14.92428,-30.59236 26.36198,-42.26448 -3.29602,-1.51283 -6.65995,-2.92233 -10.15928,-4.14406 -59.766,-20.86622 -125.15573,10.65649 -146.03184,70.45084 l -15.05215,43.11307 c -10.68122,30.59363 -34.17187,54.79029 -64.63445,66.47768 -10.17733,3.96817 -17.38414,13.4202 -18.20325,24.79116 -0.9164,13.28721 8.329,25.17993 20.89938,29.56865 l 251.64586,87.85762 c 13.1706,4.59829 28.58431,0.40642 35.75467,-11.56127 5.54241,-9.2518 5.48702,-20.48337 0.002,-29.68445 -15.90548,-26.7325 -19.22019,-58.96007 -9.94599,-88.50764 z m 0,0"
id="path6"
style="fill:#9178b7;fill-opacity:1;stroke-width:1.53536594" /><path
inkscape:connector-curvature="0"
d="m 569.88056,300.18973 c -14.90587,42.69409 -61.59697,65.2195 -104.29102,50.31364 -42.69409,-14.90587 -65.21947,-61.59696 -50.3136,-104.29106 14.90586,-42.69403 61.59693,-65.21944 104.29101,-50.31357 42.69406,14.90586 65.21947,61.59694 50.31361,104.29099 z m 0,0"
id="path8"
style="fill:#9178b7;fill-opacity:1;stroke-width:1.53536594" /><rect
style="opacity:0.5;fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:5.62767839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4504"
width="768.56519"
height="678.05548"
x="-61.99469"
y="-11.059112" /></svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="512pt"
viewBox="0 0 512 512"
width="512pt"
version="1.1"
id="svg6"
sodipodi:docname="help.svg"
inkscape:version="0.92.0 r15299">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1017"
id="namedview8"
showgrid="false"
inkscape:zoom="0.69140625"
inkscape:cx="132.67442"
inkscape:cy="151.29307"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
d="m 494.10169,605.28813 h -320 c -53.02344,0 -95.999997,-42.97656 -95.999997,-96 v -320 c 0,-53.02344 42.976557,-95.999997 95.999997,-95.999997 h 320 c 53.02344,0 96,42.976557 96,95.999997 v 320 c 0,53.02344 -42.97656,96 -96,96 z m 0,0"
id="path2"
style="fill:#ded1f2;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="m 334.10169,221.28813 c -70.57422,0 -128,57.42578 -128,128 0,70.57422 57.42578,128 128,128 70.57422,0 128,-57.42578 128,-128 0,-70.57422 -57.42578,-128 -128,-128 z m 56,138.67188 h -45.32812 v 45.32812 c 0,5.88672 -4.78516,10.67188 -10.67188,10.67188 -5.88672,0 -10.67187,-4.78516 -10.67187,-10.67188 v -45.32812 h -45.32813 c -5.88672,0 -10.67187,-4.78516 -10.67187,-10.67188 0,-5.88672 4.78515,-10.67187 10.67187,-10.67187 h 45.32813 v -45.32813 c 0,-5.88672 4.78515,-10.67187 10.67187,-10.67187 5.88672,0 10.67188,4.78515 10.67188,10.67187 v 45.32813 h 45.32812 c 5.88672,0 10.67188,4.78515 10.67188,10.67187 0,5.88672 -4.78516,10.67188 -10.67188,10.67188 z m 0,0"
id="path4"
style="fill:#9178b7;fill-opacity:1"
inkscape:connector-curvature="0" />
<rect
style="opacity:0.5;fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:4.51278925;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4504"
width="614.39001"
height="545.42297"
x="38.296513"
y="74.407166" />
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 512 512"
style="enable-background:new 0 0 512 512;"
xml:space="preserve"
width="512"
height="512"
sodipodi:docname="interval.svg"
inkscape:version="0.92.0 r15299"><metadata
id="metadata39"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs37" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1017"
id="namedview35"
showgrid="false"
inkscape:zoom="0.46093749"
inkscape:cx="369.01074"
inkscape:cy="360.3966"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g32" /><g
id="g32"><circle
cx="388.33899"
cy="373.15256"
r="326.50848"
id="circle2"
style="fill:#9178b7;fill-opacity:1;stroke-width:1.27542377" /><path
d="m 388.33899,124.4449 c -137.13356,0 -248.70763,111.57407 -248.70763,248.70763 0,137.13356 111.57407,249.98305 248.70763,249.98305 137.13356,0 248.70763,-112.84949 248.70763,-249.98305 0,-137.13356 -111.57407,-248.70763 -248.70763,-248.70763 z"
id="path6"
inkscape:connector-curvature="0"
style="fill:#eceff1;fill-opacity:1;stroke-width:1.27542377" /><path
d="m 388.33899,200.97033 c -10.57454,0 -19.13136,8.55682 -19.13136,19.13135 v 191.31356 c 0,10.57454 8.55682,19.13136 19.13136,19.13136 10.57454,0 19.13135,-8.55682 19.13135,-19.13136 V 220.10168 c 0,-10.57453 -8.55681,-19.13135 -19.13135,-19.13135 z"
id="path10"
inkscape:connector-curvature="0"
style="fill:#90a4ae;fill-opacity:1;stroke-width:1.27542377" /><path
d="M 503.12712,354.02118 H 388.33899 350.07628 c -10.57454,0 -19.13136,8.55681 -19.13136,19.13135 0,10.57454 8.55682,19.13136 19.13136,19.13136 h 38.26271 114.78813 c 10.57454,0 19.13136,-8.55682 19.13136,-19.13136 0,-10.57454 -8.55682,-19.13135 -19.13136,-19.13135 z"
id="path14"
inkscape:connector-curvature="0"
style="fill:#90a4ae;fill-opacity:1;stroke-width:1.27542377" /><rect
style="opacity:0.5;fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:5.62767839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4504"
width="768.56519"
height="678.05548"
x="-17.638517"
y="36.294277" /></g></svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="Capa_1"
enable-background="new 0 0 512 512"
height="512"
viewBox="0 0 512 512"
width="512"
version="1.1"
sodipodi:docname="love.svg"
inkscape:version="0.92.0 r15299">
<metadata
id="metadata97">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs95" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1017"
id="namedview93"
showgrid="false"
inkscape:zoom="0.4609375"
inkscape:cx="-161.41471"
inkscape:cy="87.761635"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g88" />
<g
id="g90">
<g
id="g88"
transform="matrix(1.941682,0,0,1.941682,-258.91443,105.22034)">
<g
id="g52"
style="fill:#eceff1;fill-opacity:1">
<path
d="m 182.795,15.986 v 165.382 c 0,8.829 7.157,15.986 15.986,15.986 h 20.359 c 2.854,0 5.364,1.885 6.16,4.626 l 11.126,38.317 c 1.404,4.836 7.578,6.242 10.938,2.491 l 38.788,-43.3 c 1.217,-1.358 2.954,-2.134 4.778,-2.134 h 192.658 c 8.829,0 15.986,-7.157 15.986,-15.986 V 15.986 C 499.573,7.157 492.416,0 483.587,0 H 198.781 c -8.829,0 -15.986,7.157 -15.986,15.986 z"
id="path50"
inkscape:connector-curvature="0"
style="fill:#eceff1;fill-opacity:1" />
</g>
<g
id="g64"
style="fill:#9178b7;fill-opacity:1">
<path
d="m 256.62,39.06 6.423,13.015 c 0.54,1.095 1.585,1.854 2.794,2.03 l 14.363,2.087 c 3.043,0.442 4.259,4.182 2.056,6.329 l -10.393,10.131 c -0.875,0.852 -1.274,2.081 -1.067,3.284 l 2.453,14.305 c 0.52,3.031 -2.662,5.343 -5.384,3.911 l -12.847,-6.754 c -1.081,-0.568 -2.372,-0.568 -3.453,0 l -12.847,6.754 c -2.722,1.431 -5.904,-0.88 -5.384,-3.911 l 2.453,-14.305 c 0.206,-1.204 -0.193,-2.432 -1.067,-3.284 L 224.327,62.521 c -2.202,-2.147 -0.987,-5.887 2.056,-6.329 l 14.363,-2.087 c 1.209,-0.176 2.253,-0.935 2.794,-2.03 l 6.423,-13.015 c 1.364,-2.758 5.296,-2.758 6.657,0 z"
id="path58"
inkscape:connector-curvature="0"
style="fill:#9178b7;fill-opacity:1" />
<path
d="m 344.511,39.06 6.423,13.015 c 0.54,1.095 1.585,1.854 2.794,2.03 l 14.363,2.087 c 3.043,0.442 4.259,4.182 2.056,6.329 l -10.393,10.131 c -0.875,0.852 -1.274,2.081 -1.067,3.284 l 2.453,14.305 c 0.52,3.031 -2.662,5.343 -5.384,3.911 l -12.847,-6.754 c -1.081,-0.568 -2.372,-0.568 -3.453,0 l -12.847,6.754 c -2.722,1.431 -5.904,-0.88 -5.384,-3.911 l 2.453,-14.305 c 0.206,-1.204 -0.193,-2.432 -1.067,-3.284 L 312.22,62.521 c -2.202,-2.147 -0.987,-5.887 2.056,-6.329 l 14.363,-2.087 c 1.209,-0.176 2.253,-0.935 2.794,-2.03 l 6.423,-13.015 c 1.362,-2.758 5.294,-2.758 6.655,0 z"
id="path60"
inkscape:connector-curvature="0"
style="fill:#9178b7;fill-opacity:1" />
<path
d="m 432.402,39.06 6.423,13.015 c 0.54,1.095 1.585,1.854 2.794,2.03 l 14.363,2.087 c 3.043,0.442 4.259,4.182 2.056,6.329 l -10.393,10.131 c -0.874,0.852 -1.274,2.081 -1.067,3.284 l 2.453,14.305 c 0.52,3.031 -2.662,5.343 -5.384,3.911 L 430.8,87.398 c -1.081,-0.568 -2.372,-0.568 -3.453,0 L 414.5,94.152 c -2.722,1.431 -5.904,-0.88 -5.384,-3.911 l 2.453,-14.305 c 0.206,-1.204 -0.193,-2.432 -1.067,-3.284 L 400.109,62.521 c -2.202,-2.147 -0.987,-5.887 2.056,-6.329 l 14.363,-2.087 c 1.209,-0.176 2.253,-0.935 2.794,-2.03 l 6.423,-13.015 c 1.363,-2.758 5.296,-2.758 6.657,0 z"
id="path62"
inkscape:connector-curvature="0"
style="fill:#9178b7;fill-opacity:1" />
</g>
<g
id="g76" />
<g
id="g86">
<g
id="g80"
style="fill:#90a4ae;fill-opacity:1">
<path
d="M 459.163,137.933 H 220.989 c -4.142,0 -7.5,-3.358 -7.5,-7.5 0,-4.142 3.358,-7.5 7.5,-7.5 h 238.174 c 4.142,0 7.5,3.358 7.5,7.5 0,4.142 -3.358,7.5 -7.5,7.5 z"
id="path78"
inkscape:connector-curvature="0"
style="fill:#90a4ae;fill-opacity:1" />
</g>
<g
id="g84"
style="fill:#90a4ae;fill-opacity:1;stroke:none;stroke-opacity:1">
<path
d="M 340.076,167.863 H 220.989 c -4.142,0 -7.5,-3.358 -7.5,-7.5 0,-4.142 3.358,-7.5 7.5,-7.5 h 119.087 c 4.142,0 7.5,3.358 7.5,7.5 0,4.142 -3.358,7.5 -7.5,7.5 z"
id="path82"
inkscape:connector-curvature="0"
style="fill:#90a4ae;fill-opacity:1;stroke:none;stroke-opacity:1" />
</g>
</g>
<rect
style="opacity:0.5;fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:2.89835215;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4504"
width="395.82443"
height="349.21036"
x="139.90385"
y="-53.375328" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 505 505"
style="enable-background:new 0 0 505 505;"
xml:space="preserve"
sodipodi:docname="settings.svg"
inkscape:version="0.92.0 r15299"><metadata
id="metadata43"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs41" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview39"
showgrid="false"
inkscape:zoom="0.3304499"
inkscape:cx="-433.02666"
inkscape:cy="120.52743"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" /><path
style="fill:#ded1f2;fill-opacity:1;stroke-width:1.194754"
d="m 54.471192,356.14658 c 0,-166.66819 135.007198,-301.675388 301.675388,-301.675388 166.5487,0 301.67538,135.007198 301.67538,301.675388 0,166.66817 -135.12668,301.67538 -301.67538,301.67538 -166.66819,0 -301.675388,-135.00721 -301.675388,-301.67538 z"
id="path2"
inkscape:connector-curvature="0" /><g
id="g8"
transform="scale(1.3026177)" /><g
id="g10"
transform="scale(1.3026177)" /><g
id="g12"
transform="scale(1.3026177)" /><g
id="g14"
transform="scale(1.3026177)" /><g
id="g16"
transform="scale(1.3026177)" /><g
id="g18"
transform="scale(1.3026177)" /><g
id="g20"
transform="scale(1.3026177)" /><g
id="g22"
transform="scale(1.3026177)" /><g
id="g24"
transform="scale(1.3026177)" /><g
id="g26"
transform="scale(1.3026177)" /><g
id="g28"
transform="scale(1.3026177)" /><g
id="g30"
transform="scale(1.3026177)" /><g
id="g32"
transform="scale(1.3026177)" /><g
id="g34"
transform="scale(1.3026177)" /><g
id="g36"
transform="scale(1.3026177)" /><g
transform="translate(107.14129,82.560247)"
id="g8-7"
style="fill:#90a4ae;fill-opacity:1" /><g
transform="translate(107.14129,82.560247)"
id="g48" /><g
transform="translate(107.14129,82.560247)"
id="g50" /><g
transform="translate(107.14129,82.560247)"
id="g52" /><g
transform="translate(107.14129,82.560247)"
id="g54" /><g
transform="translate(107.14129,82.560247)"
id="g56" /><g
transform="translate(107.14129,82.560247)"
id="g58" /><g
transform="translate(107.14129,82.560247)"
id="g60" /><g
transform="translate(107.14129,82.560247)"
id="g62" /><g
transform="translate(107.14129,82.560247)"
id="g64" /><g
transform="translate(107.14129,82.560247)"
id="g66" /><g
transform="translate(107.14129,82.560247)"
id="g68" /><g
transform="translate(107.14129,82.560247)"
id="g70" /><g
transform="translate(107.14129,82.560247)"
id="g72" /><g
transform="translate(107.14129,82.560247)"
id="g74" /><g
transform="translate(107.14129,82.560247)"
id="g76" /><path
inkscape:connector-curvature="0"
d="m 407.30702,633.58604 h -30.82827 c -24.93373,0 -45.22015,-20.28545 -45.22015,-45.21919 v -10.42958 c -10.60035,-3.38666 -20.89946,-7.66173 -30.79371,-12.78202 l -7.39118,7.39117 c -17.90135,17.92343 -46.57672,17.39768 -63.95808,-0.007 L 207.3268,550.75171 c -17.41207,-17.39287 -17.91288,-46.05864 0.006,-63.95809 l 7.38543,-7.38542 c -5.12029,-9.89424 -9.3944,-20.19143 -12.78202,-30.79371 h -10.42863 c -24.93276,0 -45.21918,-20.28546 -45.21918,-45.21918 v -30.82908 c 0,-24.93372 20.28642,-45.21919 45.22014,-45.21919 h 10.42862 c 3.38764,-10.60132 7.66174,-20.89946 12.78203,-30.79371 l -7.39118,-7.39022 c -17.90807,-17.88889 -17.41399,-46.55754 0.006,-63.95809 l 21.79075,-21.78979 c 17.42166,-17.44565 46.0903,-17.88122 63.95713,0.006 l 7.38447,7.38446 c 9.89423,-5.11933 20.19335,-9.3944 30.7937,-12.78202 v -10.42863 c 0,-24.93373 20.28546,-45.21918 45.22014,-45.21918 h 30.82827 c 24.93373,0 45.21919,20.28545 45.21919,45.21918 v 10.42958 c 10.60035,3.38667 20.89946,7.66174 30.7937,12.78203 l 7.39119,-7.39118 c 17.90135,-17.92343 46.57672,-17.39768 63.95809,0.007 l 21.78882,21.78787 c 17.41207,17.39289 17.91287,46.05866 -0.009,63.9581 l -7.38543,7.38542 c 5.12029,9.89425 9.3944,20.19143 12.78202,30.79371 h 10.42864 c 24.93372,0 45.22013,20.28546 45.22013,45.21919 v 30.8292 c 0,24.93373 -20.28641,45.21919 -45.22013,45.21919 h -10.42864 c -3.38762,10.60132 -7.66173,20.89946 -12.78202,30.7937 l 7.39119,7.39119 c 17.90806,17.88888 17.41397,46.55754 -0.009,63.95809 l -21.79074,21.78978 c -17.42166,17.44565 -46.09031,17.88122 -63.95713,-0.006 l -7.38447,-7.38447 c -9.89424,5.11933 -20.19335,9.3944 -30.7937,12.78202 v 10.42959 c 0,24.93181 -20.28546,45.21726 -45.22014,45.21726 z M 305.27626,534.93141 c 13.74525,8.12896 28.53914,14.27005 43.97005,18.2525 6.35504,1.63961 10.79512,7.37104 10.79512,13.93426 v 21.24868 c 0,9.06341 7.37486,16.43733 16.43827,16.43733 h 30.82828 c 9.0634,0 16.43827,-7.37392 16.43827,-16.43733 v -21.24868 c 0,-6.56322 4.44008,-12.29465 10.79512,-13.93426 15.43091,-3.98245 30.2248,-10.12354 43.97005,-18.2525 5.65564,-3.34445 12.8559,-2.43494 17.50224,2.21141 l 15.05101,15.05196 c 6.48934,6.49702 16.91029,6.34639 23.24039,0.007 l 21.80417,-21.80321 c 6.31474,-6.30707 6.5258,-16.72994 0.009,-23.24136 L 541.06052,492.0995 c -4.6454,-4.64538 -5.5549,-11.8466 -2.21141,-17.50128 8.12895,-13.7443 14.26908,-28.53818 18.25154,-43.97005 1.64057,-6.35504 7.37199,-10.79416 13.93425,-10.79416 h 21.24774 c 9.06341,0 16.43827,-7.37391 16.43827,-16.43732 v -30.82921 c 0,-9.06341 -7.37486,-16.43731 -16.43827,-16.43731 H 571.0349 c -6.56322,0 -12.29368,-4.44009 -13.93425,-10.79416 -3.98246,-15.43188 -10.12355,-30.22576 -18.25154,-43.97005 -3.34349,-5.65468 -2.43399,-12.8559 2.21141,-17.50129 l 15.05195,-15.05195 c 6.50661,-6.49895 6.3368,-16.91798 0.009,-23.24136 l -21.80131,-21.80239 c -6.31955,-6.32818 -16.74241,-6.51334 -23.24136,-0.006 l -15.05675,15.05771 c -4.64539,4.64634 -11.84853,5.55586 -17.50224,2.21141 -13.74526,-8.12897 -28.53914,-14.27005 -43.97006,-18.25251 -6.35502,-1.6396 -10.79512,-7.37103 -10.79512,-13.93426 v -21.2506 c 0,-9.06341 -7.37486,-16.43733 -16.43827,-16.43733 h -30.82827 c -9.06341,0 -16.43828,7.37392 -16.43828,16.43733 v 21.24868 c 0,6.56323 -4.44008,12.29467 -10.79512,13.93427 -15.43091,3.98245 -30.22479,10.12354 -43.97004,18.2525 -5.6566,3.34348 -12.85686,2.43398 -17.50225,-2.21141 L 272.73141,223.7668 c -6.48936,-6.49702 -16.91126,-6.34639 -23.2404,-0.007 l -21.80418,21.80322 c -6.31473,6.30707 -6.5258,16.72898 -0.006,23.24136 l 15.05771,15.05771 c 4.64538,4.64539 5.55489,11.84661 2.2114,17.50128 -8.12896,13.7443 -14.26909,28.53818 -18.25154,43.97005 -1.64056,6.35503 -7.372,10.79415 -13.93426,10.79415 h -21.24868 c -9.06341,9.7e-4 -16.43829,7.37488 -16.43829,16.43829 v 30.82921 c 0,9.06341 7.37488,16.43731 16.43829,16.43731 h 21.24772 c 6.56322,0 12.2937,4.44008 13.93426,10.79416 3.98245,15.43188 10.12354,30.22576 18.25154,43.97005 3.34349,5.65468 2.43398,12.8559 -2.2114,17.50129 l -15.05196,15.05195 c -6.50662,6.49895 -6.33681,16.91798 -0.006,23.24136 l 21.80225,21.80225 c 6.31954,6.32818 16.74241,6.51335 23.24136,0.006 l 15.05674,-15.05771 c 3.42313,-3.42215 10.54472,-6.32625 17.50321,-2.21044 z"
id="path2-7"
style="fill:#9178b7;fill-opacity:1;stroke-width:0.95939529" /><path
inkscape:connector-curvature="0"
d="m 391.89337,494.85747 c -58.9328,0 -106.87666,-47.94482 -106.87666,-106.87664 0,-58.93182 47.94386,-106.87664 106.87666,-106.87664 58.93278,0 106.87664,47.94482 106.87664,106.87664 0,58.93182 -47.94386,106.87664 -106.87664,106.87664 z m 0,-184.97142 c -43.06248,0 -78.0948,35.03329 -78.0948,78.09478 0,43.0615 35.03328,78.09478 78.0948,78.09478 43.0615,0 78.09478,-35.03328 78.09478,-78.09478 0,-43.06149 -35.03232,-78.09478 -78.09478,-78.09478 z"
id="path4-6"
style="fill:#9178b7;fill-opacity:1;stroke-width:0.95939529" /><rect
style="opacity:0.5;fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:5.62767839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4504"
width="768.56519"
height="678.05548"
x="-25.146145"
y="32.319691" /></svg>

Before

Width:  |  Height:  |  Size: 9.3 KiB

View File

@ -1,102 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 512 512"
style="enable-background:new 0 0 512 512;"
xml:space="preserve"
sodipodi:docname="support.svg"
inkscape:version="0.92.0 r15299"><metadata
id="metadata75"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs73" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1017"
id="namedview71"
showgrid="false"
inkscape:zoom="0.92187498"
inkscape:cx="127.5288"
inkscape:cy="162.24021"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g22" /><path
style="fill:#9178b7;fill-opacity:1;stroke:none"
d="m 374.18666,111.86429 c -136.624,0 -247.29601,110.672 -247.29601,247.296 0,136.624 110.67201,247.296 247.29601,247.296 136.624,0 247.296,-110.672 247.296,-247.296 0,-136.624 -110.672,-247.296 -247.296,-247.296 z m 0,368.576 c -66.928,0 -121.12,-54.336 -121.12,-121.264 0,-66.928 54.192,-121.12 121.12,-121.12 66.928,0 121.264,54.192 121.264,121.12 0.016,66.912 -54.336,121.264 -121.264,121.264 z"
id="path10"
inkscape:connector-curvature="0" /><g
id="g22"
transform="translate(81.305295,78.237171)"
style="stroke:none"><path
style="fill:#eceff1;fill-opacity:1;stroke:#eceff1;stroke-opacity:1"
d="m 195.61736,53.531119 53.776,114.448001 c 13.504,-5.2 28.128,-8.16 43.488,-8.16 15.344,0 29.968,2.96 43.488,8.16 l 53.776,-114.448001 c -29.856,-12.784 -62.72,-19.904 -97.264,-19.904 -34.544,0 -67.408,7.12 -97.264,19.904 z"
id="path14"
inkscape:connector-curvature="0" /><path
style="fill:#eceff1;fill-opacity:1;stroke:#eceff1;stroke-opacity:1"
d="m 171.76136,280.92312 c 0,-15.36 2.976,-29.984 8.176,-43.488 l -114.448003,-53.776 c -12.784,29.856 -19.904,62.72 -19.904,97.264 0,34.544 7.12,67.408 19.904,97.264 l 114.432003,-53.776 c -5.184,-13.52 -8.16,-28.144 -8.16,-43.488 z"
id="path16"
inkscape:connector-curvature="0" /><path
style="fill:#eceff1;fill-opacity:1;stroke:#eceff1;stroke-opacity:1"
d="m 390.14536,508.31512 -53.728,-114.32 c -13.536,5.216 -28.176,8.208 -43.536,8.208 -15.376,0 -30.016,-2.992 -43.552,-8.208 l -53.728,114.336 c 29.856,12.784 62.72,19.904 97.264,19.904 34.56,-0.016 67.424,-7.136 97.28,-19.92 z"
id="path18"
inkscape:connector-curvature="0" /><path
style="fill:#eceff1;fill-opacity:1;stroke:#eceff1;stroke-opacity:1"
d="m 414.16136,280.92312 c 0,15.36 -2.976,30 -8.208,43.536 l 114.32,53.728 c 12.784,-29.856 19.904,-62.72 19.904,-97.264 0,-34.544 -7.12,-67.408 -19.904,-97.264 l -114.336,53.728 c 5.232,13.52 8.224,28.176 8.224,43.536 z"
id="path20"
inkscape:connector-curvature="0" /><rect
style="opacity:0.5;fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:5.62767839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4504"
width="768.56519"
height="678.05548"
x="-178.1302"
y="-39.773388" /></g><g
id="g40"
transform="translate(81.305295,78.237171)" /><g
id="g42"
transform="translate(81.305295,78.237171)" /><g
id="g44"
transform="translate(81.305295,78.237171)" /><g
id="g46"
transform="translate(81.305295,78.237171)" /><g
id="g48"
transform="translate(81.305295,78.237171)" /><g
id="g50"
transform="translate(81.305295,78.237171)" /><g
id="g52"
transform="translate(81.305295,78.237171)" /><g
id="g54"
transform="translate(81.305295,78.237171)" /><g
id="g56"
transform="translate(81.305295,78.237171)" /><g
id="g58"
transform="translate(81.305295,78.237171)" /><g
id="g60"
transform="translate(81.305295,78.237171)" /><g
id="g62"
transform="translate(81.305295,78.237171)" /><g
id="g64"
transform="translate(81.305295,78.237171)" /><g
id="g66"
transform="translate(81.305295,78.237171)" /><g
id="g68"
transform="translate(81.305295,78.237171)" /></svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 505 505"
style="enable-background:new 0 0 505 505;"
xml:space="preserve"
sodipodi:docname="update.svg"
inkscape:version="0.92.0 r15299"><metadata
id="metadata43"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs41" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1017"
id="namedview39"
showgrid="false"
inkscape:zoom="0.6608998"
inkscape:cx="-41.965565"
inkscape:cy="289.29436"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" /><path
style="fill:#ded1f2;fill-opacity:1;stroke-width:1.194754"
d="m 54.471192,356.14658 c 0,-166.66819 135.007198,-301.675388 301.675388,-301.675388 166.5487,0 301.67538,135.007198 301.67538,301.675388 0,166.66817 -135.12668,301.67538 -301.67538,301.67538 -166.66819,0 -301.675388,-135.00721 -301.675388,-301.67538 z"
id="path2"
inkscape:connector-curvature="0" /><path
style="fill:#9178b7;fill-opacity:1;stroke-width:1.194754"
d="m 287.44822,389.59968 h 18.51868 c 14.33706,0 22.46138,-16.36813 13.85915,-27.83776 l -72.64104,-95.81927 c -6.92957,-9.19961 -20.78872,-9.19961 -27.71829,0 l -72.64105,95.81927 c -8.7217,11.46963 -0.4779,27.83776 13.85915,27.83776 h 16.72655 c 26.04564,120.07278 140.50308,170.25245 226.16694,142.7731 7.52694,-2.3895 6.09324,-13.50072 -1.91161,-14.09809 -78.97324,-5.73482 -122.58176,-74.55265 -114.21848,-128.67501 z"
id="path4"
inkscape:connector-curvature="0" /><path
style="fill:#9178b7;fill-opacity:1;stroke-width:1.194754"
d="m 424.84493,322.69346 h -18.51869 c -14.33705,0 -22.46137,16.36813 -13.85914,27.83777 l 72.64104,95.93875 c 6.92957,9.19961 20.78871,9.19961 27.71829,0 l 72.64104,-95.93875 c 8.7217,-11.46964 0.4779,-27.83777 -13.85914,-27.83777 H 534.88177 C 508.71666,202.62069 394.25922,152.44102 308.59536,179.92036 c -7.52695,2.38951 -6.09324,13.50072 1.91161,14.0981 79.09271,5.73482 122.70123,74.55265 114.33796,128.675 z"
id="path6"
inkscape:connector-curvature="0" /><g
id="g8"
transform="scale(1.3026177)" /><g
id="g10"
transform="scale(1.3026177)" /><g
id="g12"
transform="scale(1.3026177)" /><g
id="g14"
transform="scale(1.3026177)" /><g
id="g16"
transform="scale(1.3026177)" /><g
id="g18"
transform="scale(1.3026177)" /><g
id="g20"
transform="scale(1.3026177)" /><g
id="g22"
transform="scale(1.3026177)" /><g
id="g24"
transform="scale(1.3026177)" /><g
id="g26"
transform="scale(1.3026177)" /><g
id="g28"
transform="scale(1.3026177)" /><g
id="g30"
transform="scale(1.3026177)" /><g
id="g32"
transform="scale(1.3026177)" /><g
id="g34"
transform="scale(1.3026177)" /><g
id="g36"
transform="scale(1.3026177)" /><rect
style="opacity:0.5;fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:5.62767839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4504"
width="768.56519"
height="678.05548"
x="-71.073227"
y="-6.5198488" /></svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,181 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 512.001 512.001"
style="enable-background:new 0 0 512.001 512.001;"
xml:space="preserve"
sodipodi:docname="welcome.svg"
inkscape:version="0.92.0 r15299"><metadata
id="metadata99"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs97" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview95"
showgrid="false"
inkscape:zoom="1.3037256"
inkscape:cx="154.95189"
inkscape:cy="223.3697"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" /><circle
style="fill:#ded1f2;fill-opacity:1;stroke-width:0.8621738"
cx="256.00003"
cy="252.93185"
r="220.71649"
id="circle2" /><g
id="g20"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)"><path
style="fill:#34abe0"
d="m 469.869,206.196 c -3.882,0 -7.029,-3.147 -7.029,-7.029 v -11.259 c 0,-3.882 3.147,-7.029 7.029,-7.029 3.882,0 7.029,3.147 7.029,7.029 v 11.259 c -0.001,3.883 -3.148,7.029 -7.029,7.029 z"
id="path4"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0"
d="m 469.869,263.776 c -3.882,0 -7.029,-3.147 -7.029,-7.029 V 245.49 c 0,-3.882 3.147,-7.029 7.029,-7.029 3.882,0 7.029,3.147 7.029,7.029 v 11.258 c -0.001,3.881 -3.148,7.028 -7.029,7.028 z"
id="path6"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0"
d="m 504.288,229.358 h -11.259 c -3.882,0 -7.029,-3.147 -7.029,-7.029 0,-3.882 3.147,-7.029 7.029,-7.029 h 11.259 c 3.882,0 7.029,3.147 7.029,7.029 0,3.881 -3.148,7.029 -7.029,7.029 z"
id="path8"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0"
d="M 446.707,229.358 H 435.45 c -3.882,0 -7.029,-3.147 -7.029,-7.029 0,-3.882 3.147,-7.029 7.029,-7.029 h 11.258 c 3.882,0 7.029,3.147 7.029,7.029 -0.002,3.881 -3.148,7.029 -7.03,7.029 z"
id="path10"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0"
d="m 391.867,22.724 c -3.882,0 -7.029,-3.147 -7.029,-7.029 V 7.029 c 0,-3.882 3.147,-7.029 7.029,-7.029 3.882,0 7.029,3.147 7.029,7.029 v 8.666 c 0,3.883 -3.147,7.029 -7.029,7.029 z"
id="path12"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0"
d="m 391.867,67.048 c -3.882,0 -7.029,-3.147 -7.029,-7.029 v -8.666 c 0,-3.882 3.147,-7.029 7.029,-7.029 3.882,0 7.029,3.147 7.029,7.029 v 8.666 c 0,3.882 -3.147,7.029 -7.029,7.029 z"
id="path14"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0"
d="m 418.362,40.553 h -8.666 c -3.882,0 -7.029,-3.147 -7.029,-7.029 0,-3.882 3.147,-7.029 7.029,-7.029 h 8.666 c 3.882,0 7.029,3.147 7.029,7.029 0,3.882 -3.147,7.029 -7.029,7.029 z"
id="path16"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0"
d="m 374.038,40.553 h -8.666 c -3.882,0 -7.029,-3.147 -7.029,-7.029 0,-3.882 3.147,-7.029 7.029,-7.029 h 8.666 c 3.882,0 7.029,3.147 7.029,7.029 0,3.882 -3.147,7.029 -7.029,7.029 z"
id="path18"
inkscape:connector-curvature="0" /></g><path
style="fill:#9178b7;fill-opacity:1;stroke-width:0.8621738"
d="m 298.98111,139.77931 c -1.09841,0 -2.21061,-0.29831 -3.21073,-0.92511 -2.83569,-1.77694 -3.69529,-5.51619 -1.9192,-8.35187 8.88986,-14.19398 16.29077,-28.09049 21.99663,-41.303308 1.32689,-3.071925 4.89112,-4.486752 7.96563,-3.160729 3.07192,1.326886 4.48762,4.893699 3.15987,7.965625 -5.94815,13.774092 -13.63787,28.218092 -22.85278,42.931942 -1.14842,1.83643 -3.12107,2.84345 -5.13942,2.84345 z"
id="path22"
inkscape:connector-curvature="0" /><path
style="fill:#34abe0;stroke-width:0.8621738"
d="m 221.49065,234.60809 c -1.61572,0 -3.22798,-0.64233 -4.42037,-1.91403 -2.28993,-2.44081 -2.1675,-6.27489 0.27331,-8.56569 0.27849,-0.26124 28.13963,-26.53427 55.9456,-63.72931 2.00368,-2.6805 5.80157,-3.2297 8.48293,-1.22514 2.68049,2.00368 3.22884,5.80156 1.22514,8.48291 -28.47845,38.09258 -56.19562,64.21816 -57.36214,65.3114 -1.17083,1.09583 -2.65895,1.63986 -4.14447,1.63986 z"
id="path24"
inkscape:connector-curvature="0" /><path
style="fill:#f9f9f9;stroke-width:0.8621738"
d="m 275.09631,243.34881 c -1.64503,0 -3.28488,-0.6656 -4.47986,-1.97782 -2.25372,-2.47358 -2.07784,-6.30594 0.3966,-8.5614 28.21033,-25.71433 84.0654,-71.36126 141.18269,-88.17193 3.20988,-0.94408 6.57925,0.89148 7.52419,4.10223 0.94495,3.21073 -0.89149,6.57924 -4.10222,7.52419 -54.78597,16.12438 -108.99946,60.49098 -136.43987,85.50264 -1.16308,1.05961 -2.62446,1.58209 -4.08153,1.58209 z"
id="path26"
inkscape:connector-curvature="0" /><g
id="g32"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)"><path
style="fill:#9178b7;fill-opacity:1"
d="m 290.023,308.794 c -2.069,0 -4.119,-0.909 -5.507,-2.655 -2.416,-3.039 -1.91,-7.461 1.128,-9.875 2.334,-1.855 58.024,-45.266 133.17,-30.816 3.812,0.732 6.308,4.417 5.575,8.229 -0.732,3.813 -4.415,6.314 -8.229,5.575 -68.879,-13.246 -121.248,27.602 -121.769,28.017 -1.292,1.025 -2.835,1.525 -4.368,1.525 z"
id="path28"
inkscape:connector-curvature="0" /><path
style="fill:#9178b7;fill-opacity:1"
d="m 194.779,177.404 c -1.061,0 -2.137,-0.24 -3.148,-0.749 -3.469,-1.742 -4.869,-5.966 -3.126,-9.435 11.361,-22.624 23.205,-58.429 15.111,-100.516 -0.734,-3.812 1.763,-7.496 5.575,-8.229 3.811,-0.734 7.496,1.763 8.229,5.575 8.84,45.966 -4.013,84.906 -16.353,109.479 -1.234,2.456 -3.713,3.875 -6.288,3.875 z"
id="path30"
inkscape:connector-curvature="0" /></g><path
style="fill:#f9f9f9;stroke-width:0.8621738"
d="m 282.19114,351.70423 -99.61988,49.64742 -57.9993,28.91818 C 95.167528,408.4413 71.374975,379.46881 55.771353,345.91991 l 9.59427,-19.25148 45.683997,-91.6646 18.10738,-36.33287 z"
id="path34"
inkscape:connector-curvature="0" /><g
id="g42"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)"><path
style="fill:#9178b7;fill-opacity:1"
d="M 76.667,438.689 C 54.839,417.258 36.825,391.94 23.764,363.864 v -0.01 l 11.139,-22.329 z"
id="path38"
inkscape:connector-curvature="0" /><polygon
style="fill:#9178b7;fill-opacity:1"
points="170.839,428.138 152.074,384.51 87.885,235.211 108.888,193.068 237.301,321.481 286.379,370.559 "
id="polygon40" /></g><path
style="fill:#f9f9f9;stroke-width:0.8621738"
d="M 268.15494,353.91226 126.94639,212.70371 c -6.84393,-6.84395 -6.84393,-17.93926 0,-24.78319 v 0 c 6.84394,-6.84394 17.93925,-6.84394 24.78318,0 l 141.2077,141.20769 c 6.84394,6.84393 6.84394,17.93925 0,24.78318 v 0 c -6.84308,6.84394 -17.93925,6.84394 -24.78233,8.7e-4 z"
id="path46"
inkscape:connector-curvature="0" /><circle
style="fill:#f9f9f9;stroke-width:0.8621738"
cx="176.15497"
cy="142.5831"
r="6.0602198"
id="circle50" /><circle
style="fill:#9178b7;fill-opacity:1;stroke-width:0.8621738"
cx="257.1355"
cy="119.44839"
r="6.0602198"
id="circle52" /><circle
style="fill:#34abe0;stroke-width:0.8621738"
cx="356.29495"
cy="137.62819"
r="6.0602198"
id="circle54" /><g
id="g60"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)"><circle
style="fill:#f9f9f9"
cx="372.328"
cy="323.53201"
r="7.0289998"
id="circle56" /><path
style="fill:#f9f9f9"
d="m 254.9,10.029 8.735,7.769 c 0.739,0.657 1.753,0.909 2.714,0.673 L 277.7,15.68 c 2.418,-0.595 4.468,1.841 3.469,4.122 l -4.69,10.708 c -0.397,0.906 -0.322,1.949 0.199,2.789 l 6.163,9.934 c 1.312,2.116 -0.371,4.818 -2.848,4.574 L 268.36,46.656 c -0.984,-0.097 -1.953,0.296 -2.59,1.051 l -7.543,8.931 c -1.607,1.902 -4.697,1.136 -5.23,-1.296 l -2.5,-11.42 c -0.211,-0.965 -0.885,-1.766 -1.8,-2.139 l -10.824,-4.415 c -2.305,-0.94 -2.532,-4.116 -0.383,-5.374 l 10.088,-5.907 c 0.854,-0.499 1.406,-1.387 1.479,-2.373 l 0.854,-11.659 c 0.178,-2.483 3.128,-3.681 4.989,-2.026 z"
id="path58"
inkscape:connector-curvature="0" /></g><path
style="fill:#9178b7;fill-opacity:1;stroke-width:0.8621738"
d="m 454.29051,92.257154 5.2722,11.110836 c 0.44574,0.93977 1.32516,1.60019 2.35201,1.76486 l 12.14113,1.95542 c 2.58566,0.41643 3.57199,3.61768 1.66831,5.41703 l -8.93729,8.44672 c -0.75613,0.71474 -1.11134,1.75453 -0.95184,2.7831 l 1.89161,12.15148 c 0.40263,2.58824 -2.3365,4.51434 -4.63592,3.25987 l -10.79527,-5.89036 c -0.91391,-0.49834 -2.01232,-0.51559 -2.94088,-0.0448 l -10.97202,5.55411 c -2.33649,1.18291 -5.01613,-0.82682 -4.53331,-3.40213 l 2.26579,-12.08682 c 0.19226,-1.02253 -0.13278,-2.07352 -0.86562,-2.81069 l -8.67261,-8.71916 c -1.84677,-1.85712 -0.76303,-5.02561 1.83384,-5.36272 l 12.19545,-1.58036 c 1.03117,-0.13364 1.93127,-0.76648 2.40633,-1.69159 l 5.61276,-10.941845 c 1.19323,-2.331318 4.54279,-2.278727 5.66533,0.08708 z"
id="path62"
inkscape:connector-curvature="0" /><g
id="g64"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g66"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g68"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g70"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g72"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g74"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g76"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g78"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g80"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g82"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g84"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g86"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g88"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g90"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /><g
id="g92"
transform="matrix(0.86217384,0,0,0.86217384,35.283516,32.215367)" /></svg>

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,582 +0,0 @@
/* Default Stylings */
.nowrap {
white-space: nowrap;
}
.cau_spacing {
height: 25px;
}
.cau_support_buttons {
display: inline-block;
}
/* Welcome screen */
.welcome-to-cau {
background: #FFF;
border: 1px solid #CCD0D4;
margin: 25px 0;
padding: 30px;
background-size: 140px;
background-position: left bottom;
background-repeat: no-repeat;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
}
.welcome-to-cau .welcome-image {
display: inline-block;
vertical-align: middle;
width: 100px;
height: 100px;
background-image: url('images/welcome.svg');
background-size: contain;
background-position: center;
box-sizing: border-box;
}
.welcome-to-cau .welcome-content {
display: inline-block;
vertical-align: middle;
width: calc(100% - 100px);
padding-left: 25px;
box-sizing: border-box;
}
.welcome-to-cau .welcome-content strong {
color: #000;
}
.welcome-to-cau .welcome-content p {
margin: 2px 0;
}
.welcome-to-cau.help-bg {
background-image: url('images/help.svg');
}
.welcome-to-cau.support-bg {
background-image: url('images/support.svg');
}
.welcome-to-cau.love-bg {
background-image: url('images/love.svg');
}
.welcome-to-cau.update-bg {
background-image: url('images/update.svg');
}
.welcome-to-cau.email-bg {
background-image: url('images/email.svg');
}
.welcome-to-cau.interval-bg {
background-image: url('images/interval.svg');
}
.welcome-to-cau.advanced-bg {
background-image: url('images/settings.svg');
}
.welcome-to-cau h2 {
margin: 0;
margin-bottom: 25px;
font-size: 21px;
font-weight: 400;
line-height: 1.2;
}
.welcome-to-cau h2.title {
margin-bottom: 10px;
}
.welcome-to-cau h3 {
font-size: 16px;
margin-top: 0;
}
.welcome-to-cau a {
text-decoration: none;
}
.welcome-to-cau .welcome-column {
display: inline-block;
vertical-align: top;
box-sizing: border-box;
}
.welcome-to-cau.cau-show-love .welcome-column {
vertical-align: middle;
}
.welcome-to-cau .welcome-column.welcome-column-first {
display: block;
width: 100%;
}
.first-column {
padding-left: 140px;
}
.welcome-to-cau .welcome-column.welcome-column-half {
width: 50%;
}
.welcome-to-cau .welcome-column.welcome-column-third {
width: 33%;
}
.welcome-to-cau .welcome-column.welcome-column-quarter {
width: 25%;
}
.welcome-to-cau a.minimal-button {
display: inline-block;
padding: 5px;
}
select.schedule_interval {
max-width: 90%;
width: 225px;
}
.cau_save_button.fixed_button {
background: #FFF;
box-sizing: border-box;
position: fixed;
width: 100%;
right: 0;
bottom: 0;
margin-left: -25px;
z-index: 1001;
padding: 5px;
box-shadow: 0 -8px 16px 0 rgb(85 93 102 / 30%);
}
.cau_save_button.fixed_button p.submit {
display: block;
text-align: center;
font-weight: bold;
margin: 0;
padding: 0;
}
.cau_save_button.fixed_button p.submit input {
width: 100%;
max-width: 250px;
height: 100%;
padding: 5px;
}
.cau_save_button__space {
height: 75px;
}
/* Overwrite core UI */
/*.cau_content input[type="checkbox"]:checked::before {
content: "";
background: url( 'images/check.svg' );
background-size: contain;
background-position: center center;
}*/
.cau_content a {
color: #9178B7;
}
.cau_content a.nav-tab {
color: #23282D;
}
.cau_content .button-primary {
background-color: #9178B7!important;
border-color: #9178B7!important;
}
.cau_content .button-alt {
color: #9178B7!important;
border-color: #9178B7!important;
}
.cau_content .button-hero {
font-weight: 500;
padding: 2px 15px!important;
}
#message.cau {
background: #FFF;
border: 1px solid #CCD0D4;
border-left-width: 4px;
border-left-color: #9178B7;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
margin: 25px 0px 5px 0;
padding: 15px;
}
#message.cau a, #message.cau strong {
color: #9178B7;
}
/* Dashboard */
.cau-column-wide {
box-sizing: border-box;
display: inline-block;
vertical-align: top;
width: calc(100% - 450px);
padding-right: 25px;
}
.cau-column-small {
display: inline-block;
vertical-align: top;
width: 450px;
}
.cau-dashboard-box {
background-position: right bottom;
}
.cau-column-wide .cau-dashboard-box {
padding-right: 125px;
}
.cau-dashboard-box a {
margin-left: 0px;
margin-top: 10px;
}
.cau-dashboard-box .welcome-column {
padding-right: 25px;
}
.support-sidebar-list {
margin-bottom: 25px;
}
.cau_content .nav-tab {
position: relative;
}
.cau_content .nav-tab .cau_melding {
display: inline-block;
width: 11px;
height: 11px;
border-radius: 10px;
margin-left: 5px;
position: relative;
bottom: -1px;
}
.cau_content .nav-tab .cau_melding.level-okay {
background: #7AD03A;
}
.cau_content .nav-tab .cau_melding.level-low {
background: #FFBA00;
}
.cau_content .nav-tab .cau_melding.level-high {
background: #FF0000;
}
/* Table Styling */
.cau_content .widefat td {
vertical-align: middle!important;
}
table.autoupdate th.head-plugin {
min-width: 250px;
}
table.autoupdate th.head-status {
min-width: 150px;
}
table.autoupdate th.check-column {
position: relative;
min-width: 55px;
}
table.autoupdate tr.inactive {
background: #FEF7F1;
}
table.autoupdate tr.active .check-column {
border-left: 3px solid transparent;
}
table.autoupdate tr.inactive .check-column {
border-left: 3px solid #D54E21;
}
table.autoupdate tr.inactive td.column-status p {
color: #BF3D3C;
}
table.autoupdate tr.active td.column-status p {
color: #000;
}
table.autoupdate tr td.column-description p {
overflow: hidden;
max-height: 18px;
}
/* Update Log */
table.autoupdatelog {
margin-top: 25px;
}
table.autoupdatelog strong {
color: #000;
}
table.autoupdatelog .dashicons {
color: #00A0D2;
}
/* Status */
table.cau_status_list {
margin-top: 25px;
}
table.cau_status_list:not(.no_column_width) th, table.cau_status_list:not(.no_column_width) td {
width: 25%;
}
.cau_enabled {
color: #7AD03A;
}
.cau_disabled {
color: #FF0000;
}
.cau_warning {
color: #FFBA00;
}
.cau_mobile_prefix {
display: none;
}
table.cau_status_list .cau_status_icon {
width: 50px!important;
}
table.cau_status_list .cau_status_icon .dashicons, table.cau_status_list .cau_status_icon .dashicons-before:before {
height: 25px;
font-size: 2em;
}
/* Rollback list */
table.rollbacklist {
max-width: 650px;
}
table.rollbacklist td {
vertical-align: middle;
}
table.rollbacklist td a.versionselectbutton {
display: inline-block;
width: 100px;
text-align: center;
}
/* Plugin list */
.pluginListButtons {
display: block;
padding: 15px 0;
}
.pluginListButtons p.submit {
display: inline-block;
margin: 0!important;
padding: 0!important;
}
.cau_content #the-list input[type="checkbox"]:not(:checked), .cau_content #the-list input[type="checkbox"]:checked {
width: 45px;
height: 45px;
position: absolute;
top: 0;
bottom: 0;
z-index: 100;
display: block;
opacity: 0;
}
.cau_content #the-list input[type="checkbox"]:not(:checked) + label, .cau_content #the-list input[type="checkbox"]:checked + label {
position: absolute;
top: 15px;
left: 12px;
cursor: pointer;
}
.cau_content #the-list input[type="checkbox"]:not(:checked) + label:before, .cau_content #the-list input[type="checkbox"]:checked + label:before, .cau_content #the-list input[type="checkbox"]:not(:checked) + label:after, .cau_content #the-list input[type="checkbox"]:checked + label:after {
content: '';
position: absolute;
}
.cau_content #the-list input[type="checkbox"]:not(:checked) + label:before, .cau_content #the-list input[type="checkbox"]:checked + label:before {
left: 0;
top: -3px;
width: 30px;
height: 16px;
background: transparent;
border: 2px solid #9178B7;
border-radius: 15px;
transition: background-color .2s;
}
.cau_content #the-list input[type="checkbox"]:not(:checked) + label:after, .cau_content #the-list input[type="checkbox"]:checked + label:after {
width: 8px;
height: 8px;
transition: all .2s;
border-radius: 500px;
background: transparent;
border: 2px solid #9178B7;
top: 1px;
left: 5px;
}
.cau_content #the-list input[type="checkbox"]:not(:checked) + label:before {
background: #9178B7;
border: 2px solid #9178B7;
}
.cau_content #the-list input[type="checkbox"]:not(:checked) + label:after {
background: #9178B7;
border-color: #FFF;
left: 18px;
}
/* Scheduling */
.cau_schedule_input {
display: inline-block;
vertical-align: middle;
width: 50px;
padding-top: 5px;
}
.cau_schedule_input input {
max-width: 100%;
text-align: center;
}
.cau_schedule_input_div {
display: inline-block;
vertical-align: middle;
padding: 0 6px;
font-weight: bold;
}
.cau_shedule_notation {
display: inline-block;
vertical-align: middle;
width: 125px;
padding-left: 5px;
}
.cau_shedule_notation .dashicons {
position: relative;
bottom: -5px;
}
/* Tooltip */
.cau_tooltip {
position: relative;
}
.cau_tooltip .cau_tooltip_text {
visibility: hidden;
background-color: rgba(0,0,0,0.7);
color: #FFF;
text-align: left;
font-size: 14px;
padding: 15px;
border-radius: 6px;
position: absolute;
z-index: 1;
width: 240px;
bottom: 100%;
left: 50%;
margin-left: -60px;
margin-bottom: 10px;
opacity: 0;
transition: .3s;
font-weight: normal;
}
.cau_tooltip:hover .cau_tooltip_text {
visibility: visible;
opacity: 1;
}
.cau_tooltip .cau_tooltip_text::after {
content: " ";
position: absolute;
top: 100%;
left: 50%;
margin-left: -75px;
border-width: 5px;
border-style: solid;
border-color: rgba(0,0,0,0.7) transparent transparent transparent;
}
/* Responsive */
@media screen and (max-width: 1400px) {
.cau-column-wide {
width: calc(100% - 350px);
}
.cau-column-small {
width: 350px;
}
.welcome-to-cau .welcome-column.welcome-column-quarter {
width: 50%;
padding-bottom: 35px;
}
.cau-column-small .welcome-to-cau {
background-image: none;
}
}
@media screen and (max-width: 1150px) {
.cau-column-wide, .cau-column-small {
width: 100%;
padding: 0;
}
}
@media screen and (max-width: 1000px) {
/* Basics */
.cau_hide_on_mobile, table.autoupdate thead {
display: none!important;
}
.form-table td fieldset p {
display: block;
padding: 5px 0;
}
.form-table td fieldset input[type="checkbox"] {
display: inline-block;
vertical-align: middle;
width: 25px;
}
.form-table td fieldset label {
display: inline-block;
vertical-align: middle;
width: calc(100% - 40px);
box-sizing: border-box;
padding-left: 5px;
}
.cau_content .nav-tab-wrapper {
position: relative;
top: -20px;
border-bottom: 1px solid #CCC!important;
padding-bottom: 15px!important;
margin-bottom: 0px!important;
}
.cau_content .nav-tab {
font-size: 12px;
margin: 5px 5px 0 0!important;
box-sizing: border-box;
text-align: center;
}
/* Scheduling */
.cau_schedule_input {
width: 75px;
}
/* Custom buttons */
.cau-button {
display: block;
text-align: center;
margin: 5px 0;
}
.cau-button .dashicons {
float: left;
}
/* Dashboard */
.welcome-to-cau {
background-position: right bottom;
}
.welcome-to-cau.love-bg {
background-image: none;
}
.welcome-to-cau .welcome-column {
min-width: 100%;
}
.welcome-to-cau .welcome-column.welcome-column-first {
padding-left: 0px;
}
.cau-column-wide .cau-dashboard-box {
padding-right: 30px;
padding-bottom: 125px
}
.majorMinorExplain {
display: none;
}
/* Status */
table.cau_status_list .cau_status_name {
display: inline-block;
width: 50%;
box-sizing: border-box;
font-weight: 500;
}
table.cau_status_list .cau_status_interval {
display: none;
}
table.cau_status_list th.cau_status_next {
display: none;
}
table.cau_status_list td.cau_status_next {
display: block;
width: 100%;
}
table.cau_status_list .cau_status_active_state {
display: inline-block;
width: 50%;
box-sizing: border-box;
text-align: right;
}
.cau_mobile_prefix {
display: inline-block;
padding-right: 5px;
}
table.cau_status_list.cau_status_warnings td {
display: block;
width: 100%;
box-sizing: border-box;
}
table.cau_status_list.cau_status_warnings th.cau_plugin_issue_explain, table.cau_status_list.cau_status_warnings th.cau_plugin_issue_fixit {
display: none;
}
table.cau_status_list.cau_status_warnings td.cau_plugin_issue_name {
font-weight: 500;
}
}

View File

@ -1,11 +0,0 @@
#wpadminbar #wp-admin-bar-cau-has-issues .ab-icon:before {
/*content: "\f463";*/
content: "\f332";
top: 3px;
}
#wpadminbar #wp-admin-bar-cau-has-issues .cau-level-low {
/*color: #FFBA00;*/
}
#wpadminbar #wp-admin-bar-cau-has-issues .cau-level-high {
color: #FF0000;
}

View File

@ -1,526 +0,0 @@
<?php
// Check if emails should be send or not
function cau_check_updates_mail() {
// Notify of pending updates
if( cau_get_db_value( 'send' ) == 'on' ) {
cau_list_theme_updates(); // Check for theme updates
cau_list_plugin_updates(); // Check for plugin updates
}
// Notify of completed updates
if( cau_get_db_value( 'sendupdate' ) == 'on' && cau_get_db_value( 'plugins' ) == 'on' ) {
cau_plugin_updated(); // Check for updated plugins
}
// Notify of required db update
if( cau_get_db_value( 'dbupdateemails' ) == 'on' ) {
cau_notify_outofdate_db();
}
}
// Notify of out of date software
function cau_outdated_notifier_mail() {
if( cau_get_db_value( 'sendoutdated' ) == 'on' ) {
cau_list_outdated_software(); // Check for oudated plugins
}
}
// Ge the emailadresses it should be send to
function cau_set_email() {
$emailArray = array();
if( cau_get_db_value( 'email' ) == '' ) {
array_push( $emailArray, get_option('admin_email') );
} else {
$emailAdresses = cau_get_db_value( 'email' );
$list = explode( ", ", $emailAdresses );
foreach ( $list as $key ) {
array_push( $emailArray, $list );
}
}
return $emailArray;
}
// Mail format
function cau_is_html() {
if ( !function_exists( 'cau_get_db_value' ) ) require_once( plugin_dir_path( __FILE__ ) . 'cau_function.php' );
return ( cau_get_db_value( 'html_or_text' ) == 'html' ) ? true : false;
}
// Set the content for the emails about pending updates
function cau_outdated_message( $single, $plural, $list ) {
// WP version
$wpversion = get_bloginfo( 'version' );
// Base text
$text = sprintf( esc_html__( "You have %s on your WordPress site at %s that have not been tested with the latest 3 major releases of WordPress.", "companion-auto-update" ), $plural, get_site_url() );
$text .= "\n";
$text .= "\n";
// The list
if( !empty( $list ) ) {
$text .= sprintf( esc_html__( "The following %s have not been tested with WordPress %s:", "companion-auto-update" ), $plural, $wpversion );
$text .= "\n";
$text .= "\n";
foreach ( $list as $plugin => $version ) {
if( $version == '' ) $version = __( "Unknown", "companion-auto-update" );
$text .= "- ".sprintf( esc_html__( "%s tested up to: %s", "companion-auto-update" ), $plugin, $version )."\n";
}
}
return $text;
}
// Set the content for the emails about pending updates
function cau_pending_message( $single, $plural, $list ) {
// What markup to use
if( cau_is_html() ) $break = '<br />';
else $break = "\n";
// Base text
$text = sprintf( esc_html__( 'You have pending %1$s updates on your WordPress site at %2$s.', 'companion-auto-update' ), $single, get_site_url() );
$text .= $break;
if( !empty( $list ) ) {
$text .= $break;
$text .= sprintf( esc_html__( 'The following %1$s have new versions available.', 'companion-auto-update' ), $plural );
$text .= $break;
if( cau_is_html() ) $text .= "<ol>";
foreach ( $list as $key => $value ) {
if( cau_is_html() ) {
$text .= "<li>$value</li>";
} else {
$text .= "-$value\n";
}
}
if( cau_is_html() ) $text .= "</ol>";
$text .= $break;
}
$text .= __( 'Leaving your site outdated is a security risk so please consider manually updating them.', 'companion-auto-update' );
$text .= $break;
// End
$text .= sprintf( esc_html__( 'Head over to %1$s and check the ones you want to update.', 'companion-auto-update' ), get_admin_url().'update-core.php' );
return $text;
}
// Set the content for the emails about recent updates
function cau_updated_message( $type, $updatedList ) {
// What markup to use
if( cau_is_html() ) $break = '<br />';
else $break = "\n";
// The message
$text = sprintf( esc_html__(
'One or more %1$s on your WordPress site at %2$s have been updated by Companion Auto Update. No further action is needed on your part.
For more info on what is new visit your dashboard and check the changelog.', 'companion-auto-update'
), $type, get_site_url() );
$text .= $break;
$text .= $break;
$text .= sprintf( esc_html__(
'The following %1$s have been updated:', 'companion-auto-update'
), $type );
$text .= $break;
$text .= $updatedList;
$text .= $break;
$text .= __( "(You'll also receive this email if you manually updated a plugin or theme)", "companion-auto-update" );
return $text;
}
// Checks if plugins are out of date
function cau_list_outdated_software() {
// Check if cau_get_db_value() function exists.
if ( !function_exists( 'cau_get_db_value' ) ) require_once( plugin_dir_path( __FILE__ ) . 'cau_function.php' );
// Set up mail
$subject = '['.get_bloginfo( 'name' ).'] ' . __( 'You have outdated plugins on your site.', 'companion-auto-update' );
$type = __( 'plugin', 'companion-auto-update' );
$type_plural = __( 'plugins', 'companion-auto-update' );
$message = cau_outdated_message( $type, $type_plural, cau_list_outdated() );
// Send to all addresses
foreach ( cau_set_email() as $key => $value ) {
foreach ( $value as $k => $v ) {
wp_mail( $v, $subject, $message );
}
break;
}
}
// Checks if theme updates are available
function cau_list_theme_updates() {
global $wpdb;
$table_name = $wpdb->prefix . "auto_updates";
$configs = $wpdb->get_results( "SELECT * FROM $table_name WHERE name = 'themes'");
foreach ( $configs as $config ) {
if( $config->onoroff != 'on' ) {
// Check for required files
if ( !function_exists( 'get_theme_updates' ) ) {
require_once ABSPATH . 'wp-admin/includes/update.php';
}
// Begin
$themes = get_theme_updates();
$list = array();
if ( !empty( $themes ) ) {
foreach ( $themes as $stylesheet => $theme ) {
array_push( $list, $theme->get( 'Name' ) );
}
$subject = '[' . get_bloginfo( 'name' ) . '] ' . __( 'Theme update available.', 'companion-auto-update' );
$type = __('theme', 'companion-auto-update');
$type_plural = __('themes', 'companion-auto-update');
$message = cau_pending_message( $type, $type_plural, $list );
foreach ( cau_set_email() as $key => $value) {
foreach ($value as $k => $v) {
wp_mail( $v, $subject, $message );
}
break;
}
}
}
}
}
// Checks if plugin updates are available
function cau_list_plugin_updates() {
global $wpdb;
$table_name = $wpdb->prefix . "auto_updates";
$configs = $wpdb->get_results( "SELECT * FROM $table_name WHERE name = 'plugins'");
foreach ( $configs as $config ) {
if( $config->onoroff != 'on' ) {
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
// Make sure get_plugin_updates() and get_plugins() are defined
if ( !function_exists( 'get_plugin_updates' ) OR !function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
require_once ABSPATH . 'wp-admin/includes/update.php';
}
// Begin
$plugins = get_plugin_updates();
if ( !empty( $plugins ) ) {
$list = array();
foreach ( (array) $plugins as $plugin_file => $plugin_data ) {
$plugin_data = (object) _get_plugin_data_markup_translate( $plugin_file, (array) $plugin_data, false, true );
$name = $plugin_data->Name;
array_push( $list, $name );
}
$subject = '[' . get_bloginfo( 'name' ) . '] ' . __( 'Plugin update available.', 'companion-auto-update' );
$type = __( 'plugin', 'companion-auto-update' );
$type_plural = __( 'plugins', 'companion-auto-update' );
$message = cau_pending_message( $type, $type_plural, $list );
foreach ( cau_set_email() as $key => $value) {
foreach ($value as $k => $v) {
wp_mail( $v, $subject, $message );
}
break;
}
}
}
}
}
// Alerts when plugin has been updated
function cau_plugin_updated() {
// Check if cau_get_db_value() function exists.
if ( !function_exists( 'cau_get_db_value' ) ) require_once( plugin_dir_path( __FILE__ ) . 'cau_function.php' );
// Set the correct timezone for emails
date_default_timezone_set( cau_get_proper_timezone() );
// Create arrays
$pluginNames = array();
$pluginDates = array();
$pluginVersion = array();
$pluginSlug = array();
$pluginTimes = array();
$themeNames = array();
$themeDates = array();
$themeTimes = array();
// Where to look for plugins
$plugdir = plugin_dir_path( __DIR__ );
if ( !function_exists( 'get_plugins' ) ) require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); // Check if get_plugins() function exists.
$allPlugins = get_plugins();
// Where to look for themes
$themedir = get_theme_root();
$allThemes = wp_get_themes();
// Mail schedule
$schedule_mail = wp_get_schedule( 'cau_set_schedule_mail' );
// Loop trough all plugins
foreach ( $allPlugins as $key => $value ) {
// Get plugin data
$fullPath = $plugdir.'/'.$key;
$getFile = $path_parts = pathinfo( $fullPath );
$pluginData = get_plugin_data( $fullPath );
// Get the slug
$explosion = explode( '/', $key );
$actualSlug = array_shift( $explosion );
// Get last update date
$fileDate = date ( 'YmdHi', filemtime( $fullPath ) );
switch ( $schedule_mail ) {
case 'hourly':
$lastday = date( 'YmdHi', strtotime( '-1 hour', time() ) );
break;
case 'twicedaily':
$lastday = date( 'YmdHi', strtotime( '-12 hours', time() ) );
break;
default:
$lastday = date( 'YmdHi', strtotime( '-1 day', time() ) );
break;
}
$dateFormat = get_option( 'date_format' );
$timestamp = date_i18n( $dateFormat, filemtime( $fullPath ) );
$timestamp .= ' - '.date( 'H:i', filemtime( $fullPath ) );
if( $fileDate >= $lastday ) {
// Get plugin name
foreach ( $pluginData as $dataKey => $dataValue ) {
if( $dataKey == 'Name') {
array_push( $pluginNames , $dataValue );
}
if( $dataKey == 'Version') {
array_push( $pluginVersion , $dataValue );
}
}
array_push( $pluginDates, $fileDate );
array_push( $pluginSlug, $actualSlug );
array_push( $pluginTimes, $timestamp );
}
}
// Loop trough all themes
foreach ( $allThemes as $key => $value ) {
// Get theme data
$fullPath = $themedir.'/'.$key;
$getFile = $path_parts = pathinfo( $fullPath );
// Get last update date
$dateFormat = get_option( 'date_format' );
$fileDate = date ( 'YmdHi', filemtime( $fullPath ) );
if( $schedule_mail == 'hourly' ) {
$lastday = date( 'YmdHi', strtotime( '-1 hour', time() ) );
} elseif( $schedule_mail == 'twicedaily' ) {
$lastday = date( 'YmdHi', strtotime( '-12 hours', time() ) );
} elseif( $schedule_mail == 'daily' ) {
$lastday = date( 'YmdHi', strtotime( '-1 day', time() ) );
}
$dateFormat = get_option( 'date_format' );
$timestamp = date_i18n( $dateFormat, filemtime( $fullPath ) );
$timestamp .= ' - '.date( 'H:i', filemtime( $fullPath ) );
if( $fileDate >= $lastday ) {
array_push( $themeNames, $path_parts['filename'] );
array_push( $themeDates, $fileDate );
array_push( $themeTimes, $timestamp );
}
}
$totalNumP = 0;
$totalNumT = 0;
$updatedListP = '';
$updatedListT = '';
if( cau_get_db_value( 'html_or_text' ) == 'html' ) {
$updatedListP .= '<ol>';
$updatedListT .= '<ol>';
}
foreach ( $pluginDates as $key => $value ) {
// Set up some var
$plugin_name = $pluginNames[$key];
$plugin_slug = $pluginSlug[$key];
$to_version = __( "to version", "companion-auto-update" ).' '.$pluginVersion[$key];
$more_info_arr = array( __( "Time of update", "companion-auto-update" ) => $pluginTimes[$key] );
// Plugin links
if( cau_get_db_value( 'plugin_links_emails' ) == 'on' ) {
$more_info_arr[__( "Plugin details", "companion-auto-update" )] = "<a href='https://wordpress.org/plugins/{$plugin_slug}/'>".__( "Visit", "companion-auto-update" )."</a>";
$more_info_arr[__( "Release notes", "companion-auto-update" )] = "<a href='https://wordpress.org/plugins/{$plugin_slug}/#developers'>".__( "Visit", "companion-auto-update" )."</a>";
$more_info_arr[__( "Support", "companion-auto-update" )] = "<a href='https://wordpress.org/support/plugin/{$plugin_slug}/'>".__( "Visit", "companion-auto-update" )."</a>";
}
// Email format
$use_html = ( cau_get_db_value( 'html_or_text' ) == 'html' ) ? true : false;
// Email content
$updatedListP .= $use_html ? "<li>" : "-"; // Start row
$updatedListP .= $use_html ? "<strong>{$plugin_name}</strong> " : "{$plugin_name} "; // Show plugin name
$updatedListP .= $to_version; // To version
// Get advanced info
if( cau_get_db_value( 'advanced_info_emails' ) == 'on' ) {
foreach( $more_info_arr as $label => $value ) {
$updatedListP .= $use_html ? "<br />{$label}: {$value}" : "\n{$label}: {$value}";
}
}
$updatedListP .= $use_html ? "</li>" : "\n"; // End row
$totalNumP++;
}
foreach ( $themeNames as $key => $value ) {
if( cau_get_db_value( 'html_or_text' ) == 'html' ) {
$more_info = '';
if( cau_get_db_value( 'advanced_info_emails' ) == 'on' ) $more_info = "<br /><span style='opacity: 0.5;'>".__( "Time of update", "companion-auto-update" ).": ".$themeTimes[$key]."</span>";
$updatedListT .= "<li><strong>".$themeNames[$key]."</strong>".$more_info."</li>";
} else {
$updatedListT .= "- ".$themeNames[$key]."\n";
}
$totalNumT++;
}
if( cau_get_db_value( 'html_or_text' ) == 'html' ) {
$updatedListP .= '</ol>';
$updatedListT .= '</ol>';
}
// Set the email content type
if( cau_get_db_value( 'html_or_text' ) == 'html' ) {
function cau_mail_content_type() {
return 'text/html';
}
add_filter( 'wp_mail_content_type', 'cau_mail_content_type' );
}
// If plugins have been updated, send email
if( $totalNumP > 0 ) {
// E-mail content
$subject = '[' . get_bloginfo( 'name' ) . '] ' . __('One or more plugins have been updated.', 'companion-auto-update');
$type = __('plugins', 'companion-auto-update');
$message = cau_updated_message( $type, $updatedListP );
// Send to all addresses
foreach ( cau_set_email() as $key => $value) {
foreach ($value as $k => $v) {
wp_mail( $v, $subject, $message );
}
break;
}
}
// If themes have been updated, send email
if( $totalNumT > 0 ) {
// E-mail content
$subject = '[' . get_bloginfo( 'name' ) . '] ' . __('One or more themes have been updated.', 'companion-auto-update');
$type = __('themes', 'companion-auto-update');
$message = cau_updated_message( $type, $updatedListT );
// Send to all addresses
foreach ( cau_set_email() as $key => $value) {
foreach ($value as $k => $v) {
wp_mail( $v, $subject, $message );
}
break;
}
}
if( cau_get_db_value( 'html_or_text' ) == 'html' ) remove_filter( 'wp_mail_content_type', 'cau_mail_content_type' );
// Prevent duplicate emails by setting the event again
if( $totalNumT > 0 OR $totalNumP > 0 ) {
if( $schedule_mail == 'hourly' ) {
wp_clear_scheduled_hook('cau_set_schedule_mail');
wp_schedule_event( strtotime( '+1 hour', time() ) , 'hourly', 'cau_set_schedule_mail' );
}
}
}
function cau_notify_outofdate_db() {
// Check if cau_get_db_value() function exists.
if ( !function_exists( 'cau_get_db_value' ) ) require_once( plugin_dir_path( __FILE__ ) . 'cau_function.php' );
// Database requires an update
if ( cau_incorrectDatabaseVersion() ) {
// Set up mail
$subject = '[' . get_bloginfo( 'name' ) . '] ' . __( 'We need your help with something', 'companion-auto-update' );
$message = __( 'Hi there! We need your help updating the database of Companion Auto Update to the latest version. No rush, old features will continue to work but some new features might not work until you update the database.', 'companion-auto-update' );
// Send to all addresses
foreach ( cau_set_email() as $key => $value ) {
foreach ( $value as $k => $v ) {
wp_mail( $v, $subject, $message );
}
break;
}
}
}

View File

@ -1,420 +0,0 @@
<?php
/*
* Plugin Name: Companion Auto Update
* Plugin URI: http://codeermeneer.nl/portfolio/companion-auto-update/
* Description: This plugin auto updates all plugins, all themes and the wordpress core.
* Version: 3.9.1
* Author: Papin Schipper
* Author URI: http://codeermeneer.nl/
* Contributors: papin
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: companion-auto-update
* Domain Path: /languages/
*/
// Disable direct access
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
// Load translations
function cau_init() {
load_plugin_textdomain( 'companion-auto-update', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); // Load language files (for backwards compat mostly)
add_filter( 'plugins_auto_update_enabled', '__return_false' ); // Turn off default WP5.5 plugin update features to avoid confusion
add_filter( 'themes_auto_update_enabled', '__return_false' ); // Turn off default WP5.5 theme update features to avoid confusion
}
add_action( 'init', 'cau_init' );
// Set up the database and required schedules
function cau_install( $network_wide ) {
if ( is_multisite() && $network_wide ) {
global $wpdb;
$blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id );
cau_database_creation();
restore_current_blog();
}
} else {
cau_database_creation();
}
if (! wp_next_scheduled ( 'cau_set_schedule_mail' )) wp_schedule_event( time(), 'daily', 'cau_set_schedule_mail'); // Set schedule for basic notifcations
if (! wp_next_scheduled ( 'cau_custom_hooks_plugins' )) wp_schedule_event( time(), 'daily', 'cau_custom_hooks_plugins'); // Run custom hooks on plugin updates
if (! wp_next_scheduled ( 'cau_custom_hooks_themes' )) wp_schedule_event( time(), 'daily', 'cau_custom_hooks_themes'); // Run custom hooks on theme updates
if (! wp_next_scheduled ( 'cau_log_updater' )) wp_schedule_event( ( time() - 1800 ), 'daily', 'cau_log_updater'); // Keep the log up to date
if (! wp_next_scheduled ( 'cau_outdated_notifier' )) wp_schedule_event( time(), 'daily', 'cau_outdated_notifier'); // Set schedule for basic notifcations
}
add_action( 'cau_set_schedule_mail', 'cau_check_updates_mail' );
add_action( 'cau_outdated_notifier', 'cau_outdated_notifier_mail' );
add_action( 'wp_update_plugins', 'cau_run_custom_hooks_p' );
add_action( 'wp_update_themes', 'cau_run_custom_hooks_t' );
add_action( 'wp_version_check', 'cau_run_custom_hooks_c' );
// Hourly event to keep the log up to date
function cau_keep_log_uptodate() {
cau_savePluginInformation(); // Check for new plugins and themes
cau_check_delayed(); // Check for plugin delays
}
add_action( 'cau_log_updater', 'cau_keep_log_uptodate' );
// Redirect to welcome screen on activation of plugin
function cau_pluginActivateWelcome() {
add_option( 'cau_redirectToWelcomeScreen', true );
}
register_activation_hook(__FILE__, 'cau_pluginActivateWelcome');
// Redirect to welcome screen on activation of plugin
function cau_pluginRedirectWelcomeScreen() {
if ( get_option( 'cau_redirectToWelcomeScreen', false ) ) {
delete_option( 'cau_redirectToWelcomeScreen' );
if( !isset( $_GET['activate-multi'] ) ) {
wp_redirect( admin_url( cau_menloc().'?page=cau-settings&welcome=1' ) );
}
}
}
add_action( 'admin_init', 'cau_pluginRedirectWelcomeScreen' );
// Donate url
function cau_donateUrl() {
return 'https://www.paypal.me/dakel/10/';
}
// Database version
function cau_db_version() {
return '3.8.3';
}
function cau_database_creation() {
global $wpdb;
// Plugin db info
$cau_db_version = cau_db_version();
$autoupdates = $wpdb->prefix."auto_updates";
$updateLog = $wpdb->prefix."update_log";
// WordPress db info
$charset_collate = $wpdb->get_charset_collate();
// DB table creation queries
$sql = "CREATE TABLE $autoupdates ( id INT(9) NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, onoroff TEXT NOT NULL, UNIQUE KEY id (id) ) $charset_collate;";
$sql2 = "CREATE TABLE $updateLog ( id INT(9) NOT NULL AUTO_INCREMENT, slug VARCHAR(255) NOT NULL, oldVersion VARCHAR(10) NOT NULL, newVersion VARCHAR(10) NOT NULL, method VARCHAR(10) NOT NULL, put_on_hold VARCHAR(100) DEFAULT '0', UNIQUE KEY id (id) ) $charset_collate;";
// Create DB tables
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
dbDelta( $sql2 );
// Database version
add_option( "cau_db_version", "$cau_db_version" );
// Insert data
cau_install_data();
}
// Check if database table exists before creating
function cau_check_if_exists( $whattocheck, $id = 'name', $db_table = 'auto_updates' ) {
global $wpdb;
$table_name = $wpdb->prefix.$db_table;
$rows = $wpdb->get_col( "SELECT COUNT(*) as num_rows FROM {$table_name} WHERE {$id} = '{$whattocheck}'" );
$check = $rows[0];
return ( $check > 0 ) ? true : false;
}
// Insert date into database
function cau_install_data() {
global $wpdb;
$table_name = $wpdb->prefix . "auto_updates";
$toemail = get_option('admin_email');
// Update configs
if( !cau_check_if_exists( 'plugins' ) ) $wpdb->insert( $table_name, array( 'name' => 'plugins', 'onoroff' => 'on' ) );
if( !cau_check_if_exists( 'themes' ) ) $wpdb->insert( $table_name, array( 'name' => 'themes', 'onoroff' => 'on' ) );
if( !cau_check_if_exists( 'minor' ) ) $wpdb->insert( $table_name, array( 'name' => 'minor', 'onoroff' => 'on' ) );
if( !cau_check_if_exists( 'major' ) ) $wpdb->insert( $table_name, array( 'name' => 'major', 'onoroff' => '' ) );
// Email configs
if( !cau_check_if_exists( 'email' ) ) $wpdb->insert( $table_name, array( 'name' => 'email', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'send' ) ) $wpdb->insert( $table_name, array( 'name' => 'send', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'sendupdate' ) ) $wpdb->insert( $table_name, array( 'name' => 'sendupdate', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'sendoutdated' ) ) $wpdb->insert( $table_name, array( 'name' => 'sendoutdated', 'onoroff' => '' ) );
// Advanced
if( !cau_check_if_exists( 'notUpdateList' ) ) $wpdb->insert( $table_name, array( 'name' => 'notUpdateList', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'translations' ) ) $wpdb->insert( $table_name, array( 'name' => 'translations', 'onoroff' => 'on' ) );
if( !cau_check_if_exists( 'wpemails' ) ) $wpdb->insert( $table_name, array( 'name' => 'wpemails', 'onoroff' => 'on' ) );
if( !cau_check_if_exists( 'notUpdateListTh' ) ) $wpdb->insert( $table_name, array( 'name' => 'notUpdateListTh', 'onoroff' => '' ) );
// Stuff
if( !cau_check_if_exists( 'html_or_text' ) ) $wpdb->insert( $table_name, array( 'name' => 'html_or_text', 'onoroff' => 'html' ) );
if( !cau_check_if_exists( 'dbupdateemails' ) ) $wpdb->insert( $table_name, array( 'name' => 'dbupdateemails', 'onoroff' => '' ) );
// Advanced
if( !cau_check_if_exists( 'allow_administrator' ) ) $wpdb->insert( $table_name, array( 'name' => 'allow_administrator', 'onoroff' => 'on' ) );
if( !cau_check_if_exists( 'allow_editor' ) ) $wpdb->insert( $table_name, array( 'name' => 'allow_editor', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'allow_author' ) ) $wpdb->insert( $table_name, array( 'name' => 'allow_author', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'ignore_seo' ) ) $wpdb->insert( $table_name, array( 'name' => 'ignore_seo', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'ignore_cron' ) ) $wpdb->insert( $table_name, array( 'name' => 'ignore_cron', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'advanced_info_emails' ) ) $wpdb->insert( $table_name, array( 'name' => 'advanced_info_emails', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'update_delay' ) ) $wpdb->insert( $table_name, array( 'name' => 'update_delay', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'update_delay_days' ) ) $wpdb->insert( $table_name, array( 'name' => 'update_delay_days', 'onoroff' => '' ) );
if( !cau_check_if_exists( 'plugin_links_emails' ) ) $wpdb->insert( $table_name, array( 'name' => 'plugin_links_emails', 'onoroff' => '' ) );
}
register_activation_hook( __FILE__, 'cau_install' );
// Clear everything on deactivation
function cau_remove() {
// Delete tables
global $wpdb;
$autoupdates = $wpdb->prefix."auto_updates";
$updateLog = $wpdb->prefix."update_log";
$wpdb->query( "DROP TABLE IF EXISTS $autoupdates" );
$wpdb->query( "DROP TABLE IF EXISTS $updateLog" );
// Clear schedules
wp_clear_scheduled_hook( 'cau_set_schedule_mail' );
wp_clear_scheduled_hook( 'cau_custom_hooks_plugins' );
wp_clear_scheduled_hook( 'cau_custom_hooks_themes' );
wp_clear_scheduled_hook( 'cau_log_updater' );
// Restore WordPress 5.5 default update functionality
add_filter( 'plugins_auto_update_enabled', '__return_true' );
add_filter( 'themes_auto_update_enabled', '__return_true' );
add_filter( 'auto_plugin_update_send_email', '__return_true' );
add_filter( 'auto_theme_update_send_email', '__return_true' );
}
register_deactivation_hook( __FILE__, 'cau_remove' );
// Update
function cau_update_db_check() {
$cau_db_version = cau_db_version();
if ( get_site_option( 'cau_db_version' ) != $cau_db_version ) {
cau_database_creation();
// In 3.7.2 we've added $wpdb->get_charset_collate
if( get_site_option( 'cau_db_version' ) < '3.7.2' ) {
global $wpdb;
$autoupdates = $wpdb->prefix."auto_updates";
$updateLog = $wpdb->prefix."update_log";
$db_charset = constant( 'DB_CHARSET' );
$wpdb->query( "ALTER TABLE $autoupdates CONVERT TO CHARACTER SET $db_charset" );
$wpdb->query( "ALTER TABLE $updateLog CONVERT TO CHARACTER SET $db_charset" );
}
update_option( "cau_db_version", $cau_db_version );
}
}
add_action( 'upgrader_process_complete', 'cau_update_db_check' );
// Manual update
function cau_manual_update() {
cau_update_db_check();
}
// Load custom functions
require_once( plugin_dir_path( __FILE__ ) . 'cau_functions.php' );
// Add plugin to menu
function register_cau_menu_page() {
if( cau_allowed_user_rights() ) add_submenu_page( cau_menloc() , __( 'Auto Updater', 'companion-auto-update' ), __( 'Auto Updater', 'companion-auto-update' ), 'manage_options', 'cau-settings', 'cau_frontend' );
}
add_action( 'admin_menu', 'register_cau_menu_page' );
// Settings page
function cau_frontend() {
echo "<div class='wrap cau_content_wrap cau_content'>
<h1 class='wp-heading-inline'>".__( 'Companion Auto Update', 'companion-auto-update' )."</h1>
<hr class='wp-header-end'>";
// Make sure the correct timezone is used
date_default_timezone_set( cau_get_proper_timezone() );
// Allow only access to these pages
$allowedPages = array(
'dashboard' => __( 'Dashboard' ),
'pluginlist' => __( 'Update filter', 'companion-auto-update' ),
'log' => __( 'Update log', 'companion-auto-update' ),
'status' => __( 'Status', 'companion-auto-update' ),
);
// Show subtabs
echo "<h2 class='nav-tab-wrapper wp-clearfix'>";
foreach ( $allowedPages as $page => $title ) {
echo "<a href='".cau_url( $page )."' id='tab-".$page."' class='nav-tab "._active_tab( $page )."'>".$title;
if( $page == 'status' ) echo cau_pluginHasIssues() ? "<span class='cau_melding level-".cau_pluginIssueLevels()."'></span>" : "<span class='cau_melding level-okay'></span>"; // Show status icon
echo "</a>";
}
echo "</h2>";
// Show page content
if( !isset( $_GET['tab'] ) ) {
$requestedPage = 'dashboard';
echo "<script>jQuery('#tab-dashboard').addClass('nav-tab-active');</script>"; // Set active tab class
} else {
$requestedPage = sanitize_key( $_GET['tab'] );
}
if( array_key_exists( $requestedPage, $allowedPages ) ) {
require_once( plugin_dir_path( __FILE__ ) . 'admin/'.$requestedPage.'.php' );
} else {
wp_die( 'You\'re not allowed to view <strong>'.$requestedPage.'</strong>.' );
}
echo '</div>';
}
// Add a widget to the dashboard.
function cau_add_widget() {
if ( cau_allowed_user_rights() ) wp_add_dashboard_widget( 'cau-update-log', __('Update log', 'companion-auto-update'), 'cau_widget' );
}
add_action( 'wp_dashboard_setup', 'cau_add_widget' );
// Widget content
function cau_widget() {
echo '<style>table.autoupdatewidget { border: 0px solid transparent; border-bottom: 1px solid #EEEEEE; margin: 0 -12px; width: calc(100% + 24px); } table.autoupdatewidget tr td { border-top: 1px solid #EEEEEE; padding: 9px 12px 5px 12px; background: #FAFAFA; } .cau_divide { display: inline-block; color: #E7E0DF; padding: 0 2px; } </style>';
echo '<p>'.__('Below are the last 7 updates ran on this site. Includes plugins and themes, both automatically updated and manually updated.', 'companion-auto-update').'</p>';
cau_fetch_log( '7' );
echo '<p><a href="'.cau_url( 'log' ).'">'.__( 'View full changelog', 'companion-auto-update' ).'</a> <span class="cau_divide">|</span> <a href="'.cau_url( 'dashboard' ).'">'.__( 'Settings' ).'</a></p>';
}
// Load admin styles
function load_cau_global_styles( $hook ) {
wp_enqueue_style( 'cau_admin_styles', plugins_url( 'backend/style.css' , __FILE__ ) ); // Plugin scripts
wp_enqueue_style( 'cau_warning_styles', plugins_url( 'backend/warningbar.css' , __FILE__ ) ); // Check for issues
}
add_action( 'admin_enqueue_scripts', 'load_cau_global_styles', 99 );
// Load admin styles
function load_cau_page_styles( $hook ) {
// Only load on plugins' pages
if( $hook != 'tools_page_cau-settings' && $hook != 'index_page_cau-settings' ) return;
// WordPress scripts we need
wp_enqueue_style( 'thickbox' );
wp_enqueue_script( 'thickbox' );
wp_enqueue_script( 'plugin-install' );
}
add_action( 'admin_enqueue_scripts', 'load_cau_page_styles', 100 );
// Send e-mails
require_once( plugin_dir_path( __FILE__ ) . 'cau_emails.php' );
// Add settings link on plugin page
function cau_settings_link( $links ) {
$settings_link = '<a href="'.cau_url( 'dashboard' ).'">'.__( 'Settings' ).'</a>';
$settings_link2 = '<a href="https://translate.wordpress.org/projects/wp-plugins/companion-auto-update">'.__( 'Help us translate', 'companion-auto-update' ).'</a>';
$settings_link3 = '<a href="'.cau_donateUrl().'">'.__( 'Donate to help development', 'companion-auto-update' ).'</a>';
array_unshift( $links, $settings_link2 );
array_unshift( $links, $settings_link3 );
if( cau_allowed_user_rights() ) array_unshift( $links, $settings_link );
return $links;
}
$plugin = plugin_basename(__FILE__);
add_filter( "plugin_action_links_$plugin", "cau_settings_link" );
// Auto Update Class
class CAU_auto_update {
// Enable Update filters
public function __construct() {
add_action( 'plugins_loaded', array( &$this, 'CAU_auto_update_filters' ), 1 );
}
public function CAU_auto_update_filters() {
global $wpdb;
$table_name = $wpdb->prefix . "auto_updates";
// Disable WP emails
add_filter( 'auto_plugin_update_send_email', '__return_false' ); // Plugin updates
add_filter( 'auto_theme_update_send_email', '__return_false' ); // Theme updates
// Enable for major updates
$configs = $wpdb->get_results( "SELECT * FROM {$table_name} WHERE name = 'major'");
foreach ( $configs as $config ) {
if( $config->onoroff == 'on' ) add_filter( 'allow_major_auto_core_updates', '__return_true', 1 ); // Turn on
else add_filter( 'allow_major_auto_core_updates', '__return_false', 1 ); // Turn off
}
// Enable for minor updates
$configs = $wpdb->get_results( "SELECT * FROM {$table_name} WHERE name = 'minor'");
foreach ( $configs as $config ) {
if( $config->onoroff == 'on' ) add_filter( 'allow_minor_auto_core_updates', '__return_true', 1 ); // Turn on
else add_filter( 'allow_minor_auto_core_updates', '__return_false', 1 ); // Turn off
}
// Enable for plugins
$configs = $wpdb->get_results( "SELECT * FROM {$table_name} WHERE name = 'plugins'");
foreach ( $configs as $config ) {
if( $config->onoroff == 'on' ) add_filter( 'auto_update_plugin', 'cau_dontUpdatePlugins', 10, 2 ); // Turn on
else add_filter( 'auto_update_plugin', '__return_false', 1 ); // Turn off
}
// Enable for themes
$configs = $wpdb->get_results( "SELECT * FROM {$table_name} WHERE name = 'themes'");
foreach ( $configs as $config ) {
if( $config->onoroff == 'on' ) add_filter( 'auto_update_theme', '__return_true' ); // Turn on
else add_filter( 'auto_update_theme', '__return_false', 1 ); // Turn off
}
// Enable for translation files
$configs = $wpdb->get_results( "SELECT * FROM {$table_name} WHERE name = 'translations'");
foreach ( $configs as $config ) {
if( $config->onoroff == 'on' ) add_filter( 'auto_update_translation', '__return_true', 1 ); // Turn on
else add_filter( 'auto_update_translation', '__return_false', 1 ); // Turn off
}
// WP Email Config
$configs = $wpdb->get_results( "SELECT * FROM {$table_name} WHERE name = 'wpemails'");
foreach ( $configs as $config ) {
if( $config->onoroff == 'on' ) add_filter( 'auto_core_update_send_email', '__return_true', 1 ); // Turn on
else add_filter( 'auto_core_update_send_email', '__return_false', 1 ); // Turn off
}
}
}
new CAU_auto_update();
// Check for issues
function cau_checkForIssues( $admin_bar ) {
if( cau_pluginHasIssues() && is_admin() && cau_pluginIssueLevels() == 'high' ) {
$admin_bar->add_menu( array(
'id' => 'cau-has-issues',
'title' => '<span class="ab-icon"></span><span class="cau-level-'.cau_pluginIssueLevels().'">'.cau_pluginIssueCount().'</span>',
'href' => cau_url( 'status' ),
'meta' => array(
'target' => '_self',
'title' => __( 'Companion Auto Update ran into a critical error. View the status log for more info.', 'companion-auto-update' ),
),
));
}
}
add_action( 'admin_bar_menu', 'cau_checkForIssues', 150 );

View File

@ -1,2 +0,0 @@
<?php
# Silence is golden.

View File

@ -1,62 +0,0 @@
# Copyright (C) 2016 Companion Auto Update
# This file is distributed under the same license as the Companion Auto Update package.
msgid ""
msgstr ""
"Project-Id-Version: Companion Auto Update 1.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/companion-auto-"
"update\n"
"POT-Creation-Date: 2016-05-24 08:16:37+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2016-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
#: companion_portfolio.php:96
msgid "Auto Updater"
msgstr ""
#: companion_portfolio.php:122
msgid "Auto update plugins?"
msgstr ""
#: companion_portfolio.php:122
msgid "Auto update themes?"
msgstr ""
#: companion_portfolio.php:122
msgid "Auto update minor core updates?"
msgstr ""
#: companion_portfolio.php:122
msgid "Auto update major core updates?"
msgstr ""
#: companion_portfolio.php:125
msgid "Settings saved"
msgstr ""
#: companion_portfolio.php:125
msgid "Settings"
msgstr ""
#. Plugin Name of the plugin/theme
msgid "Companion Auto Update"
msgstr ""
#. #-#-#-#-# plugin.pot (Companion Auto Update 1.0) #-#-#-#-#
#. Plugin URI of the plugin/theme
#. #-#-#-#-# plugin.pot (Companion Auto Update 1.0) #-#-#-#-#
#. Author URI of the plugin/theme
msgid "https://qreative-web.com"
msgstr ""
#. Description of the plugin/theme
msgid ""
"This plugin auto updates all plugins, all themes and the wordpress core."
msgstr ""
#. Author of the plugin/theme
msgid "Qreative-Web"
msgstr ""

View File

@ -1,4 +0,0 @@
<?php
/**
* Nothing to see here
*/

View File

@ -1,202 +0,0 @@
=== Companion Auto Update ===
Contributors: Papin, qweb
Donate link: https://www.paypal.me/dakel/10/
Tags: auto, automatic, background, update, updates, updating, automatic updates, automatic background updates, easy update, wordpress update, theme update, plugin update, up-to-date, security, update latest version, update core, update wp, update wp core, major updates, minor updates, update to new version, update core, update plugin, update plugins, update plugins automatically, update theme, plugin, theme, advance, control, mail, notifations, enable
Requires at least: 5.3.0
Tested up to: 6.4
Requires PHP: 5.1
Stable tag: 3.9.1
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Manage all updates on your WordPress site. Stay in the know with several optional e-mail notifications and logs. For free.
== Description ==
Companion Auto Update is a powerful and completely free plugin that allows you to manage all the updates on your WordPress site. Our aim is to give you the best control over these updates and stay in the know at all times.
We understand that you might not always be able to check if your WordPress site has any updates that need to be installed. Especially when you maintain multiple websites keeping them up-to-date can be a lot of work. This plugin can help you with that. We'll keep your site up-to-date and keep you posted about what's happening and notify you when we need your help with something.
If you have a feature suggestion or idea youd like to see in the plugin, wed love to hear about it! [Suggest a Feature](https://codeermeneer.nl/contact/)
= Main features =
1. Auto-updating for plugins, themes, core and translation files
1. Set at what time you wish to update
1. Filter plugins and themes to not be updated
1. E-mail notifications about old software, pending updates and completed updates
1. An update log with all updates
1. Option to delay automatic updates with an x number of days
= Full control over everything =
Full control, that's what this plugin is all about. With this plugin you can enable (or disable) automatic updating for plugins, themes, WordPress core updates (both minor and major can be changed separately) and for translation files. Don't want to run the updater for all plugins? Don't worry, just disable auto updating for the plugins you'd like to skip and we can even notify you when there's an update for these plugins so you can go and update them yourself.
= Scheduling =
By default we'll check for updates twice a day but you can change this to several different options if you'd like. When choosing to update on a daily basis you can even select at what time you'd like it to run. Besides the updaters you can also schedule te notifications, want to update every hour but only recieve notifications once a day? No problem!
Sometimes developers will push an update that will cause errors on your site, they'll often fix it within a day but if the updater has run in the mean time it can cause all kinds of issues. Now you can choose to delay updates with an x number of days to prevent this from happening.
= Know what's happening =
We want you to know what's happening on your website. This plugin offers settings for various email notifications. We can send you an email when an update is available, when a plugin has been updated or when wordpress has been updated.
But if you don't want to recieve emails about this you can still log in and view the changelog to see what happened.
== Installation ==
How to install Companion Auto Update
= Manual install =
1. Download Companion Auto Update.
1. Upload the 'Companion Auto Update' directory to your '/wp-content/plugins/' directory.
1. Activate Companion Auto Update from your Plugins page.
= Via WordPress =
1. Search for 'Companion Auto Update'.
1. Click install.
1. Activate.
= Settings =
Settings can be found trough Tools > Auto Updater
== Frequently Asked Questions ==
= Check our website for the FAQ =
[https://codeermeneer.nl/documentation/auto-update/faq-auto-updater/](https://codeermeneer.nl/documentation/auto-update/faq-auto-updater/)
= What features can I expect to see in the future? =
Your feedback is what made this plugin what is and what itll become so keep the feedback coming! To see what features you've suggested and what we're working on [read our blogpost here](https://codeermeneer.nl/blog/companion-auto-update-and-its-future/)
= What's the difference between WordPress 5.5 and this plugin? =
WordPress 5.5 was released recently and it packs tons of new features. One of those features is auto-updates for plugins and themes. Something Companion Auto Update does too.
So obviously, some of you wondered what the difference would be between the default WordPress method and the one offered by Companion Auto Update and I figured Id quickly write a blog about it, explaining the differences.
[You can read this blogpost here](https://codeermeneer.nl/blog/wordpress-5-5-versus-companion-auto-update/)
== Screenshots ==
1. Full control over what to update and when to recieve notifications
2. Disable auto-updating for certain plugins and/or themes
3. Advanced scheduling options for updating and notifcations
4. Keep track of updates with the update log
== Changelog ==
= 3.9.1 (March 8, 2024) =
* Fixed: Undefined variable $totalNum
= 3.9.0 (February 2, 2024) =
* Fixed: Fatal error during Cron
* Fixed: PHP deprecated error for PHP 8 and up
= 3.8.9 (January 9, 2024) =
* Fixed error: Call to undefined function is_plugin_active()
= 3.8.8 (December 19, 2023) =
* Fixed a few minor bugs
* Made some performance improvements
* We now require at least WordPress 5.3
= 3.8.7.1 (September 28, 2022) =
* Tweak: Extended function_exists check with get_plugins() for the fatal error when trying to send update emails
= 3.8.7 (September 12, 2022) =
* Fix: Fatal error when trying to send update emails
= 3.8.6 (August 11, 2022) =
* Tweak: Code optimization for better performance
= 3.8.5 (March 17, 2022) =
* New: Added more checks on the status page and added an explanation to some of them.
* New: Added an list of delayed updates on the status page to help with troubleshooting.
* Tweak: Made some improvements to the update delay feature.
* Tweak: Added a notice to explain that update delay does not work with WordPress update currently.
* Tweak: Improved code on the status page to be more reliable.
= 3.8.4 (February 2, 2022) =
* Tweak: Fixed a few styling errors with WP5.9
= 3.8.3 (December 9, 2021) =
* New: Plugin update e-mails now have an option to link to a few important pages
* Fix: Error: Undefined index: dbupdateemails
* Fix: Error: A non-numeric value encountered
= 3.8.2 (July 1, 2021) =
* Fix: Error: Call to undefined function get_plugin_updates()
= 3.8.1 (June 4, 2021) =
* New: Be notified when we need your help updating to a new database version [Feature Request](https://wordpress.org/support/topic/feature-request-839/)
* Tweak: Made some under the hood performance improvements
= 3.8.0 (January 14, 2021) =
* New: Better handling of plugins with an unknown WP version
* New: More intervals for notifications
* Fix: Call to undefined function errors
= 3.7.1.1 (November 2, 2020) =
* Fix: Type in wp_next_scheduled
= 3.7.1 (October 30, 2020) =
* Fix: PHP Warning: strtotime() expects parameter 2 to be integer, string given
= 3.7 (September 8, 2020) =
* New: Delay updates with an x number of days
* New: Be notified of plugins that have not been tested with the latest 3 major releases of WordPress.
* New: Choose to see more info in the emails (like the time at which the update happened)
* Fix: "Contact for support" button will work again
* Fix: Fixed a few PHP errors
* Tweak: Made improvements to the "Fix it" button for the "All automatic updates are disabled" error.
* Tweak: You can now choose to ignore the "Search Engine Visibility" and "Cronjobs" warnings
* Tweak: Reports on the Site Health page will only show a summary and point to the status page for more information and possible fixes
* Tweak: Removed cronjob check and Search Engine Visibility check from site health
* Tweak: E-mails are now fully translatable
* Tweak: Renamed Core notifications to WordPress notifications
* Tweak: WordPress plugin and theme update notifications are now disabled
Also: Check out what features we're working on at [our blogpost](https://codeermeneer.nl/blog/companion-auto-update-and-its-future/)
= 3.6 (August 12, 2020) =
* New: Added an "after core update" hook [More info](https://codeermeneer.nl/documentation/codex-auto-updater/)
* New: Select which userroles can access settings. (Defaults to only administrators)
* Tweak: Added Theme and Core update method the log
* Tweak: Few WordPress 5.5 improvements
= 3.5.5 (August 5, 2020) =
* Fix: Added better multisite support
* Tweak: We've added a bunch more checks to the status page and you can now see more passed checks.
* Support for WordPress 5.5
= 3.5.4.1 (June 20, 2020) =
* Fix: Sometimes the hour settings for intervals wouldn't show up
= 3.5.4 (June 19, 2020) =
* New: See translations in the update log
* New: We've added a few checks to WordPress' Site Health page
* Fix: Error with Companion Auto Update Database Update
* Fix: Schedule interval duplicates
= 3.5.3 (June 5, 2020) =
* New: We're working on a better update log. You should see the Update method (Manual/Automatic) in the log now. (Only works for Plugins right now)
Please report any issues with this feature over at our sticky post: [Problems with the Update method in the new update log?](https://wordpress.org/support/topic/problems-with-the-update-method-in-the-new-update-log/)
* Fix: Not able to see checks in boxes (reverted back to before it all went wrong)
* Fix: Error date_default_timezone_set(): Timezone ID +00:00 is invalid
* Tweak: The status tab will no longer show turned-off settings as an error
* Tweak: Made some improvements to the "Update pending" emails, you can now see a list of all pending updates and go directly to the update page.
= 3.5.2 (April 1, 2020) =
* Fix: Not able to see checks in boxes
= 3.5.1 (March 25, 2020) =
* Tweak: You seem to like the new dashboard, we've fixed a few issues regarding the responsiveness of the design. We've also tweaked the icons to be a bit more transparant.
* Tweak: We've added the release notes link to Plain text emails
* Tweak: Fixed a few typos
* Tweak: Various minor security improvements
= 3.5.0 (March 5, 2020) =
* New: In version 3.4.6 we've changed to HTML emails rather than plain text, in this version you can opt to change it back to plain text emails
* Fix: We've 'fixed an issue where on occasion nothing would update
* Tweak: Made some improvements to the "Fix it" button for the AUTOMATIC_UPDATER_DISABLED error
* Tweak: We've changed the dashboard, moved both the settings page and de support page to the dashboard. Please let us know if you like this change or not.
* Bug: We've had to (temporarily) disable the theme filter because it was causing issues on some installations. We'll try to get it working again in a future update.
[View full changelog](https://codeermeneer.nl/stuffs/auto-updater-changelog/)

View File

@ -1,134 +0,0 @@
<?php
/**
* This file creates a class to build our CSS.
*
* @package GP Premium
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access, please.
}
if ( ! class_exists( 'GeneratePress_Backgrounds_CSS' ) ) {
/**
* Generate our background CSS.
*/
class GeneratePress_Backgrounds_CSS {
/**
* The css selector that you're currently adding rules to
*
* @access protected
* @var string
*/
protected $_selector = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* Stores the final css output with all of its rules for the current selector.
*
* @access protected
* @var string
*/
protected $_selector_output = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* Stores all of the rules that will be added to the selector
*
* @access protected
* @var string
*/
protected $_css = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* The string that holds all of the css to output
*
* @access protected
* @var string
*/
protected $_output = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* Sets a selector to the object and changes the current selector to a new one
*
* @access public
* @since 1.0
*
* @param string $selector - the css identifier of the html that you wish to target.
* @return $this
*/
public function set_selector( $selector = '' ) {
// Render the css in the output string everytime the selector changes.
if ( '' !== $this->_selector ) {
$this->add_selector_rules_to_output();
}
$this->_selector = $selector;
return $this;
}
/**
* Adds a css property with value to the css output
*
* @access public
* @since 1.0
*
* @param string $property - the css property.
* @param string $value - the value to be placed with the property.
* @param string $url Whether we need to generate URL in the string.
* @return $this
*/
public function add_property( $property, $value, $url = '' ) {
// If we don't have a value or our value is the same as our og default, bail.
if ( empty( $value ) ) {
return false;
}
// Set up our background image URL param if needed.
$url_start = ( '' !== $url ) ? "url('" : ""; // phpcs:ignore -- need double quotes.
$url_end = ( '' !== $url ) ? "')" : ""; // phpcs:ignore -- need double quotes.
$this->_css .= $property . ':' . $url_start . $value . $url_end . ';';
return $this;
}
/**
* Adds the current selector rules to the output variable
*
* @access private
* @since 1.0
*
* @return $this
*/
private function add_selector_rules_to_output() {
if ( ! empty( $this->_css ) ) {
$this->_selector_output = $this->_selector;
$selector_output = sprintf( '%1$s{%2$s}', $this->_selector_output, $this->_css );
$this->_output .= $selector_output;
// Reset the css.
$this->_css = '';
}
return $this;
}
/**
* Returns the minified css in the $_output variable
*
* @access public
* @since 1.0
*
* @return string
*/
public function css_output() {
// Add current selector's rules to output.
$this->add_selector_rules_to_output();
// Output minified css.
return $this->_output;
}
}
}

Some files were not shown because too many files have changed in this diff Show More