├── .eslintrc ├── .extract-wp-hooks.json ├── CHANGELOG.md ├── CONTRIBUTE.md ├── LICENSE ├── README.md ├── SECURITY.md ├── THEMES.md ├── blocks ├── block-visibility │ ├── build │ │ ├── index.asset.php │ │ └── index.js │ └── src │ │ └── index.js ├── follow-me │ ├── block.json │ ├── build │ │ ├── index.asset.php │ │ └── index.js │ └── src │ │ └── index.js ├── friend-posts │ ├── block.json │ ├── build │ │ ├── index.asset.php │ │ └── index.js │ └── src │ │ └── index.js ├── friends-list │ ├── block.json │ ├── build │ │ ├── index.asset.php │ │ └── index.js │ └── src │ │ └── index.js └── message │ ├── block.json │ ├── build │ ├── index.asset.php │ └── index.js │ └── src │ └── index.js ├── composer.json ├── emojis.json ├── feed-parsers ├── SimplePie │ ├── class-simplepie-file-accept-only-rss.php │ └── class-simplepie-misc.php ├── activitypub │ ├── class-activitypub-transformer-message.php │ └── class-virtual-user-feed.php ├── class-feed-item.php ├── class-feed-parser-activitypub.php ├── class-feed-parser-json-feed.php ├── class-feed-parser-microformats.php ├── class-feed-parser-simplepie.php ├── class-feed-parser-v2.php └── class-feed-parser.php ├── friends-admin.css ├── friends-admin.js ├── friends-blocks.css ├── friends.css ├── friends.css.map ├── friends.js ├── friends.php ├── includes ├── class-access-control.php ├── class-admin.php ├── class-automatic-status-list-table.php ├── class-automatic-status.php ├── class-blocks.php ├── class-feed.php ├── class-friends.php ├── class-frontend.php ├── class-gamajo-template-loader-1-4-0.php ├── class-import.php ├── class-logging.php ├── class-messages.php ├── class-notifications.php ├── class-plugin-installer.php ├── class-reactions.php ├── class-rest.php ├── class-shortcodes.php ├── class-subscription.php ├── class-template-loader.php ├── class-third-parties.php ├── class-user-feed.php ├── class-user-query.php └── class-user.php ├── integrations └── class-enable-mastodon-apps.php ├── lerna.json ├── libs ├── Mf2 │ └── Parser.php └── blocks-everywhere │ ├── blocks-everywhere.php │ ├── build │ ├── images │ │ └── wordpress.e7ce7231.png │ ├── index.min.asset.php │ ├── index.min.js │ ├── style-index.min.css │ ├── support-content-editor.min.asset.php │ ├── support-content-editor.min.css │ ├── support-content-editor.min.js │ ├── support-content-view.min.asset.php │ ├── support-content-view.min.css │ ├── support-content-view.min.js │ └── theme-compat.min.css │ ├── classes │ ├── class-editor.php │ ├── class-handler.php │ └── handlers │ │ ├── class-friends-message.php │ │ └── class-friends-status-post.php │ └── readme.txt ├── phpcs.xml ├── phpunit.xml ├── plugin-installer.js ├── plugin-strings ├── friends-autoresolve-links.php ├── friends-debugger.php ├── friends-mastodon-like-interface.php ├── friends-parser-fraidyscrape.php ├── friends-parser-rss-bridge.php ├── friends-post-collection.php └── friends-send-to-e-reader.php ├── plugins.json ├── previous-changelog-entries.md ├── templates ├── admin │ ├── add-friend.php │ ├── add-reaction-li.php │ ├── automatic-status-list-table.php │ ├── browser-extension.php │ ├── dashboard-widget-welcome.php │ ├── dashboard-widget.php │ ├── duplicates.php │ ├── edit-feeds.php │ ├── edit-friend.php │ ├── edit-notifications.php │ ├── edit-raw-rules.php │ ├── edit-rules.php │ ├── friends-list.php │ ├── import-export.php │ ├── latest-friends.php │ ├── logs.php │ ├── notification-manager.php │ ├── opml.php │ ├── plugin-details.php │ ├── plugin-info.php │ ├── plugin-installer-footer.php │ ├── plugin-installer-header.php │ ├── preview-rules.php │ ├── reactions-picker.php │ ├── select-feeds.php │ ├── settings-footer.php │ ├── settings-header.php │ ├── settings-wp-friendships.php │ ├── settings.php │ ├── unfriend.php │ └── welcome.php ├── email │ ├── accepted-friend-request-text.php │ ├── accepted-friend-request.php │ ├── footer-text.php │ ├── footer.php │ ├── friend-message-received-text.php │ ├── friend-message-received.php │ ├── header.php │ ├── keyword-match-post-text.php │ ├── keyword-match-post.php │ ├── lost-follower-text.php │ ├── lost-follower.php │ ├── new-follower-text.php │ ├── new-follower.php │ ├── new-friend-post-text.php │ ├── new-friend-post.php │ ├── new-friend-request-text.php │ ├── new-friend-request.php │ ├── unknown-friend-message-received-text.php │ └── unknown-friend-message-received.php ├── embed │ ├── embed-content.php │ └── header-embed.php └── frontend │ ├── author-header.php │ ├── editor.php │ ├── error-message.php │ ├── followers.php │ ├── footer.php │ ├── header.php │ ├── index.php │ ├── main-feed-header.php │ ├── messages │ ├── author-header.php │ ├── friend.php │ └── message-form.php │ ├── no-friends.php │ ├── no-posts.php │ ├── parts │ ├── activitypub │ │ ├── boost-button.php │ │ ├── follow-link.php │ │ └── header-menu.php │ ├── comments-content.php │ ├── comments.php │ ├── content-image.php │ ├── content-status.php │ ├── content.php │ ├── entry-content.php │ ├── footer.php │ ├── header-menu.php │ ├── header-status.php │ ├── header.php │ ├── reactions.php │ ├── reblog-button.php │ └── title.php │ ├── reactions-picker.php │ └── single-header.php └── widgets ├── class-widget-base-friends-list.php ├── class-widget-friend-request.php ├── class-widget-friend-stats.php ├── class-widget-friends-list.php ├── class-widget-header.php ├── class-widget-new-private-post.php ├── class-widget-post-formats.php ├── class-widget-recent-friends-list.php ├── class-widget-refresh.php └── class-widget-starred-friends-list.php /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ "plugin:@wordpress/eslint-plugin/recommended" ] 3 | } 4 | -------------------------------------------------------------------------------- /.extract-wp-hooks.json: -------------------------------------------------------------------------------- 1 | { 2 | "namespace": "Friends", 3 | "wiki_directory": "../friends.wiki", 4 | "github_blob_url": "https://github.com/akirk/friends/blob/main/", 5 | "section": "file", 6 | "ignore_regex": "/^activitypub_/", 7 | "ignore_filter": [ 8 | "_get_template_part_", 9 | "_get_template_part", 10 | "_template_paths", 11 | "bulk_post_updated_messages", 12 | "convert_chars", 13 | "friends_debug", 14 | "edit_posts_per_page", 15 | "fake_http_response", 16 | "get_edit_user_link", 17 | "get_template_part_", 18 | "local_fetch_feed", 19 | "rest_api_init", 20 | "the_content", 21 | "widget_title", 22 | "wp_feed_cache_transient_lifetime", 23 | "wp_mail_from", 24 | "wp_update_comment_count", 25 | "wptexturize" 26 | ], 27 | "exclude_dirs": [ 28 | "blocks", 29 | "libs", 30 | "tests" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /CONTRIBUTE.md: -------------------------------------------------------------------------------- 1 | # Contributing to Friends Plugin 2 | 3 | Thank you for considering contributing to the Friends Plugin! We welcome contributions from the community and appreciate your interest in helping us improve our project. 4 | 5 | ## Table of Contents 6 | 7 | - [Getting Started](#getting-started) 8 | - [Coding Guidelines](#coding-guidelines) 9 | - [Compiling SCSS](#compiling-scss) 10 | - [Submitting Changes](#submitting-changes) 11 | - [Reporting Issues](#reporting-issues) 12 | 13 | ## Getting Started 14 | 15 | 1. **Fork the repository**: Click the "Fork" button on the top right corner of this page. 16 | 2. **Clone your fork**: 17 | ```bash 18 | git clone https://github.com/your-username/friends.git 19 | ``` 20 | 3. **Install Node.js dependencies**: 21 | Navigate to the project directory and run: 22 | ```bash 23 | npm install 24 | ``` 25 | 26 | ## Coding Guidelines 27 | 28 | - Follow the existing coding style in the project. 29 | - Write clear, descriptive commit messages. 30 | - Ensure your code is well-commented and easy to understand. 31 | 32 | ## Compiling SCSS 33 | 34 | To compile the SCSS files, run the following command in your terminal: 35 | 36 | ```bash 37 | npm run sass:compile 38 | ``` 39 | 40 | This will process the SCSS files and update the CSS output accordingly. 41 | 42 | ## Submitting Changes 43 | 44 | 1. **Create a new feature branch**: 45 | ```bash 46 | git checkout -b feature/your-feature-name 47 | ``` 48 | 2. **Make your changes**. 49 | 3. **Commit your changes**: 50 | ```bash 51 | git add . 52 | git commit -m "Add some feature" 53 | ``` 54 | 4. **Push to your fork**: 55 | ```bash 56 | git push origin feature/your-feature-name 57 | ``` 58 | 5. **Create a Pull Request**: Go to the original repository and click on the "New Pull Request" button. Select your branch and submit the pull request. 59 | 60 | ## Reporting Issues 61 | 62 | If you encounter any bugs or have suggestions for improvement, please open an issue in this repository. Provide as much detail as possible, including steps to reproduce the issue. 63 | 64 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Reporting a Vulnerability 2 | 3 | If you find a security vulnerability with the Friends plugin, please contact me at https://alex.kirk.at/contact/ and I'll follow up with you on the next steps. 4 | -------------------------------------------------------------------------------- /THEMES.md: -------------------------------------------------------------------------------- 1 | # Friends Themes 2 | 3 | Here you can find themes that have been created for the Friends plugin. 4 | 5 | - [Mastodon-like interface](https://github.com/akirk/friends-mastodon-like-interface) 6 | 7 | If you want to create your own theme, take a look at the [wiki page on Writing Themes](https://github.com/akirk/friends/wiki/Writing-Themes). 8 | -------------------------------------------------------------------------------- /blocks/block-visibility/build/index.asset.php: -------------------------------------------------------------------------------- 1 | array('wp-block-editor', 'wp-components', 'wp-compose', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'd734ad9fe0363b9d44a8'); 2 | -------------------------------------------------------------------------------- /blocks/block-visibility/build/index.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e=window.wp.element,n=window.wp.i18n,i=window.wp.hooks,t=window.wp.compose,l=window.wp.blockEditor,s=window.wp.components;const o=(0,t.createHigherOrderComponent)((i=>t=>{const{attributes:o,setAttributes:r}=t;let a="";return void 0!==o.className&&(/\bonly-friends\b/.test(o.className)?a="only-friends":/\bnot-friends\b/.test(o.className)&&(a="not-friends")),(0,e.createElement)(e.Fragment,null,(0,e.createElement)(i,t),(0,e.createElement)(l.InspectorControls,null,(0,e.createElement)(s.PanelBody,{className:"friends-block-visibility",title:(0,n.__)("Friends Visibility","friends")},(0,e.createElement)(s.SelectControl,{label:(0,n.__)("Block visibility","friends"),onChange:e=>{const n=((o.className||"").replace(/\b(only|not)-friends\b/g,"")+" "+e).replace(/^\s+|\s+$/,"");r({className:n})},value:a,options:[{label:(0,n.__)("For everyone","friends"),value:""},{label:(0,n.__)("Only friends","friends"),value:"only-friends"},{label:(0,n.__)("Everyone except friends","friends"),value:"not-friends"}]}))))}),"withFriendsBlockVisibility");(0,i.addFilter)("editor.BlockEdit","friends/block-visibility",o)}(); -------------------------------------------------------------------------------- /blocks/block-visibility/src/index.js: -------------------------------------------------------------------------------- 1 | import { __ } from '@wordpress/i18n'; 2 | import { addFilter } from '@wordpress/hooks'; 3 | import { createHigherOrderComponent } from '@wordpress/compose'; 4 | import { InspectorControls } from '@wordpress/block-editor'; 5 | import { PanelBody, SelectControl } from '@wordpress/components'; 6 | 7 | const friendsBlockVisibility = createHigherOrderComponent( ( BlockEdit ) => { 8 | return ( props ) => { 9 | const { attributes, setAttributes } = props; 10 | let friendsVisibility = ''; 11 | if ( typeof attributes.className !== 'undefined' ) { 12 | if ( /\bonly-friends\b/.test( attributes.className ) ) { 13 | friendsVisibility = 'only-friends'; 14 | } else if ( /\bnot-friends\b/.test( attributes.className ) ) { 15 | friendsVisibility = 'not-friends'; 16 | } 17 | } 18 | return ( 19 | <> 20 | 21 | 22 | 23 | { 26 | const className = ((attributes.className || '').replace( /\b(only|not)-friends\b/g, '' ) + ' ' + friendsVisibility).replace(/^\s+|\s+$/, '' ); 27 | setAttributes( { className } ) } 28 | } 29 | value={ friendsVisibility } 30 | options={ [ 31 | { 32 | label: __( 'For everyone', 'friends' ), 33 | value: '', 34 | }, 35 | { 36 | label: __( 'Only friends', 'friends' ), 37 | value: 'only-friends', 38 | }, 39 | { 40 | label: __( 'Everyone except friends', 'friends' ), 41 | value: 'not-friends', 42 | }, 43 | ] } 44 | /> 45 | 46 | 47 | 48 | ); 49 | }; 50 | }, 'withFriendsBlockVisibility' ); 51 | 52 | addFilter( 'editor.BlockEdit', 'friends/block-visibility', friendsBlockVisibility ); 53 | -------------------------------------------------------------------------------- /blocks/follow-me/block.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schemas.wp.org/trunk/block.json", 3 | "apiVersion": 2, 4 | "name": "friends/follow-me", 5 | "title": "Follow Me", 6 | "category": "widgets", 7 | "textdomain": "friends", 8 | "icon": "groups", 9 | "attributes": {}, 10 | "example": {}, 11 | "editorScript": "file:./build/index.js" 12 | } 13 | -------------------------------------------------------------------------------- /blocks/follow-me/build/index.asset.php: -------------------------------------------------------------------------------- 1 | array('wp-block-editor', 'wp-blocks', 'wp-element', 'wp-i18n', 'wp-polyfill'), 'version' => 'c192f5095b204b8c70c554a1dd555d65'); -------------------------------------------------------------------------------- /blocks/follow-me/build/index.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=4)}([function(e,t){e.exports=window.wp.element},function(e,t){e.exports=window.wp.blockEditor},function(e,t){e.exports=window.wp.i18n},function(e,t){e.exports=window.wp.blocks},function(e,t,n){"use strict";n.r(t);var r=n(0),o=n(2),c=n(3),l=n(1);function i(e){return Object(r.createElement)("div",null,Object(r.createElement)("input",{type:"text",name:"friends_friend_request_url",placeholder:"https://example.com/"})," ",Object(r.createElement)("button",{disabled:e?null:"disabled"},Object(o.__)("Follow this site","friends")))}Object(c.registerBlockType)("friends/follow-me",{apiVersion:2,edit:function(){var e=Object(o.__)('Enter your blog URL to join my network. Learn more',"friends");return Object(r.createElement)("div",Object(l.useBlockProps)(),Object(r.createElement)("form",{method:"post"},Object(r.createElement)(l.InnerBlocks,{template:[["core/paragraph",{content:e}]]}),i(!1)))},save:function(){var e=l.useBlockProps.save();return Object(r.createElement)("div",e,Object(r.createElement)("form",{method:"post"},Object(r.createElement)(l.InnerBlocks.Content,null),i(!0)))}})}]); -------------------------------------------------------------------------------- /blocks/follow-me/src/index.js: -------------------------------------------------------------------------------- 1 | import { __ } from '@wordpress/i18n'; 2 | import { registerBlockType } from '@wordpress/blocks'; 3 | import { useBlockProps } from '@wordpress/block-editor'; 4 | import { InnerBlocks } from "@wordpress/block-editor"; 5 | 6 | function getHTML( is_saving ) { 7 | return ( 8 |
9 | 10 |   11 | 12 |
13 | ); 14 | } 15 | 16 | registerBlockType( 'friends/follow-me', { 17 | apiVersion: 2, 18 | edit: function() { 19 | const content = __( 'Enter your blog URL to join my network. Learn more', 'friends' ); 20 | return ( 21 |
22 |
23 | 30 | 31 | { getHTML( false ) } 32 | 33 |
34 | ); 35 | }, 36 | save: () => { 37 | const blockProps = useBlockProps.save(); 38 | 39 | return ( 40 |
41 |
42 | 43 | { getHTML( true ) } 44 | 45 |
46 | ); 47 | }, 48 | } ); 49 | -------------------------------------------------------------------------------- /blocks/friend-posts/block.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schemas.wp.org/trunk/block.json", 3 | "apiVersion": 2, 4 | "name": "friends/friend-posts", 5 | "title": "Friend Posts", 6 | "category": "widgets", 7 | "textdomain": "friends", 8 | "icon": "groups", 9 | "attributes": { 10 | "author_inline": { 11 | "type": "boolean", 12 | "default": false 13 | }, 14 | "author_name": { 15 | "type": "boolean", 16 | "default": true 17 | }, 18 | "author_avatar": { 19 | "type": "boolean", 20 | "default": true 21 | }, 22 | "show_date": { 23 | "type": "boolean", 24 | "default": true 25 | }, 26 | "count": { 27 | "type": "number", 28 | "default": 5 29 | }, 30 | "exclude_users": { 31 | "type": "string" 32 | }, 33 | "only_users": { 34 | "type": "string" 35 | }, 36 | "internal_link": { 37 | "type": "boolean", 38 | "default": false 39 | } 40 | }, 41 | "example": { 42 | "attributes": {} 43 | }, 44 | "editorScript": "file:./build/index.js" 45 | } 46 | -------------------------------------------------------------------------------- /blocks/friend-posts/build/index.asset.php: -------------------------------------------------------------------------------- 1 | array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '8f351f3f1c3a7a97ca51'); 2 | -------------------------------------------------------------------------------- /blocks/friend-posts/build/index.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e={n:function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,{a:t}),t},d:function(n,t){for(var r in t)e.o(t,r)&&!e.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:t[r]})},o:function(e,n){return Object.prototype.hasOwnProperty.call(e,n)}},n=window.wp.element,t=window.wp.i18n,r=window.wp.blocks,o=window.wp.blockEditor,a=window.wp.components,l=window.wp.serverSideRender,c=e.n(l);(0,r.registerBlockType)("friends/friend-posts",{apiVersion:2,edit:function(e){let{attributes:r,setAttributes:l}=e;const s=(0,o.useBlockProps)();return(0,n.createElement)(n.Fragment,null,(0,n.createElement)(o.InspectorControls,null,(0,n.createElement)(a.PanelBody,null,(0,n.createElement)(a.CheckboxControl,{label:(0,t.__)("Display Author name","friends"),checked:r.author_name,onChange:e=>l({author_name:e})}),(0,n.createElement)(a.CheckboxControl,{label:(0,t.__)("Display Author avatar","friends"),checked:r.author_avatar,onChange:e=>l({author_avatar:e})}),(0,n.createElement)(a.CheckboxControl,{label:(0,t.__)("Show Author inline","friends"),checked:r.author_inline,onChange:e=>l({author_inline:e})}),(0,n.createElement)(a.CheckboxControl,{label:(0,t.__)("Show Date","friends"),checked:r.show_date,onChange:e=>l({show_date:e})}),(0,n.createElement)(a.RangeControl,{label:(0,t.__)("Number of posts","friends"),value:r.count,onChange:e=>l({count:e}),min:1,max:100}),(0,n.createElement)(a.TextControl,{label:(0,t.__)("Exclude these users","friends"),placeholder:(0,t.__)("space and/or comma separated","friends"),value:r.exclude_users,onChange:e=>l({exclude_users:e})}),(0,n.createElement)(a.TextControl,{label:(0,t.__)("Only these users","friends"),placeholder:(0,t.__)("space and/or comma separated","friends"),value:r.only_users,onChange:e=>l({only_users:e})}),(0,n.createElement)(a.CheckboxControl,{label:(0,t.__)("Link to local page","friends"),checked:r.internal_link,onChange:e=>l({internal_link:e})}))),(0,n.createElement)("div",s,(0,n.createElement)(c(),{block:"friends/friend-posts",attributes:r})))},save(){return null}})}(); -------------------------------------------------------------------------------- /blocks/friend-posts/src/index.js: -------------------------------------------------------------------------------- 1 | import { __ } from '@wordpress/i18n'; 2 | import { registerBlockType } from '@wordpress/blocks'; 3 | import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; 4 | import { CheckboxControl, PanelBody, RangeControl, SelectControl, TextControl } from '@wordpress/components'; 5 | import ServerSideRender from '@wordpress/server-side-render'; 6 | 7 | registerBlockType( 'friends/friend-posts', { 8 | apiVersion: 2, 9 | edit: function( { attributes, setAttributes } ) { 10 | const blockProps = useBlockProps(); 11 | return ( 12 | <> 13 | 14 | 15 | setAttributes( { author_name } ) } 19 | /> 20 | setAttributes( { author_avatar } ) } 24 | /> 25 | setAttributes( { author_inline } ) } 29 | /> 30 | setAttributes( { show_date } ) } 34 | /> 35 | setAttributes( { count } ) } 39 | min={ 1 } 40 | max={ 100 } 41 | /> 42 | setAttributes( { exclude_users } ) } 47 | /> 48 | setAttributes( { only_users } ) } 53 | /> 54 | setAttributes( { internal_link } ) } 58 | /> 59 | 60 | 61 |
62 | 66 |
67 | 68 | ); 69 | }, 70 | 71 | save() { 72 | return null; 73 | }, 74 | } ); 75 | -------------------------------------------------------------------------------- /blocks/friends-list/block.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schemas.wp.org/trunk/block.json", 3 | "apiVersion": 2, 4 | "name": "friends/friends-list", 5 | "title": "Friends List", 6 | "category": "widgets", 7 | "textdomain": "friends", 8 | "icon": "groups", 9 | "attributes": { 10 | "users_inline": { 11 | "type": "boolean", 12 | "default": false 13 | }, 14 | "user_types": { 15 | "type": "string" 16 | } 17 | }, 18 | "example": { 19 | "attributes": { 20 | "user_types": "friends" 21 | } 22 | }, 23 | "editorScript": "file:./build/index.js" 24 | } 25 | -------------------------------------------------------------------------------- /blocks/friends-list/build/index.asset.php: -------------------------------------------------------------------------------- 1 | array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'ea0e64f6d793946cdea4'); 2 | -------------------------------------------------------------------------------- /blocks/friends-list/build/index.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e={n:function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(r,{a:r}),r},d:function(n,r){for(var t in r)e.o(r,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:r[t]})},o:function(e,n){return Object.prototype.hasOwnProperty.call(e,n)}},n=window.wp.element,r=window.wp.i18n,t=window.wp.blocks,s=window.wp.blockEditor,i=window.wp.components,l=window.wp.serverSideRender,o=e.n(l);(0,t.registerBlockType)("friends/friends-list",{apiVersion:2,edit:function(e){let{attributes:t,setAttributes:l}=e;const u=(0,s.useBlockProps)();return(0,n.createElement)(n.Fragment,null,(0,n.createElement)(s.InspectorControls,null,(0,n.createElement)(i.PanelBody,null,(0,n.createElement)(i.CheckboxControl,{label:(0,r.__)("Display Users inline","friends"),checked:t.users_inline,onChange:e=>l({users_inline:e})}),(0,n.createElement)(i.SelectControl,{label:(0,r.__)("User Types","friends"),onChange:e=>l({user_types:e}),value:t.user_types,options:[{label:(0,r.__)("Friends","friends"),value:"friends"},{label:(0,r.__)("Friend requests","friends"),value:"friend_requests"},{label:(0,r.__)("Subscriptions","friends"),value:"subscriptions"},{label:(0,r.__)("Friends + Subscriptions","friends"),value:"friends_subscriptions"}]}))),(0,n.createElement)("div",u,(0,n.createElement)(o(),{block:"friends/friends-list",attributes:t})))},save(){return null}})}(); -------------------------------------------------------------------------------- /blocks/friends-list/src/index.js: -------------------------------------------------------------------------------- 1 | import { __ } from '@wordpress/i18n'; 2 | import { registerBlockType } from '@wordpress/blocks'; 3 | import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; 4 | import { CheckboxControl, PanelBody, SelectControl, TextControl } from '@wordpress/components'; 5 | import ServerSideRender from '@wordpress/server-side-render'; 6 | 7 | registerBlockType( 'friends/friends-list', { 8 | apiVersion: 2, 9 | edit: function( { attributes, setAttributes } ) { 10 | const blockProps = useBlockProps(); 11 | return ( 12 | <> 13 | 14 | 15 | setAttributes( { users_inline } ) } 19 | /> 20 | setAttributes( { user_types } ) } 23 | value={ attributes.user_types } 24 | options={ [ 25 | { 26 | label: __( 'Friends', 'friends' ), 27 | value: 'friends', 28 | }, 29 | { 30 | label: __( 'Friend requests', 'friends' ), 31 | value: 'friend_requests', 32 | }, 33 | { 34 | label: __( 'Subscriptions', 'friends' ), 35 | value: 'subscriptions', 36 | }, 37 | { 38 | label: __( 'Friends + Subscriptions', 'friends' ), 39 | value: 'friends_subscriptions', 40 | }, 41 | ] } 42 | /> 43 | 44 | 45 |
46 | 50 |
51 | 52 | ); 53 | }, 54 | 55 | save() { 56 | return null; 57 | }, 58 | } ); 59 | -------------------------------------------------------------------------------- /blocks/message/block.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schemas.wp.org/trunk/block.json", 3 | "apiVersion": 2, 4 | "name": "friends/message", 5 | "title": "Friend Message", 6 | "category": "widgets", 7 | "textdomain": "friends", 8 | "icon": "groups", 9 | "attributes": { 10 | "sender": { 11 | "type": "number" 12 | }, 13 | "date": { 14 | "type": "number" 15 | } 16 | }, 17 | "example": {}, 18 | "editorScript": "file:./build/index.js" 19 | } 20 | -------------------------------------------------------------------------------- /blocks/message/build/index.asset.php: -------------------------------------------------------------------------------- 1 | array('wp-block-editor', 'wp-blocks', 'wp-element', 'wp-i18n'), 'version' => '76626e82b74710c6be3d'); 2 | -------------------------------------------------------------------------------- /blocks/message/build/index.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e=window.wp.element,n=(window.wp.i18n,window.wp.blocks),t=window.wp.blockEditor;(0,n.registerBlockType)("friends/message",{apiVersion:2,edit:function(){return(0,e.createElement)("div",(0,t.useBlockProps)(),(0,e.createElement)(t.InnerBlocks,null))},save:()=>{const n=t.useBlockProps.save();return(0,e.createElement)("div",n,(0,e.createElement)(t.InnerBlocks.Content,null))}})}(); -------------------------------------------------------------------------------- /blocks/message/src/index.js: -------------------------------------------------------------------------------- 1 | import { __ } from '@wordpress/i18n'; 2 | import { registerBlockType } from '@wordpress/blocks'; 3 | import { useBlockProps } from '@wordpress/block-editor'; 4 | import { InnerBlocks } from "@wordpress/block-editor"; 5 | 6 | registerBlockType( 'friends/message', { 7 | apiVersion: 2, 8 | edit: function() { 9 | return ( 10 |
11 | 12 |
13 | ); 14 | }, 15 | save: () => { 16 | const blockProps = useBlockProps.save(); 17 | 18 | return ( 19 |
20 | 21 |
22 | ); 23 | }, 24 | } ); 25 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "akirk/friends", 3 | "description": "A social network between WordPresses. Privacy focused, by itself a self-hosted RSS++ reader with notifications.", 4 | "license": "GPL-2.0-or-later", 5 | "require-dev": { 6 | "phpcompatibility/php-compatibility": "dev-develop as 9.99.99", 7 | "phpcompatibility/phpcompatibility-wp": "*", 8 | "wp-coding-standards/wpcs": "*", 9 | "yoast/phpunit-polyfills": "*", 10 | "php-parallel-lint/php-parallel-lint": "^1.3", 11 | "phpunit/phpunit": "9.*", 12 | "akirk/extract-wp-hooks": "*" 13 | }, 14 | "config": { 15 | "allow-plugins": { 16 | "dealerdirect/phpcodesniffer-composer-installer": true 17 | } 18 | }, 19 | "prefer-stable": true, 20 | "scripts": { 21 | "lint": [ 22 | "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git" 23 | ], 24 | "check-cs": [ 25 | "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" 26 | ], 27 | "fix-cs": [ 28 | "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf" 29 | ], 30 | "test": [ 31 | "@php ./vendor/phpunit/phpunit/phpunit --no-coverage" 32 | ], 33 | "update-wiki": [ 34 | "test -d ../friends.wiki && php ./vendor/akirk/extract-wp-hooks/extract-wp-hooks.php && cd ../friends.wiki/ && git add . && git commit -m 'Update hooks'; git push" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /feed-parsers/SimplePie/class-simplepie-file-accept-only-rss.php: -------------------------------------------------------------------------------- 1 | in_reply_to; 25 | } 26 | 27 | protected function get_to() { 28 | return $this->to; 29 | } 30 | 31 | protected function get_cc() { 32 | return $this->cc; 33 | } 34 | 35 | protected function get_mentions() { 36 | if ( ! isset( $this->mentions ) ) { 37 | $this->mentions = array(); 38 | foreach ( (array) $this->to as $to ) { 39 | $acct = \Activitypub\Webfinger::uri_to_acct( $to ); 40 | if ( $acct && ! is_wp_error( $acct ) ) { 41 | $acct = str_replace( 'acct:', '@', $acct ); 42 | } 43 | $this->mentions[ $acct ] = $to; 44 | } 45 | } 46 | return $this->mentions; 47 | } 48 | 49 | protected function get_content() { 50 | $post = $this->item; 51 | $content = $post->post_content; 52 | if ( ! $content ) { 53 | $content = ''; 54 | } 55 | 56 | $mentions = ''; 57 | foreach ( $this->get_mentions() as $acct => $to ) { 58 | $acct = substr( $acct, 0, strpos( $acct, '@', 1 ) ); 59 | $mention = sprintf( 60 | '', 61 | esc_url( $to ) 62 | ); 63 | if ( strpos( $content, $mention ) !== false ) { 64 | continue; 65 | } 66 | 67 | if ( strpos( $content, $acct ) !== false ) { 68 | $content = str_replace( $acct, $mention . esc_html( $acct ) . '', $content ); 69 | } else { 70 | $mentions .= $mention . esc_html( $acct ) . ' '; 71 | } 72 | } 73 | 74 | if ( preg_match( '/^(]*>)/', $content, $m ) ) { 75 | $content = $m[1] . $mentions . substr( $content, strlen( $m[1] ) ); 76 | } else { 77 | $content = $mentions . \trim( $content ); 78 | } 79 | 80 | $content = \wpautop( $content ); 81 | $content = \preg_replace( '/[\n\r\t]/', '', $content ); 82 | $content = \trim( $content ); 83 | 84 | /** 85 | * Filter the content of the comment. 86 | * 87 | * @param string $content The content of the comment. 88 | * @param \WP_Comment $comment The comment object. 89 | * 90 | * @return string The filtered content of the comment. 91 | */ 92 | return \apply_filters( 'activitypub_the_content', $content ); 93 | } 94 | 95 | public function get_likes() { 96 | // You can't fetch likes for a message. 97 | return null; 98 | } 99 | 100 | public function get_shares() { 101 | // You can't fetch shares for a message. 102 | return null; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /feed-parsers/activitypub/class-virtual-user-feed.php: -------------------------------------------------------------------------------- 1 | friend_user = $friend_user; 21 | $this->title = $title; 22 | } 23 | public function __toString() { 24 | } 25 | public function get_id() { 26 | return 'virtual-user-feed-' . $this->friend_user->get_id(); 27 | } 28 | public function get_url() { 29 | return null; 30 | } 31 | public function get_private_url( $validity = 3600 ) { 32 | return null; 33 | } 34 | public function get_friend_user() { 35 | return $this->friend_user; 36 | } 37 | public function get_active() { 38 | return false; 39 | } 40 | public function get_post_format() { 41 | return 'status'; 42 | } 43 | public function get_parser() { 44 | return 'virtual'; 45 | } 46 | public function get_mime_type() { 47 | return ''; 48 | } 49 | public function get_title() { 50 | return $this->title; 51 | } 52 | public function get_last_log() { 53 | return ''; 54 | } 55 | public function is_active() { 56 | return true; 57 | } 58 | public function get_interval() { 59 | return 0; 60 | } 61 | public function get_modifier() { 62 | return 0; 63 | } 64 | public function get_next_poll() { 65 | return 0; 66 | } 67 | public function was_polled() { 68 | return false; 69 | } 70 | public function can_be_polled_now() { 71 | return true; 72 | } 73 | public function set_polling_now() { 74 | return true; 75 | } 76 | public function activate() { 77 | return true; 78 | } 79 | public function deactivate() { 80 | return false; 81 | } 82 | public function delete() { 83 | return false; 84 | } 85 | public function get_metadata( $key ) { 86 | return null; 87 | } 88 | public function update_metadata( $key, $value ) { 89 | return $value; 90 | } 91 | public function delete_metadata( $key ) { 92 | return null; 93 | } 94 | public function update_last_log( $value ) { 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /feed-parsers/class-feed-parser-v2.php: -------------------------------------------------------------------------------- 1 | 'https://url.of/the/feed/item', 25 | * 'title' => 'Title for the feed item', 26 | * 'content' => 'Content for the feed item', 27 | * 'date' => gmdate( 'Y-m-d H:i:s' ), 28 | * // Optional fields: 29 | * 'comment_count' => 0, 30 | * 'gravatar' => 'https://url/icon.png', 31 | * 'post_status' => 'publish', // A WordPress post status (e.g. publish or private). 32 | * 'post_id' => 123, // the id of the post for better update/duplicate detection. 33 | * 'updated_date' => gmdate( 'Y-m-d H:i:s' ), 34 | * ), 35 | * ); 36 | * 37 | * @param string $url The url. 38 | * @param User_Feed $user_feed The user feed. 39 | * 40 | * @return array An array of feed items. 41 | */ 42 | public function fetch_feed( $url, ?User_Feed $user_feed = null ) { 43 | return array(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /feed-parsers/class-feed-parser.php: -------------------------------------------------------------------------------- 1 | 'https://url.of/the/feed', 37 | * 'title' => 'Title from the tag if any', 38 | * 'mime-type' => 'mime-type from the tag if any', 39 | * // You can add these fields in the response: 40 | * 'autoselect' => true|false, 41 | * 'post-format' => 'standard', // or 'aside', etc. see get_post_format_strings() of WordPress core 42 | * ); 43 | * 44 | * @param array $feed_details The feed details. 45 | * 46 | * @return array The (potentially) modified feed details. 47 | */ 48 | public function update_feed_details( $feed_details ) { 49 | return $feed_details; 50 | } 51 | 52 | /** 53 | * Discover the feeds available at the URL specified. 54 | * 55 | * The content for the URL has already been fetched for you which can be analyzed. 56 | * 57 | * Return an array of supported feeds in the format of the $feed_details above: 58 | * 59 | * return array( 60 | * array( 61 | * 'url' => 'https://url.of/the/feed', 62 | * 'title' => 'Title for the feed', 63 | * 'mime-type' => 'mime-type for the feed', 64 | * 'rel' => 'e.g. alternate', 65 | * ), 66 | * ); 67 | * 68 | * @param string $content The content for the URL is already provided here. 69 | * @param string $url The url to search. 70 | * 71 | * @return array A list of supported feeds at the URL. 72 | */ 73 | public function discover_available_feeds( $content, $url ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed 74 | return array(); 75 | } 76 | 77 | /** 78 | * Convert relative URLs to absolute ones in incoming content. 79 | * 80 | * @param string $html The html. 81 | * @param string $permalink The permalink of the feed. 82 | * 83 | * @return string The HTML with URLs replaced to their absolute represenation. 84 | */ 85 | public function convert_relative_urls_to_absolute_urls( $html, $permalink ) { 86 | if ( ! $html ) { 87 | $html = ''; 88 | } 89 | 90 | // Strip off the hash. 91 | $permalink = strtok( $permalink, '#' ); 92 | 93 | // For now this only converts links and image srcs. 94 | return preg_replace_callback( 95 | '~(src|href)=(?:"([^"]+)|\'([^\']+))~i', 96 | function ( $m ) use ( $permalink ) { 97 | // Don't update hash-only links. 98 | if ( str_starts_with( $m[2], '#' ) ) { 99 | return $m[0]; 100 | } 101 | 102 | // Remove absolute URL from hashes so that it can become relative. 103 | if ( str_starts_with( $m[2], $permalink . '#' ) ) { 104 | return str_replace( $permalink, '', $m[0] ); 105 | } 106 | 107 | // Don't convert content URLs like data:image/png;base64, etc. 108 | if ( str_starts_with( $m[2], 'data:' ) ) { 109 | return $m[0]; 110 | } 111 | 112 | // Convert relative URLs to absolute ones. 113 | return str_replace( $m[2], Mf2\resolveUrl( $permalink, $m[2] ), $m[0] ); 114 | }, 115 | $html 116 | ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /friends-blocks.css: -------------------------------------------------------------------------------- 1 | 2 | .only-friends { 3 | background-color: #efe; 4 | padding-left: .5em; 5 | } 6 | 7 | .not-friends { 8 | background-color: #fee; 9 | padding-left: .5em; 10 | } 11 | 12 | .only-friends .watermark, .not-friends .watermark { 13 | float: right; 14 | padding-top: .5em; 15 | padding-right: .5em; 16 | font-size: 80%; 17 | color: #ccc; 18 | } 19 | 20 | ul.friend-posts img.avatar { 21 | vertical-align: middle; 22 | margin-right: .3em; 23 | } 24 | -------------------------------------------------------------------------------- /includes/class-import.php: -------------------------------------------------------------------------------- 1 | save_feed( 62 | $xml_url, 63 | array( 64 | 'active' => true, 65 | 'mime-type' => 'atom' === (string) $friend['type'] ? 'application/atom+xml' : 'application/rss+xml', 66 | ) 67 | ); 68 | 69 | if ( ! $feed instanceof User_Feed ) { 70 | if ( is_wp_error( $feed ) && apply_filters( 'friends_debug', false ) ) { 71 | wp_trigger_error( __FUNCTION__, $feed->get_error_message() ); 72 | 73 | } 74 | return null; 75 | } 76 | 77 | return $feed; 78 | } 79 | 80 | private static function recurse_into_opml( $feeds, $friend ) { 81 | $xml_url = (string) $friend['xmlUrl']; 82 | if ( $xml_url ) { 83 | $feed = self::get_feed_from_opml_node( $friend ); 84 | if ( $feed instanceof User_Feed ) { 85 | $friend_user = $feed->get_friend_user(); 86 | 87 | if ( ! isset( $feeds[ $friend_user->user_login ] ) ) { 88 | $feeds[ $friend_user->user_login ] = array(); 89 | } 90 | $feeds[ $friend_user->user_login ][] = $feed; 91 | } 92 | return $feeds; 93 | } 94 | 95 | foreach ( $friend->outline as $child ) { 96 | $feeds = self::recurse_into_opml( $feeds, $child ); 97 | } 98 | 99 | return $feeds; 100 | } 101 | 102 | public static function opml( $opml ) { 103 | $opml = simplexml_load_string( $opml ); 104 | if ( ! $opml ) { 105 | return new \WP_Error( 'friends_import_opml_error', __( 'Failed to parse OPML.', 'friends' ) ); 106 | } 107 | 108 | $feeds = self::recurse_into_opml( array(), $opml->body ); 109 | 110 | return $feeds; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /includes/class-shortcodes.php: -------------------------------------------------------------------------------- 1 | friends = $friends; 35 | $this->register_shortcodes(); 36 | } 37 | 38 | /** 39 | * Register the WordPress shortcodes 40 | */ 41 | private function register_shortcodes() { 42 | add_shortcode( 'only-friends', array( $this, 'only_friends_shortcode' ) ); 43 | add_shortcode( 'not-friends', array( $this, 'not_friends_shortcode' ) ); 44 | add_shortcode( 'friends-list', array( $this, 'friends_list_shortcode' ) ); 45 | add_shortcode( 'friends-count', array( $this, 'friends_count_shortcode' ) ); 46 | } 47 | 48 | /** 49 | * Display the content of this shortcode just to friends. 50 | * 51 | * @param array $atts Attributes provided by the user. 52 | * @param string $content Enclosed content provided by the user. 53 | * @return string The content to be output. 54 | */ 55 | public function only_friends_shortcode( $atts, $content = null ) { 56 | if ( current_user_can( 'friend' ) ) { 57 | return do_shortcode( $content ); 58 | } 59 | 60 | if ( friends::has_required_privileges() ) { 61 | return '
' . __( 'Only friends', 'friends' ) . '' . do_shortcode( $content ) . '
'; 62 | } 63 | 64 | return ''; 65 | } 66 | 67 | /** 68 | * Display the content of this shortcode to everyone except friends. 69 | * 70 | * @param array $atts Attributes provided by the user. 71 | * @param string $content Enclosed content provided by the user. 72 | * @return string The content to be output. 73 | */ 74 | public function not_friends_shortcode( $atts, $content = null ) { 75 | if ( current_user_can( 'friend' ) ) { 76 | return ''; 77 | } 78 | 79 | if ( friends::has_required_privileges() ) { 80 | return '
' . __( 'Not friends', 'friends' ) . '' . do_shortcode( $content ) . '
'; 81 | } 82 | 83 | return do_shortcode( $content ); 84 | } 85 | 86 | /** 87 | * Display a list of your friends. 88 | * 89 | * @param array $atts Attributes provided by the user. 90 | * @return string The content to be output. 91 | */ 92 | public function friends_list_shortcode( $atts ) { 93 | $a = shortcode_atts( 94 | array( 95 | 'include-links' => false, 96 | ), 97 | $atts 98 | ); 99 | 100 | $friends = User_Query::all_friends(); 101 | $ret = ''; 121 | 122 | return $ret; 123 | } 124 | 125 | /** 126 | * Display the number of your friends. 127 | * 128 | * @return string The content to be output. 129 | */ 130 | public function friends_count_shortcode() { 131 | $friends = User_Query::all_friends(); 132 | return $friends->get_total(); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /includes/class-template-loader.php: -------------------------------------------------------------------------------- 1 | friends = $friends; 35 | $this->register_hooks(); 36 | } 37 | 38 | /** 39 | * Register the WordPress hooks 40 | */ 41 | private function register_hooks() { 42 | add_filter( 'option_fx-private-site', array( $this, 'fx_private_site' ) ); 43 | add_filter( 'wp_sweep_excluded_taxonomies', array( $this, 'wp_sweep_excluded_taxonomies' ) ); 44 | } 45 | 46 | /** 47 | * Allow accessing the private feed when the FX Private Site plugin is installed. 48 | * 49 | * @param mixed $value Value of the option. 50 | */ 51 | public function fx_private_site( $value ) { 52 | if ( $this->friends->access_control->feed_is_authenticated() ) { 53 | $value['enable'] = false; 54 | } 55 | return $value; 56 | } 57 | 58 | /** 59 | * WP Sweep 60 | * Prevent WP Sweep from sweeping our taxonomies. 61 | * 62 | * @since 2.0 63 | * 64 | * @param array $excluded_taxonomies list of taxonomies excluded from sweeping. 65 | * @return array 66 | */ 67 | public function wp_sweep_excluded_taxonomies( $excluded_taxonomies ) { 68 | return array_merge( $excluded_taxonomies, array( User_Feed::TAXONOMY, User_Feed::POST_TAXONOMY, Subscription::TAXONOMY ) ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /integrations/class-enable-mastodon-apps.php: -------------------------------------------------------------------------------- 1 | get_feeds() as $feed ) { 33 | if ( $feed->is_active() ) { 34 | continue; 35 | } 36 | if ( class_exists( 'Friends\Feed_Parser_ActivityPub' ) && Feed_Parser_ActivityPub::SLUG === $feed->get_parser() ) { 37 | $feed->activate(); 38 | } 39 | } 40 | return $user_id; 41 | } 42 | 43 | public static function mastodon_api_account_unfollow( $user_id ) { 44 | $user = User::get_user_by_id( $user_id ); 45 | foreach ( $user->get_active_feeds() as $feed ) { 46 | $feed->deactivate(); 47 | } 48 | } 49 | 50 | public static function mastodon_api_view_post_types( $view_post_types ) { 51 | $view_post_types[] = Friends::CPT; 52 | return $view_post_types; 53 | } 54 | 55 | public static function mastodon_api_favourites_args( $args, $user_id ) { 56 | return self::mastodon_api_reaction_args( 57 | apply_filters( 'friends_favourites_emoji', '2764' ), // ❤️ 58 | $args, 59 | $user_id 60 | ); 61 | } 62 | public static function mastodon_api_bookmarks_args( $args, $user_id ) { 63 | return self::mastodon_api_reaction_args( 64 | apply_filters( 'friends_bookmarks_emoji', '2b50' ), // ⭐ 65 | $args, 66 | $user_id 67 | ); 68 | } 69 | 70 | protected static function mastodon_api_reaction_args( $reaction, $args, $user_id ) { 71 | $tax_query = array(); 72 | if ( isset( $args['tax_query'] ) ) { 73 | $tax_query = $args['tax_query']; 74 | } 75 | 76 | if ( ! empty( $tax_query ) ) { 77 | $tax_query['relation'] = 'AND'; 78 | } 79 | Reactions::register_user_taxonomy( $user_id ); 80 | 81 | $reaction_query = array( 82 | 'taxonomy' => 'friend-reaction-' . $user_id, 83 | 'field' => 'slug', 84 | 'terms' => array( strval( $reaction ) ), 85 | ); 86 | 87 | if ( ! empty( $tax_query ) ) { 88 | $tax_query[] = $reaction_query; 89 | } else { 90 | $tax_query = array( $reaction_query ); 91 | } 92 | 93 | $args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query 94 | 95 | return $args; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "blocks/block-visibility", 4 | "blocks/follow-me", 5 | "blocks/friend-posts", 6 | "blocks/friends-list", 7 | "blocks/message" 8 | ], 9 | "version": "independent" 10 | } 11 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/blocks-everywhere.php: -------------------------------------------------------------------------------- 1 | handlers[] = new Handler\Friends_Message(); 71 | $this->handlers[] = new Handler\Friends_Status_Post(); 72 | } 73 | 74 | /** 75 | * Get the instantiated handler class for the specified type, or null if it isn't configured or known. 76 | * 77 | * @param 'Comments'|'bbPress'|'BuddyPress' $which The handler type. 78 | * @return Handler\Handler|null object or null it not configured. 79 | */ 80 | public function get_handler( $which ) { 81 | if ( isset( $this->handlers[ $which ] ) ) { 82 | return $this->handlers[ $which ]; 83 | } 84 | 85 | return null; 86 | } 87 | 88 | /** 89 | * Perform additional admin tasks when on the comment page 90 | * 91 | * @param String $hook Page hook. 92 | * @return void 93 | */ 94 | public function admin_enqueue_scripts( $hook ) { 95 | foreach ( $this->handlers as $handler ) { 96 | if ( $handler->can_show_admin_editor( $hook ) ) { 97 | add_action( 98 | 'admin_head', 99 | function() use ( $handler ) { 100 | add_filter( 'the_editor', [ $handler, 'the_editor' ] ); 101 | add_filter( 'wp_editor_settings', [ $handler, 'wp_editor_settings' ], 10, 2 ); 102 | } 103 | ); 104 | 105 | // Stops a problem with the Gutenberg plugin accessing widgets that don't exist 106 | remove_action( 'admin_footer', 'gutenberg_block_editor_admin_footer' ); 107 | 108 | // Load Gutenberg in in_admin_header so WP admin doesn't set the 'block-editor-page' body class 109 | add_action( 110 | 'in_admin_header', 111 | function() use ( $handler ) { 112 | $handler->load_editor( '.wp-editor-area' ); 113 | } 114 | ); 115 | 116 | break; 117 | } 118 | } 119 | } 120 | } 121 | 122 | Blocks_Everywhere::init(); 123 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/build/images/wordpress.e7ce7231.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akirk/friends/38d74cefb56fe8f0f490b90c8a908d3470f3e881/libs/blocks-everywhere/build/images/wordpress.e7ce7231.png -------------------------------------------------------------------------------- /libs/blocks-everywhere/build/index.min.asset.php: -------------------------------------------------------------------------------- 1 | array('lodash', 'react', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-dom-ready', 'wp-editor', 'wp-element', 'wp-format-library', 'wp-hooks', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-plugins', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-viewport'), 'version' => '7e116ecf70f375d6dba8'); 4 | 5 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/build/support-content-editor.min.asset.php: -------------------------------------------------------------------------------- 1 | array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '3cbe38af286559c26c5f'); 4 | 5 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/build/support-content-editor.min.css: -------------------------------------------------------------------------------- 1 | .be-support-content-placeholder .components-placeholder__input[type=url]{margin:0 8px 0 0!important}.be-support-content-placeholder .components-notice-list .components-notice__content{margin:4px 25px 4px 0}.be-support-content-placeholder__search-slot{flex-basis:100%;position:relative}.be-support-content-confirm-anchor{position:relative}.be-support-content-confirm-content{background:#fff;padding:12px}.be-support-content-confirm-content button.is-tertiary{padding:6px 12px}.be-support-content-confirm-content__item{color:#50575e!important;font-family:SF Pro Text,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif!important;font-size:.875rem!important;font-weight:400}.be-support-content-confirm-content__item:hover{box-shadow:inset 0 0 0 1px #50575e!important}.be-support-content-confirm-content__item.is-destructive{color:#d63638!important}.be-support-content-confirm-content__item.is-destructive:hover{box-shadow:inset 0 0 0 1px #d63638!important}.be-support-content-search-results{background-color:#fff;border:1px solid #d8dbdd;border-radius:2px;box-shadow:0 2px 6px rgba(0,0,0,.08);left:0;padding:10px;position:absolute;top:12px;width:100%;z-index:10000}.be-support-content-search-results__loading{display:flex}.be-support-content-search-results__item{cursor:pointer;padding:10px 20px}.be-support-content-search-results__item:hover{background-color:#f6f7f7}.be-support-content-search-results__title{font-size:1rem;font-weight:500;line-height:24px}.be-support-content-search-results__link,.be-support-content-search-results__title{display:block;font-family:SF Pro Text,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-style:normal;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.be-support-content-search-results__link{font-size:.875rem;font-weight:400;line-height:20px} 2 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/build/support-content-view.min.asset.php: -------------------------------------------------------------------------------- 1 | array(), 'version' => '8c1222f1c56fa9b57470'); 4 | 5 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/build/support-content-view.min.css: -------------------------------------------------------------------------------- 1 | .wp-block-blocks-everywhere-support-content:not(:first-child){margin-top:28px}.wp-block-blocks-everywhere-support-content:not(:last-child){margin-bottom:28px}.wp-block-blocks-everywhere-support-content .components-notice.is-error.is-dismissible{padding-right:0}.be-support-content{--line-height-content:20px;--line-height-title:24px;--color-light-gray:#eee;background:#fff;border:1px solid var(--color-light-gray);border-radius:4px;cursor:pointer;display:flex;flex-direction:column;font-family:SF Pro Text,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:.875rem;font-style:normal;font-weight:400;gap:16px;line-height:var(--line-height-content);padding:29px 30px;position:relative}.be-support-content__created{display:none}.be-support-content__opener{bottom:0;left:0;position:absolute;right:0;top:0}.be-support-content__link{color:#50575e!important;text-decoration:none!important;z-index:1}.be-support-content__link:hover{color:#50575e!important;text-decoration:underline!important}.be-support-content__header{align-items:center;display:flex;gap:24px}.be-support-content__title{align-items:center;color:#101517;display:flex;font-size:1rem;font-weight:500;gap:8px;line-height:var(--line-height-title)}.be-support-content__badge{background:#bbe0fa;border-radius:4px;color:#02395c;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:.75rem;font-weight:500;line-height:var(--line-height-content);padding:0 10px}.be-support-content__source{color:#50575e;display:flex;gap:4px}.be-support-content__details{color:#50575e;font-size:.75rem;font-weight:400;line-height:var(--line-height-content)}.be-support-content__content{-webkit-line-clamp:3;-webkit-box-orient:vertical;color:#2c3338;display:-webkit-box;max-height:calc(var(--line-height-content)*3);overflow:hidden}.be-support-content__reactions{color:#50575e;font-size:.75rem;font-weight:400;line-height:var(--line-height-content)}.bbp-reply-content .be-support-content a.be-support-content__link{text-decoration:none!important}.bbp-reply-content .be-support-content a.be-support-content__link:hover{text-decoration:underline!important}.be-support-content-wordpress-icon{align-items:center;background-color:#0675c4;border-radius:2px;display:flex;height:60px;justify-content:center;width:60px}.be-support-content-block-icon.is-margin-right{margin-right:10px}.be-support-content-block-icon svg{fill:#fff!important}@keyframes be-support-content_skeleton__animation{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.be-support-content-inline-skeleton{animation:be-support-content_skeleton__animation 1.6s ease-in-out infinite;background-color:var(--color-light-gray);color:var(--color-light-gray);display:inline-block;width:20em}.be-support-content-inline-skeleton:after{content:"X"}.be-support-content-inline-skeleton.is-hidden{visibility:hidden}.be-support-content-inline-skeleton.is-large{height:calc(var(--line-height-content)*3);width:34em} 2 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/build/support-content-view.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";function e(e){const t=e.querySelector(".be-support-content__created"),o=e.querySelector(".be-support-content__relative-created");var n;t?.textContent&&o&&(o.textContent=(n=t.textContent,(0,window.moment)(n).fromNow()))}document.addEventListener("DOMContentLoaded",(()=>{document.querySelectorAll(".wp-block-blocks-everywhere-support-content").forEach(e)}))}(); -------------------------------------------------------------------------------- /libs/blocks-everywhere/classes/handlers/class-friends-message.php: -------------------------------------------------------------------------------- 1 | load_editor( '.friends-message-message.blocks-everywhere-enabled', '.blocks-everywhere' ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/classes/handlers/class-friends-status-post.php: -------------------------------------------------------------------------------- 1 | current_user_can( 'edit_private_posts' ), 17 | 'allowedMimeTypes' => get_allowed_mime_types(), 18 | ) 19 | ); 20 | $settings['iso']['blocks']['allowBlocks'][] = 'core/image'; 21 | $settings['iso']['blocks']['allowBlocks'][] = 'core/embed'; 22 | $settings['iso']['toolbar']['inspector'] = true; 23 | return $settings; 24 | } ); 25 | 26 | } 27 | 28 | /** 29 | * Gets the editor type. 30 | * 31 | * @return string The editor type. 32 | */ 33 | public function get_editor_type() { 34 | return 'friends-status'; 35 | } 36 | 37 | /** 38 | * Modifies the allowed blocks. 39 | * 40 | * @param array $allowed The allowed blocks. 41 | * @param string $type The editor type. 42 | * 43 | * @return array The allowed blocks. 44 | */ 45 | public function allowed_blocks( $allowed, $type ) { 46 | if ( 'friends-status' === $type ) { 47 | $allowed[] = 'core/embed'; 48 | $allowed[] = 'core/image'; 49 | } 50 | return $allowed; 51 | } 52 | 53 | /** 54 | * Get the HTML that the editor uses on the page 55 | */ 56 | public function add_to_form() { 57 | $this->load_editor( '.friends-status-content.blocks-everywhere-enabled', '.blocks-everywhere' ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /libs/blocks-everywhere/readme.txt: -------------------------------------------------------------------------------- 1 | Based on Gutenberg Everywhere 1.14.1 2 | https://github.com/Automattic/gutenberg-everywhere/ 3 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Generally-applicable sniffs for WordPress plugins 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | tests/* 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | warning 49 | tests/bootstrap.php 50 | */widgets/* 51 | */templates/email/*.text.php 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | warning 66 | 67 | 68 | 69 | 70 | 71 | 72 | . 73 | 74 | 75 | 76 | 77 | */node_modules/* 78 | */bin/* 79 | */tests/* 80 | */vendor/* 81 | */libs/* 82 | blocks/*/build/index.asset.php 83 | 84 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /plugin-installer.js: -------------------------------------------------------------------------------- 1 | var friends_plugin_installer = friends_plugin_installer || {}; 2 | 3 | jQuery( document ).ready( function ( $ ) { 4 | 'use strict'; 5 | 6 | let is_loading = false; 7 | 8 | /** 9 | * Install the plugin 10 | * 11 | * @since 1.0 12 | * @param el object Button element 13 | * @param plugin string Plugin slug 14 | */ 15 | friends_plugin_installer.install_plugin = function ( el, plugin ) { 16 | is_loading = true; 17 | el.addClass( 'installing' ); 18 | el.text( friends_plugin_installer_localize.installing ); 19 | 20 | $.ajax( { 21 | type: 'POST', 22 | url: friends_plugin_installer_localize.ajax_url, 23 | data: { 24 | action: 'friends_plugin_installer', 25 | plugin, 26 | nonce: friends_plugin_installer_localize.admin_nonce, 27 | dataType: 'json', 28 | }, 29 | success( data ) { 30 | if ( data ) { 31 | if ( data.status === 'success' ) { 32 | el.attr( 'class', 'activate button button-primary' ); 33 | el.text( 34 | friends_plugin_installer_localize.activate_btn 35 | ); 36 | } else { 37 | el.removeClass( 'installing' ); 38 | } 39 | } else { 40 | el.removeClass( 'installing' ); 41 | } 42 | is_loading = false; 43 | }, 44 | error( xhr, status, error ) { 45 | el.removeClass( 'installing' ); 46 | is_loading = false; 47 | }, 48 | } ); 49 | }; 50 | 51 | /** 52 | * Activate the plugin 53 | * 54 | * @since 1.0 55 | * @param el object Button element 56 | * @param plugin string Plugin slug 57 | */ 58 | friends_plugin_installer.activate_plugin = function ( el, plugin ) { 59 | $.ajax( { 60 | type: 'POST', 61 | url: friends_plugin_installer_localize.ajax_url, 62 | data: { 63 | action: 'friends_plugin_activation', 64 | plugin, 65 | nonce: friends_plugin_installer_localize.admin_nonce, 66 | dataType: 'json', 67 | }, 68 | success( data ) { 69 | if ( data ) { 70 | if ( data.status === 'success' ) { 71 | el.attr( 'class', 'installed button disabled' ); 72 | el.text( 73 | friends_plugin_installer_localize.installed_btn 74 | ); 75 | el.closest( 'div' ) 76 | .find( '.deactivate' ) 77 | .toggleClass( 'hidden' ); 78 | } 79 | } 80 | is_loading = false; 81 | }, 82 | error( xhr, status, error ) { 83 | is_loading = false; 84 | }, 85 | } ); 86 | }; 87 | 88 | /** 89 | * Deactivate the plugin 90 | * 91 | * @since 1.0 92 | * @param el object Button element 93 | * @param plugin string Plugin slug 94 | */ 95 | friends_plugin_installer.deactivate_plugin = function ( el, plugin ) { 96 | $.ajax( { 97 | type: 'POST', 98 | url: friends_plugin_installer_localize.ajax_url, 99 | data: { 100 | action: 'friends_plugin_deactivation', 101 | plugin, 102 | nonce: friends_plugin_installer_localize.admin_nonce, 103 | dataType: 'json', 104 | }, 105 | success( data ) { 106 | if ( data ) { 107 | if ( data.status === 'success' ) { 108 | el.toggleClass( 'hidden' ); 109 | el.closest( 'div' ) 110 | .find( '.installed' ) 111 | .attr( 'class', 'activate button button-primary' ) 112 | .text( 113 | friends_plugin_installer_localize.activate_btn 114 | ); 115 | } 116 | } 117 | is_loading = false; 118 | }, 119 | error( xhr, status, error ) { 120 | is_loading = false; 121 | }, 122 | } ); 123 | }; 124 | 125 | /** 126 | * Install/Activate Button Click 127 | * 128 | * @since 1.0 129 | */ 130 | $( document ).on( 131 | 'click', 132 | '.friends-plugin-installer a.button:not(.details)', 133 | function ( e ) { 134 | const el = $( this ), 135 | plugin = el.data( 'slug' ); 136 | 137 | e.preventDefault(); 138 | 139 | if ( ! el.hasClass( 'disabled' ) ) { 140 | if ( is_loading ) return false; 141 | 142 | // Installation 143 | if ( el.hasClass( 'install' ) ) { 144 | friends_plugin_installer.install_plugin( el, plugin ); 145 | } 146 | 147 | // Activation 148 | if ( el.hasClass( 'activate' ) ) { 149 | friends_plugin_installer.activate_plugin( el, plugin ); 150 | } 151 | 152 | // Activation 153 | if ( el.hasClass( 'deactivate' ) ) { 154 | friends_plugin_installer.deactivate_plugin( el, plugin ); 155 | } 156 | } 157 | } 158 | ); 159 | } ); 160 | -------------------------------------------------------------------------------- /plugin-strings/friends-autoresolve-links.php: -------------------------------------------------------------------------------- 1 | plugin page on WordPress.org.', 'friends' ); 23 | // translators: %s: URL to the Embed library. 24 | __( 'This plugin is largely powered by the open source project Embed and provides support to resolve links to the following domains:', 'friends' ); 25 | __( 'Re-resolve', 'friends' ); 26 | __( 'Autoresolve Links', 'friends' ); 27 | __( 'Friends', 'friends' ); 28 | __( 'About', 'friends' ); 29 | -------------------------------------------------------------------------------- /plugin-strings/friends-debugger.php: -------------------------------------------------------------------------------- 1 | plugin page on WordPress.org.', 'friends' ); 27 | // translators: %s: URL to the Fraidyscrape. 28 | __( 'This parser is powered by a PHP port of the open source project Fraidyscrape and provides support to parse the following properties:', 'friends' ); 29 | __( 'Fraidyscrape Tester', 'friends' ); 30 | __( 'Here you can test what the parser makes of the URL you give it. ', 'friends' ); 31 | __( 'Enter a URL:', 'friends' ); 32 | _x( 'Parse Now', 'button', 'friends' ); 33 | // translators: %s is a URL to be displayed verbatim. 34 | __( 'Parsing Result for %s', 'friends' ); 35 | __( 'This feed doesn\'t contain any entries. There might be a problem parsing the feed.', 'friends' ); 36 | __( 'Items in the Feed', 'friends' ); 37 | __( 'Fraidyscrape', 'friends' ); 38 | __( 'Friends', 'friends' ); 39 | __( 'About', 'friends' ); 40 | -------------------------------------------------------------------------------- /plugin-strings/friends-parser-rss-bridge.php: -------------------------------------------------------------------------------- 1 | plugin page on WordPress.org.', 'friends' ); 26 | // translators: %s: URL to the RSS Bridge. 27 | __( 'This parser is powered by the open source project RSS Bridge and provides support to parse the following properties:', 'friends' ); 28 | __( 'RSS Bridge Tester', 'friends' ); 29 | __( 'Here you can test what the parser makes of the URL you give it. ', 'friends' ); 30 | __( 'Enter a URL:', 'friends' ); 31 | _x( 'Parse Now', 'button', 'friends' ); 32 | // translators: %s is a URL to be displayed verbatim. 33 | __( 'Parsing Result for %s', 'friends' ); 34 | __( 'This feed doesn\'t contain any entries. There might be a problem parsing the feed.', 'friends' ); 35 | __( 'Parser Details', 'friends' ); 36 | // translators: %s is the name of a Bridge = specific parser. 37 | __( 'Using Bridge: %s', 'friends' ); 38 | // translators: %s is an explanation for the Bridge = specific parser. 39 | __( 'Bridge Description: %s', 'friends' ); 40 | __( 'Items in the Feed', 'friends' ); 41 | __( 'RSS Bridge', 'friends' ); 42 | __( 'Friends', 'friends' ); 43 | __( 'About', 'friends' ); 44 | -------------------------------------------------------------------------------- /templates/admin/add-friend.php: -------------------------------------------------------------------------------- 1 |
12 | 13 |

14 | 15 | 16 | use a bookmarklet.', 'friends' ), esc_url( self_admin_url( 'tools.php' ) ) ), array( 'a' => array( 'href' => array() ) ) ); 19 | ?> 20 |

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 50 | 51 | 52 |
29 | 30 |

31 | 32 |

33 |
38 | 39 | 40 | 41 | 42 |

43 | %s will skip the next step and just subscribe you.', 'friends' ), $quick_subscribe ), array( 'em' => array() ) ); 46 | ?> 47 |

48 | 49 |
53 | 54 |
55 | -------------------------------------------------------------------------------- /templates/admin/add-reaction-li.php: -------------------------------------------------------------------------------- 1 | '; 13 | } else { 14 | $_id = $args['id']; 15 | $emoji = $args['emoji']; 16 | } 17 | ?> 18 |
  • 19 | 20 | 21 | 22 |
  • 23 | '; 27 | } 28 | -------------------------------------------------------------------------------- /templates/admin/automatic-status-list-table.php: -------------------------------------------------------------------------------- 1 |
    12 |

    13 | 16 |

    17 | 18 |
    19 | 20 |

    21 |
    22 | 23 |
    24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 |
    id="automatic-status-enabled" /> 29 | 30 |

    31 |
    35 | 36 |

    37 | 38 |

    39 |
    40 |
    41 | 42 | views(); ?> 43 | 44 |
    45 | 46 | 47 | 48 | 49 | 50 | 51 | display(); ?> 52 | 53 |
    54 | 55 | has_items() ) { 57 | $args['wp_list_table']->inline_edit(); 58 | } 59 | ?> 60 | 61 |
    62 | -------------------------------------------------------------------------------- /templates/admin/browser-extension.php: -------------------------------------------------------------------------------- 1 |
    10 | 11 | 12 | 13 | 14 | 15 | 24 | 25 | 26 |
    16 | 17 | 18 | 19 | 20 | 21 | 22 |

    23 |
    27 |
    28 | -------------------------------------------------------------------------------- /templates/admin/dashboard-widget-welcome.php: -------------------------------------------------------------------------------- 1 | 9 |

    10 |
      11 |
    • 12 |
    • 13 |
    14 | -------------------------------------------------------------------------------- /templates/admin/dashboard-widget.php: -------------------------------------------------------------------------------- 1 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /templates/admin/duplicates.php: -------------------------------------------------------------------------------- 1 | 11 |

    12 |
    13 |

    14 | get_posts() as $_post ) { 18 | if ( ! isset( $args['uniques'][ $_post->ID ] ) ) { 19 | ++$duplicate_count; 20 | } 21 | } 22 | 23 | echo esc_html( 24 | sprintf( 25 | // translators: %d is the number of duplicates. 26 | _n( '%d post was identified as aduplicate.', '%d posts were identified as duplicate.', $duplicate_count, 'friends' ), 27 | $duplicate_count 28 | ) 29 | ); 30 | echo ' '; 31 | esc_html_e( 'You can check or uncheck the posts before you click the button to delete them.', 'friends' ); 32 | ?> 33 | 34 |

    35 |

    36 | 37 |

    38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | get_posts() as $_post ) { 47 | $_title = get_the_title( $_post ); 48 | if ( empty( $_title ) ) { 49 | $_title = wp_trim_words( get_the_excerpt( $_post ), 10 ); 50 | } 51 | 52 | ?> 53 | 54 | 55 | 67 | 68 | 69 | 72 | 73 |
    ID ] ) ); ?>> 56 | 61 | 62 | 65 | 66 | post_date ) ) ); ?>
    74 | 75 | 76 |
    77 | -------------------------------------------------------------------------------- /templates/admin/edit-notifications.php: -------------------------------------------------------------------------------- 1 |
    10 | user_login ); ?> 11 | 12 | 13 | can_refresh_feeds() ) : ?> 14 | 15 | 16 | 28 | 29 | 30 | 31 | 47 | 48 | 49 | 50 | 51 |
    17 | 18 | 19 | 20 |
    21 | 25 |
    26 | 27 |
    32 |
    33 | 45 |
    46 |
    52 | 53 |

    54 | 55 |

    56 |
    57 | -------------------------------------------------------------------------------- /templates/admin/edit-raw-rules.php: -------------------------------------------------------------------------------- 1 | 10 |

    11 | view the raw rules data.', 'friends' ), '"#" id="toggle-raw-rules-data"' ), 15 | array( 16 | 'a' => array( 17 | 'href' => array(), 18 | 'id' => array(), 19 | ), 20 | ) 21 | ); 22 | ?> 23 |

    24 | 43 | -------------------------------------------------------------------------------- /templates/admin/edit-rules.php: -------------------------------------------------------------------------------- 1 |
    10 | user_login ) ); ?> 11 | 12 |

    13 |

    14 | 15 | 16 | 17 | 18 | 26 | 27 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 50 | 51 | 52 |
    19 | 25 | 28 | 34 | ()
    44 | 49 |
    53 |

    54 | 55 |

    56 |
    57 | 58 |

    59 | -------------------------------------------------------------------------------- /templates/admin/import-export.php: -------------------------------------------------------------------------------- 1 | 11 |
    12 | 13 | 14 | 15 | 16 | 17 | 36 | 37 | 38 | 52 | 53 | 54 | 55 | 56 | 64 | 65 | 66 |
    18 | 19 | Private OPML file (contains private urls!) and import it to your feed reader.', 'friends' ), esc_url( home_url( '/friends/opml/?auth=' . $args['private_rss_key'] ) ) ), array( 'a' => array( 'href' => array() ) ) ); 22 | ?> 23 | 24 | 25 | Public OPML file (only public urls).', 'friends' ), esc_url( home_url( '/friends/opml/?public' ) ) ), array( 'a' => array( 'href' => array() ) ) ); 28 | ?> 29 | 30 |

    31 | 34 |

    35 |
    39 | 40 | compiled RSS feed of friend posts.', 'friends' ), esc_url( home_url( '/friends/feed/?auth=' . $args['private_rss_key'] ) ) ), array( 'a' => array( 'href' => array() ) ) ); 43 | ?> 44 | 45 |

    46 | 49 |

    50 | 51 |
    Import OPML 57 | 58 |

    59 | 62 |

    63 |
    67 | 68 |

    69 | 70 |

    71 |
    72 | 14 |

    15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | 35 |
    27 | display_name ); ?> 28 | 29 | user_registered ) ) ); ?>get_role_name() ); ?>
    36 |
    37 | -------------------------------------------------------------------------------- /templates/admin/logs.php: -------------------------------------------------------------------------------- 1 | 9 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 50 | 51 | 52 | 53 | 54 |
    post_date ); ?> 35 |
    36 | post_title ); ?> 37 |
    38 | 						', '', '', '' ), esc_html( $log->post_content ) ),
    41 | 							array(
    42 | 								'ins' => array(),
    43 | 								'del' => array(),
    44 | 							)
    45 | 						);
    46 | 						?>
    47 | 								
    48 |
    49 |
    post_author ) ); ?>
    55 | -------------------------------------------------------------------------------- /templates/admin/opml.php: -------------------------------------------------------------------------------- 1 | '; 13 | 14 | ?> 15 | 16 | 17 | <?php echo esc_html( $args['title'] ); ?> 18 | 19 | display_name ); ?> 20 | 21 | 22 | $users ) { 24 | ?> 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /templates/admin/plugin-details.php: -------------------------------------------------------------------------------- 1 |

    2 |

    3 |

    Author: array( 'href' => true ) ) ); ?> Website:

    4 | $section ) : ?> 5 |

    6 | 7 | 8 |




    9 | -------------------------------------------------------------------------------- /templates/admin/plugin-info.php: -------------------------------------------------------------------------------- 1 | details; 11 | 12 | ?>
    13 |
    14 |
    15 |

    16 | name ); ?> version ); ?> 17 |

    18 |
    19 | 20 |
    21 |

    short_description ); ?>

    22 | comment ) ) : ?> 23 |

    24 |
    25 | comment ); ?> 26 |

    27 | 28 |

    29 | 30 | author 36 | ), 37 | array( 'a' => array( 'href' => array() ) ) 38 | ); 39 | ?> 40 | 41 |

    42 |
    43 |
    44 | 45 |
    46 | 47 | 48 | 52 | name 58 | ) 59 | ); 60 | ?> 61 | 62 | 63 | 64 | 65 |
    66 |
    67 | -------------------------------------------------------------------------------- /templates/admin/plugin-installer-footer.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/admin/plugin-installer-header.php: -------------------------------------------------------------------------------- 1 | 10 |
    11 |

    12 |

    13 |
    14 |
    15 | -------------------------------------------------------------------------------- /templates/admin/preview-rules.php: -------------------------------------------------------------------------------- 1 | apply_feed_rules( $_post, null, $args['friend'] ); 18 | ?> 19 | 20 | 21 | post_title : $_post->post_title ); ?> 22 | ID, 'author', true ) ); ?> 23 | post_date ) ) ); ?> 24 | 25 | _feed_rule_delete ) { 27 | echo esc_html( _x( 'Delete', 'verb', 'friends' ) ); 28 | ?> 29 | 30 | _feed_rule_transform['post_status'] ) && 'trash' === $modified_post->_feed_rule_transform['post_status'] ) { 33 | echo esc_html( _x( 'Trash', 'verb' ) ); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain 34 | } else { 35 | echo esc_html( _x( 'Accept', 'verb', 'friends' ) ); 36 | } 37 | ?> 38 | 39 | 40 | 41 | 44 | 45 | 46 | 51 |

    52 | 53 |

    54 | 57 |

    58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
    75 | 76 | 77 |

    78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | get_posts() as $_post ) { 90 | preview_row( $_post, $args ); 91 | } 92 | ?> 93 | 94 |
    95 | -------------------------------------------------------------------------------- /templates/admin/reactions-picker.php: -------------------------------------------------------------------------------- 1 | get_template_part( 9 | 'admin/add-reaction-li', 10 | null, 11 | array( 12 | 'template' => true, 13 | ) 14 | ); 15 | 16 | ?> 17 | 22 | -------------------------------------------------------------------------------- /templates/admin/settings-footer.php: -------------------------------------------------------------------------------- 1 | 9 |
    10 |
    11 | -------------------------------------------------------------------------------- /templates/admin/settings-header.php: -------------------------------------------------------------------------------- 1 | 'friends', 13 | __( 'Settings' ) => 'friends-settings', // phpcs:ignore WordPress.WP.I18n.MissingArgDomain 14 | __( 'Friendships', 'friends' ) => 'friends-wp-friendships', 15 | __( 'Notifications', 'friends' ) => 'friends-notification-manager', 16 | __( 'Import/Export', 'friends' ) => 'friends-import-export', 17 | ) 18 | ); 19 | } 20 | 21 | if ( empty( $args['active'] ) ) { 22 | $args['active'] = false; 23 | } 24 | 25 | if ( empty( $args['title'] ) ) { 26 | $args['title'] = __( 'Friends', 'friends' ); 27 | } 28 | 29 | ?> 30 |
    31 |
    32 |
    33 |

    34 | 35 |

    36 |
    37 | 40 | 81 | 84 |
    85 |
    86 |
    87 | -------------------------------------------------------------------------------- /templates/admin/unfriend.php: -------------------------------------------------------------------------------- 1 | display_name . ' (' . $args['friend']->user_login . ')'; 10 | $heading = sprintf( 11 | // translators: %s is a username. 12 | _x( 'Unfriend %s', 'heading', 'friends' ), 13 | $friend_name 14 | ); 15 | 16 | $button_text = sprintf( 17 | // translators: %s is a username. 18 | _x( 'Delete %s', 'action', 'friends' ), 19 | $friend_name 20 | ); 21 | if ( is_multisite() ) { 22 | $button_text = sprintf( 23 | // translators: %s is a username. 24 | _x( 'Remove %s', 'action', 'friends' ), 25 | $friend_name 26 | ); 27 | } 28 | $numfeeds = count( $args['friend']->get_active_feeds() ); 29 | 30 | ?> 31 |
    32 |

    33 |
    34 | user_login ); ?> 35 |

    36 | user_login, 24 ); 38 | echo ' '; 39 | echo esc_html( $friend_name ); 40 | ?> 41 |

    42 | 69 |

    70 | 81 |

    82 | 83 |

    84 | 85 | 86 |

    87 | 88 |
    89 |
    90 | -------------------------------------------------------------------------------- /templates/email/accepted-friend-request-text.php: -------------------------------------------------------------------------------- 1 | display_name ); 14 | echo PHP_EOL; 15 | 16 | // translators: %s is a username. 17 | printf( __( 'Good news, %s has accepted your friend request.', 'friends' ), $args['friend_user']->display_name ); 18 | echo PHP_EOL . PHP_EOL; 19 | 20 | // translators: %s is a URL. 21 | printf( wp_strip_all_tags( __( 'Go to your friends page and look at their posts.', 'friends' ) ) ); 22 | echo PHP_EOL . PHP_EOL; 23 | 24 | echo $args['friend_user']->get_local_friends_page_url(); 25 | -------------------------------------------------------------------------------- /templates/email/accepted-friend-request.php: -------------------------------------------------------------------------------- 1 | 10 |

    11 | display_name ) ); 14 | ?> 15 |

    16 | 17 |

    18 | display_name ) ); 21 | ?> 22 |

    23 | 24 |

    25 | friends page and look at their posts.', 'friends' ), esc_url( $args['friend_user']->get_local_friends_page_url() ) ), array( 'a' => array( 'href' => true ) ) ); 28 | ?> 29 |

    30 | -------------------------------------------------------------------------------- /templates/email/footer-text.php: -------------------------------------------------------------------------------- 1 | 10 |
    11 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /templates/email/friend-message-received-text.php: -------------------------------------------------------------------------------- 1 | /i', PHP_EOL, $args['message'] ); 10 | $plain_text = wp_strip_all_tags( $ensure_linebreaks ); 11 | $normalized_whitespace = preg_replace( '/(' . PHP_EOL . '\s*' . PHP_EOL . ')+/m', PHP_EOL . PHP_EOL, $plain_text ); 12 | $quoted_text = '> ' . str_replace( PHP_EOL, PHP_EOL . '> ', trim( $normalized_whitespace ) ); 13 | 14 | // This is a text e-mail, not a place for HTML escaping. 15 | // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped 16 | 17 | // translators: %s is a user display name. 18 | printf( __( 'Hi %s!', 'friends' ), $args['user']->display_name ); 19 | echo PHP_EOL; 20 | 21 | // translators: %s is a username. 22 | printf( __( 'We just received a message from %s:', 'friends' ), $args['friend_user']->display_name ); 23 | echo PHP_EOL . PHP_EOL; 24 | 25 | echo $quoted_text; 26 | 27 | // translators: %s is a URL. 28 | printf( wp_strip_all_tags( __( 'Go to your friends page to respond.', 'friends' ) ) ); 29 | echo PHP_EOL . PHP_EOL; 30 | 31 | echo $args['friend_user']->get_local_friends_page_url(); 32 | -------------------------------------------------------------------------------- /templates/email/friend-message-received.php: -------------------------------------------------------------------------------- 1 | 10 |

    11 | display_name ) ); 14 | ?> 15 |

    16 | 17 |

    18 | display_name ) ); 21 | ?> 22 |

    23 | 24 |
    25 | 28 |
    29 | 30 | 31 |

    32 | friends page to respond.', 'friends' ), esc_url( $args['friend_user']->get_local_friends_page_url() ) ), array( 'a' => array( 'href' => true ) ) ); 35 | ?> 36 |

    37 | -------------------------------------------------------------------------------- /templates/email/header.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 142 | <?php echo esc_html( $args['email_title'] ); ?> 143 | 155 | 156 | 157 | 158 |
    159 | -------------------------------------------------------------------------------- /templates/email/keyword-match-post-text.php: -------------------------------------------------------------------------------- 1 | /i', PHP_EOL, $args['post']->post_content ); 10 | $plain_text = wp_strip_all_tags( $ensure_linebreaks ); 11 | $normalized_whitespace = preg_replace( '/(' . PHP_EOL . '\s*' . PHP_EOL . ')+/m', PHP_EOL . PHP_EOL, $plain_text ); 12 | $quoted_text = '> ' . str_replace( PHP_EOL, PHP_EOL . '> ', trim( $normalized_whitespace ) ); 13 | 14 | // This is a text e-mail, not a place for HTML escaping. 15 | // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped 16 | 17 | // translators: %s is a keyword string specified by the user. 18 | printf( __( 'Keyword matched: %s', 'friends' ), $args['keyword'] ); 19 | 20 | echo PHP_EOL, PHP_EOL; 21 | 22 | echo $quoted_text; 23 | 24 | echo PHP_EOL, PHP_EOL; 25 | 26 | printf( 27 | // translators: %1$s is a username, %2$s is a URL. 28 | __( 'This post was published by your friend %1$s at %2$s', 'friends' ), 29 | $args['author']->display_name, 30 | get_permalink( $args['post'] ) 31 | ); 32 | 33 | echo PHP_EOL; 34 | printf( 35 | // translators: %s is a URL. 36 | __( 'You can also view this post on your friends page: %s', 'friends' ), 37 | $args['author']->get_local_friends_page_url( $args['post']->ID ) 38 | ); 39 | echo PHP_EOL, PHP_EOL; 40 | 41 | printf( 42 | // translators: %s is a URL. 43 | __( 'Manage your subscription settings at %s', 'friends' ), 44 | $args['author']->display_name, 45 | self_admin_url( 'admin.php?page=friends-settings' ) 46 | ); 47 | echo PHP_EOL; 48 | 49 | printf( 50 | // translators: %1$s is a username, %2$s is a URL. 51 | __( 'Or just unsubscribe from %1$s\'s posts at %2$s', 'friends' ), 52 | $args['author']->display_name, 53 | self_admin_url( 'admin.php?page=edit-friend&user=' . $args['author']->user_login ) 54 | ); 55 | -------------------------------------------------------------------------------- /templates/email/keyword-match-post.php: -------------------------------------------------------------------------------- 1 | display_name, $args['post']->ID ); 11 | 12 | ?> 13 | ' . esc_html( $args['keyword'] ) . '' ), 17 | array( 'strong' => array() ) 18 | ); 19 | ?> 20 |

    21 | 32 | 33 |
    34 | post_content, $args ) ); 36 | ?> 37 |
    38 | 39 | 63 | 64 |
    65 |
    66 | global notification settings, change notifications for %3$s, or muffle posts like these.', 'friends' ), 71 | '"' . esc_url( self_admin_url( 'admin.php?page=friends-settings' ) ) . '"', 72 | '"' . esc_url( self_admin_url( 'admin.php?page=edit-friend&user=' . $args['author']->ID ) ) . '"', 73 | '' . esc_html( $args['author']->display_name ) . '', 74 | '"' . esc_url( self_admin_url( 'admin.php?page=edit-friend-rules&user=' . $args['author']->ID . '&post=' . $args['post']->ID ) ) . '"' 75 | ), 76 | array( 77 | 'em' => array(), 78 | 'a' => array( 'href' => true ), 79 | ) 80 | ); 81 | 82 | ?> 83 |
    84 | -------------------------------------------------------------------------------- /templates/email/lost-follower-text.php: -------------------------------------------------------------------------------- 1 | display_name ) ); 14 | echo PHP_EOL; 15 | echo PHP_EOL; 16 | // translators: %s is a username. 17 | printf( __( 'Sorry to inform you that you lost follower %s.', 'friends' ), $args['follower']->get_name() . ' (' . $args['follower']->get_preferred_username() . '@' . $args['server'] . ')' ); 18 | echo PHP_EOL; 19 | echo PHP_EOL; 20 | echo '> ' . wp_strip_all_tags( $args['follower']->get_summary() ); 21 | echo PHP_EOL; 22 | // translators: %s is a time duration. 23 | printf( __( 'They have been following you for: %s', 'friends' ), $args['duration'] ); 24 | -------------------------------------------------------------------------------- /templates/email/lost-follower.php: -------------------------------------------------------------------------------- 1 | 10 |

    11 | display_name ) ); 14 | ?> 15 |

    16 | 17 |

    18 | 21 |

    22 | 23 | 24 | 25 | 30 | 42 | 43 |
    26 | 27 | <?php echo esc_attr( $args['follower']->get_name() ); ?> 28 | 29 | 31 | 32 | 33 | get_name() ); ?> (get_preferred_username() . '@' . $args['server'] ); ?>) 34 | 35 |
    36 | get_summary() ) { 38 | echo wp_kses_post( nl2br( $args['follower']->get_summary() ) ); 39 | } 40 | ?> 41 |
    44 | 45 |

    46 | 50 |

    51 | 52 | 53 | -------------------------------------------------------------------------------- /templates/email/new-follower-text.php: -------------------------------------------------------------------------------- 1 | display_name ) ); 14 | echo PHP_EOL; 15 | echo PHP_EOL; 16 | // translators: %s is a username. 17 | printf( __( 'You have a new follower %s.', 'friends' ), $args['follower']->get_name() ); 18 | echo PHP_EOL; 19 | echo PHP_EOL; 20 | echo '> ' . wp_strip_all_tags( $args['follower']->get_summary() ); 21 | echo PHP_EOL; 22 | // translators: %s is a URL. 23 | printf( __( 'You can view their profile at %s', 'friends' ), esc_url( $args['url'] ) ); 24 | echo PHP_EOL; 25 | echo PHP_EOL; 26 | echo __( 'Maybe you want to follow them back?', 'friends' ), ' ', esc_url( add_query_arg( 'url', $args['url'], admin_url( 'admin.php?page=add-friend' ) ) ); 27 | echo PHP_EOL; 28 | -------------------------------------------------------------------------------- /templates/email/new-follower.php: -------------------------------------------------------------------------------- 1 | 10 |

    11 | display_name ) ); 14 | ?> 15 |

    16 | 17 |

    18 | 21 |

    22 | 23 | 24 | 25 | 30 | 42 | 43 |
    26 | 27 | <?php echo esc_attr( $args['follower']->get_name() ); ?> 28 | 29 | 31 | 32 | 33 | get_name() ); ?> (get_preferred_username() . '@' . $args['server'] ); ?>) 34 | 35 |
    36 | get_summary() ) { 38 | echo wp_kses_post( nl2br( $args['follower']->get_summary() ) ); 39 | } 40 | ?> 41 |
    44 | 45 |

    46 | friends page to see what they recently posted about.', 'friends' ), esc_url( $args['following']->get_local_friends_page_url() ) ), array( 'a' => array( 'href' => array() ) ) ); 52 | } else { 53 | // translators: %s is a URL. 54 | echo wp_kses( sprintf( __( 'You can view their profile at %s', 'friends' ), '' . esc_url( $args['follower']->get_url() ) . '' ), array( 'a' => array( 'href' => array() ) ) ); 55 | echo '

    '; 56 | echo '

    '; 57 | // translators: %s is a URL. 58 | echo wp_kses( sprintf( __( 'Maybe you want to follow them back?', 'friends' ), esc_url( add_query_arg( 'url', $args['url'], admin_url( 'admin.php?page=add-friend' ) ) ) ), array( 'a' => array( 'href' => array() ) ) ); 59 | } 60 | ?> 61 |

    62 | -------------------------------------------------------------------------------- /templates/email/new-friend-post-text.php: -------------------------------------------------------------------------------- 1 | /i', PHP_EOL, $args['post']->post_content ); 10 | $plain_text = wp_strip_all_tags( $ensure_linebreaks ); 11 | $normalized_whitespace = preg_replace( '/(' . PHP_EOL . '\s*' . PHP_EOL . ')+/m', PHP_EOL . PHP_EOL, $plain_text ); 12 | $quoted_text = '> ' . str_replace( PHP_EOL, PHP_EOL . '> ', trim( $normalized_whitespace ) ); 13 | 14 | // This is a text e-mail, not a place for HTML escaping. 15 | // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped 16 | echo $quoted_text; 17 | 18 | echo PHP_EOL, PHP_EOL; 19 | 20 | printf( 21 | // translators: %1$s is a username, %2$s is a URL. 22 | __( 'This post was published by your friend %1$s at %2$s', 'friends' ), 23 | $args['author']->display_name, 24 | get_permalink( $args['post'] ) 25 | ); 26 | 27 | echo PHP_EOL; 28 | printf( 29 | // translators: %s is a URL. 30 | __( 'You can also view this post on your friends page: %s', 'friends' ), 31 | $args['author']->get_local_friends_page_url( $args['post']->ID ) 32 | ); 33 | echo PHP_EOL, PHP_EOL; 34 | 35 | printf( 36 | // translators: %s is a URL. 37 | __( 'Manage your subscription settings at %s', 'friends' ), 38 | $args['author']->display_name, 39 | self_admin_url( 'admin.php?page=friends-settings' ) 40 | ); 41 | echo PHP_EOL; 42 | 43 | printf( 44 | // translators: %1$s is a username, %2$s is a URL. 45 | __( 'Or just unsubscribe from %1$s\'s posts at %2$s', 'friends' ), 46 | $args['author']->display_name, 47 | self_admin_url( 'admin.php?page=edit-friend&user=' . $args['author']->user_login ) 48 | ); 49 | -------------------------------------------------------------------------------- /templates/email/new-friend-post.php: -------------------------------------------------------------------------------- 1 | display_name, $args['post']->ID ); 11 | 12 | ?> 13 | 24 | 25 |
    26 | post_content, $args ) ); 28 | ?> 29 |
    30 | 31 | 55 | 56 |
    57 |
    58 | global notification settings, change notifications for %3$s, or muffle posts like these.', 'friends' ), 63 | '"' . esc_url( self_admin_url( 'admin.php?page=friends-settings' ) ) . '"', 64 | '"' . esc_url( self_admin_url( 'admin.php?page=edit-friend&user=' . $args['author']->user_login ) ) . '"', 65 | '' . esc_html( $args['author']->display_name ) . '', 66 | '"' . esc_url( self_admin_url( 'admin.php?page=edit-friend-rules&user=' . $args['author']->user_login . '&post=' . $args['post']->ID ) ) . '"' 67 | ), 68 | array( 69 | 'em' => array(), 70 | 'a' => array( 'href' => true ), 71 | ) 72 | ); 73 | ?> 74 |
    75 | -------------------------------------------------------------------------------- /templates/email/new-friend-request-text.php: -------------------------------------------------------------------------------- 1 | display_name ); 14 | echo PHP_EOL; 15 | 16 | // translators: %s is a username. 17 | printf( __( 'You have received a new friend request from %s.', 'friends' ), $args['friend_user']->display_name ); 18 | echo PHP_EOL . PHP_EOL; 19 | 20 | // translators: %s is a URL. 21 | printf( wp_strip_all_tags( __( 'Go to your admin page to review the request and approve or delete it.', 'friends' ) ) ); 22 | echo PHP_EOL . PHP_EOL; 23 | 24 | echo self_admin_url( 'users.php?role=friend_request' ); 25 | 26 | echo PHP_EOL . PHP_EOL; 27 | -------------------------------------------------------------------------------- /templates/email/new-friend-request.php: -------------------------------------------------------------------------------- 1 | 10 |

    11 | display_name ) ); 14 | ?> 15 |

    16 | 17 |

    18 | display_name ) ); 21 | ?> 22 |

    23 | 24 |

    25 | admin page to review the request and approve or delete it.', 'friends' ), esc_url( self_admin_url( 'users.php?role=friend_request' ) ) ), array( 'a' => array( 'href' => true ) ) ); 28 | ?> 29 |

    30 | -------------------------------------------------------------------------------- /templates/email/unknown-friend-message-received-text.php: -------------------------------------------------------------------------------- 1 | /i', PHP_EOL, $args['message'] ); 10 | $plain_text = wp_strip_all_tags( $ensure_linebreaks ); 11 | $normalized_whitespace = preg_replace( '/(' . PHP_EOL . '\s*' . PHP_EOL . ')+/m', PHP_EOL . PHP_EOL, $plain_text ); 12 | $quoted_text = '> ' . str_replace( PHP_EOL, PHP_EOL . '> ', trim( $normalized_whitespace ) ); 13 | 14 | // This is a text e-mail, not a place for HTML escaping. 15 | // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped 16 | 17 | // translators: %s is a user display name. 18 | printf( __( 'Hi %s!', 'friends' ), $args['user']->display_name ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 19 | echo PHP_EOL; 20 | 21 | // translators: %s is a username. 22 | printf( __( 'We just received a message from %s:', 'friends' ), $args['sender_name'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 23 | echo PHP_EOL . PHP_EOL; 24 | 25 | echo $quoted_text; 26 | 27 | // translators: %s is a URL. 28 | printf( wp_strip_all_tags( __( 'Maybe you want to follow them to respond?', 'friends' ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 29 | echo PHP_EOL . PHP_EOL; 30 | 31 | echo home_url( '?add-friend=' . esc_url( $args['feed_url'] ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 32 | -------------------------------------------------------------------------------- /templates/email/unknown-friend-message-received.php: -------------------------------------------------------------------------------- 1 | 10 |

    11 | display_name ) ); 14 | ?> 15 |

    16 | 17 |

    18 | 22 |

    23 | 24 |
    25 | 28 |
    29 | 30 | 31 |

    32 | follow them to respond?', 'friends' ), esc_attr( home_url( '?add-friend=' . esc_url( $args['feed_url'] ) ) ) ), array( 'a' => array( 'href' => true ) ) ); 35 | ?> 36 |

    37 | -------------------------------------------------------------------------------- /templates/embed/embed-content.php: -------------------------------------------------------------------------------- 1 | 12 |
    13 | 14 |

    15 | 16 | 17 | 18 |

    19 | 20 |
    21 | 22 | 30 | 31 | 50 |
    51 | 18 | 19 | class="no-js"> 20 | 21 | <?php echo esc_html( wp_get_document_title() ); ?> 22 | 23 | 31 | 32 | > 33 | -------------------------------------------------------------------------------- /templates/frontend/editor.php: -------------------------------------------------------------------------------- 1 | 9 |
    10 | 11 | 12 |
    13 |
    14 | 15 | Published Privately 16 |
    17 | -------------------------------------------------------------------------------- /templates/frontend/error-message.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | 5 | 6 |
    7 | 8 |
    9 |
    10 |
    11 | -------------------------------------------------------------------------------- /templates/frontend/footer.php: -------------------------------------------------------------------------------- 1 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /templates/frontend/header.php: -------------------------------------------------------------------------------- 1 | 25 | class="no-js no-svg"> 26 | 27 | 28 | 29 | 30 | 31 | 32 | > 33 |
    34 |
    35 | 36 | 37 | 38 |
    39 |
    40 | 41 |
    42 |
    43 | 44 | 45 | 46 |
    47 |
    48 | 83 | 84 | 85 | 86 | 87 | 88 | 101 |
    102 | get_template_part( 10 | 'frontend/header', 11 | $args['post_format'], 12 | $args 13 | ); 14 | 15 | $show_welcome = isset( $args['show_welcome'] ) && $args['show_welcome']; 16 | 17 | ?> 18 |
    19 | 22 |
    23 |
    24 | frontend->post_format ) { 26 | $post_formats = get_post_format_strings(); 27 | 28 | if ( $args['friend_user'] ) { 29 | echo esc_html( 30 | sprintf( 31 | // translators: %s is the name of an author. 32 | __( '%1$s hasn\'t posted anything with the post format %2$s yet!', 'friends' ), 33 | get_the_author(), 34 | $post_formats[ $args['friends']->frontend->post_format ] 35 | ) 36 | ); 37 | ?> 38 | 39 | frontend->post_format ] 46 | ) 47 | ); 48 | ?> 49 | 50 | get_total() > 0 ) { 55 | Friends\Friends::template_loader()->get_template_part( 'frontend/no-posts', $args['post_format'], $args ); 56 | } else { 57 | Friends\Friends::template_loader()->get_template_part( 'frontend/no-friends', $args['post_format'], $args ); 58 | } 59 | } 60 | ?> 61 |
    62 |
    63 | 69 |
    70 | get_template_part( 72 | 'frontend/footer', 73 | $args['post_format'], 74 | $args 75 | ); 76 | -------------------------------------------------------------------------------- /templates/frontend/messages/author-header.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /templates/frontend/messages/friend.php: -------------------------------------------------------------------------------- 1 | 15 |
    16 | 17 | get_posts() as $_post ) { 19 | $messages = get_posts( 20 | array( 21 | 'post_parent' => $_post->ID, 22 | 'post_type' => 'friend_message', 23 | 'post_status' => array( 'friends_read', 'friends_unread' ), 24 | 'order' => 'ASC', 25 | 'numberposts' => -1, 26 | ) 27 | ); 28 | array_unshift( $messages, $_post ); 29 | 30 | $classes = array( 'display-message' => true ); 31 | $subject = false; 32 | $last_message_time = false; 33 | foreach ( $messages as $message ) { 34 | if ( get_post_status( $message ) === 'friends_unread' ) { 35 | $classes['unread'] = true; 36 | } 37 | $post_time = get_post_modified_time( 'U', true, $message ); 38 | if ( ! $last_message_time || $post_time > $last_message_time ) { 39 | $last_message_time = $post_time; 40 | 41 | $subject = get_the_title( $message ); 42 | if ( ! $subject ) { 43 | $subject = get_the_excerpt( $message ); 44 | } 45 | } 46 | } 47 | ?> 48 |
    49 | 50 | 56 | 57 | 114 |
    115 | 118 |
    119 | -------------------------------------------------------------------------------- /templates/frontend/messages/message-form.php: -------------------------------------------------------------------------------- 1 | 10 | 86 | get_template_part( 10 | 'admin/welcome', 11 | $args['post_format'], 12 | array( 13 | 'plugin-list' => false, 14 | ) 15 | ); 16 | 17 | ?>

    18 | 19 | Note: This box will go away as soon as you have added your first friend or subscription.', 'friends' ), array( 'strong' => array() ) ); 21 | ?> 22 | 23 |
    24 | 25 | Friends admin menu for later reference.', 'friends' ), 30 | '"' . admin_url( 'admin.php?page=friends' ) . '"' 31 | ), 32 | array( 33 | 'a' => array( 'href' => array() ), 34 | 'br' => array(), 35 | 'strong' => array(), 36 | ) 37 | ); 38 | ?> 39 | 40 |

    41 | -------------------------------------------------------------------------------- /templates/frontend/no-posts.php: -------------------------------------------------------------------------------- 1 | 1 ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended 10 | esc_html_e( 'No further posts of your friends could were found.', 'friends' ); 11 | } else { 12 | esc_html_e( 'Unfortunately, we could not find a post.', 'friends' ); 13 | } 14 | -------------------------------------------------------------------------------- /templates/frontend/parts/activitypub/boost-button.php: -------------------------------------------------------------------------------- 1 | ID === get_current_user_id() ) { 10 | return; 11 | } 12 | ?> 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /templates/frontend/parts/activitypub/follow-link.php: -------------------------------------------------------------------------------- 1 | 10 | ' . wp_kses( /* translators: %s is a username. */ sprintf( __( 'Follow %s', 'friends' ), '' . esc_html( $args['name'] ) . '' ), array( 'span' => array( 'class' => true ) ) ) . '' . 16 | '' . esc_html( $args['name'] ) . '' 17 | ), 18 | array( 19 | 'a' => array( 20 | 'href' => true, 21 | 'class' => true, 22 | ), 23 | 'span' => array( 24 | 'class' => true, 25 | ), 26 | 27 | ) 28 | ); 29 | ?> 30 | 31 | -------------------------------------------------------------------------------- /templates/frontend/parts/activitypub/header-menu.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /templates/frontend/parts/comments-content.php: -------------------------------------------------------------------------------- 1 |
    10 | $_post_id, 18 | 'status' => 'approve', 19 | 'order' => 'ASC', 20 | 'orderby' => 'comment_date_gmt', 21 | ) 22 | ), 23 | $_post_id 24 | ); 25 | 26 | if ( ! empty( $_comments ) ) { 27 | $template_loader = Friends\Friends::template_loader(); 28 | ?> 29 |
    30 |
      31 | 'ol', 36 | 'short_ping' => true, 37 | 'avatar_size' => 24, 38 | ), 39 | $_comments 40 | ); 41 | ?> 42 |
    43 | 48 |
    49 | -------------------------------------------------------------------------------- /templates/frontend/parts/comments.php: -------------------------------------------------------------------------------- 1 | frontend->link( 10 | get_comments_link(), 11 | __( 'Comments' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain 12 | array( 13 | 'class' => 'comments btn btn-link ml-1 text', 14 | 'dashicon_front' => 'admin-comments', 15 | 'data-id' => get_the_ID(), 16 | 'data-cnonce' => wp_create_nonce( 'comments-' . get_the_ID() ), 17 | ) 18 | ); 19 | -------------------------------------------------------------------------------- /templates/frontend/parts/content-image.php: -------------------------------------------------------------------------------- 1 | 11 |
    > 12 |
    13 | get_template_part( 'frontend/parts/header', get_post_format(), $args ); 15 | $template_loader->get_template_part( 'frontend/parts/title', get_post_format(), $args ); 16 | $template_loader->get_template_part( 'frontend/parts/entry-content', get_post_format(), $args ); 17 | $template_loader->get_template_part( 'frontend/parts/footer', get_post_format(), $args ); 18 | ?> 19 |
    20 |
    21 | -------------------------------------------------------------------------------- /templates/frontend/parts/content-status.php: -------------------------------------------------------------------------------- 1 | 11 |
    > 12 | get_template_part( 'frontend/parts/header', get_post_format(), $args ); 14 | $template_loader->get_template_part( 'frontend/parts/entry-content', get_post_format(), $args ); 15 | $template_loader->get_template_part( 'frontend/parts/footer', get_post_format(), $args ); 16 | ?> 17 |
    18 | -------------------------------------------------------------------------------- /templates/frontend/parts/content.php: -------------------------------------------------------------------------------- 1 | 11 |
    > 12 | get_template_part( 'frontend/parts/header', get_post_format(), $args ); 14 | $template_loader->get_template_part( 'frontend/parts/title', get_post_format(), $args ); 15 | $template_loader->get_template_part( 'frontend/parts/entry-content', get_post_format(), $args ); 16 | $template_loader->get_template_part( 'frontend/parts/footer', get_post_format(), $args ); 17 | ?> 18 |
    19 | -------------------------------------------------------------------------------- /templates/frontend/parts/entry-content.php: -------------------------------------------------------------------------------- 1 | 11 |
    12 | 19 |
    20 | -------------------------------------------------------------------------------- /templates/frontend/parts/footer.php: -------------------------------------------------------------------------------- 1 |
    10 | 11 | get_template_part( 'frontend/parts/reactions', null, $args ); 14 | Friends\Friends::template_loader()->get_template_part( 'frontend/parts/comments', null, $args ); 15 | ?> 16 |
    17 | 18 | 19 | 20 | 21 | 30 |
    31 | 34 | 35 | 36 |
    37 | get_template_part( 'frontend/parts/comments-content', null, $args ); 40 | 41 | ?> 42 | -------------------------------------------------------------------------------- /templates/frontend/parts/header-menu.php: -------------------------------------------------------------------------------- 1 | 12 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 56 | 57 | $reaction ) { 11 | $classes = array(); 12 | if ( $reaction->user_reacted ) { 13 | $classes[] = 'pressed'; 14 | } 15 | echo '' . PHP_EOL; 19 | } 20 | 21 | if ( ( in_array( get_post_type(), apply_filters( 'friends_frontend_post_types', array() ), true ) || count( $reactions ) || get_the_author_meta( 'ID' ) !== get_current_user_id() ) && ( Friends\Friends::is_main_user() || current_user_can( 'friend' ) || current_user_can( 'acquaintance' ) ) ) : 22 | ?> 23 |
    24 | 25 | 26 | 27 | get_template_part( 'frontend/reactions-picker', null, $args ); ?> 28 |
    29 | ID === get_current_user_id() ) { 10 | return; 11 | } 12 | ?> 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /templates/frontend/parts/title.php: -------------------------------------------------------------------------------- 1 |

    10 | 11 | frontend->link( 13 | get_the_permalink(), 14 | get_the_title() 15 | ); 16 | ?> 17 | 18 | 19 | 20 |

    21 | -------------------------------------------------------------------------------- /templates/frontend/reactions-picker.php: -------------------------------------------------------------------------------- 1 | 9 | 14 | -------------------------------------------------------------------------------- /templates/frontend/single-header.php: -------------------------------------------------------------------------------- 1 | friends = Friends::get_instance(); 36 | } 37 | 38 | /** 39 | * Render a friend list. 40 | * 41 | * @param array $args The widget arguments. 42 | * @param string $title The list title. 43 | * @param \WP_User_Query $friends The friends to list. 44 | */ 45 | public function list_friends( $args, $title, \WP_User_Query $friends ) { 46 | $open = Frontend::get_widget_open_state( $args['widget_id'] ); 47 | ?> 48 |
    data-id="" data-nonce=""> 49 | 50 | array( 'class' => array() ), 56 | 'a' => array( 57 | 'class' => array(), 58 | 'href' => array(), 59 | ), 60 | ) 61 | ); 62 | echo $args['after_title']; 63 | ?> 64 | 65 | 70 |
    71 | friends->frontend->post_format ) { 83 | $url = $friend_user->get_local_friends_page_post_format_url( $this->friends->frontend->post_format ); 84 | } else { 85 | $url = $friend_user->get_local_friends_page_url(); 86 | } 87 | } else { 88 | $url = $friend_user->user_url; 89 | } 90 | ?> 91 | 92 | defaults; 105 | 106 | return $instance; 107 | } 108 | 109 | /** 110 | * Return an associative array of default values 111 | * 112 | * These values are used in new widgets. 113 | * 114 | * @return array Array of default values for the Widget's options 115 | */ 116 | public function defaults() { 117 | return array( 118 | 'title' => '', 119 | ); 120 | } 121 | 122 | /** 123 | * Register this widget. 124 | */ 125 | public static function register() { 126 | register_widget( get_called_class() ); 127 | } 128 | } 129 | 130 | -------------------------------------------------------------------------------- /widgets/class-widget-friend-request.php: -------------------------------------------------------------------------------- 1 | __( 'Send a friend request.', 'friends' ), 29 | ) 30 | ); 31 | } 32 | 33 | /** 34 | * Render the widget. 35 | * 36 | * @param array $args Sidebar arguments. 37 | * @param array $instance Widget instance settings. 38 | */ 39 | public function widget( $args, $instance ) { 40 | $instance = wp_parse_args( $instance, $this->defaults() ); 41 | 42 | $title = apply_filters( 'widget_title', $instance['title'] ); 43 | echo $args['before_widget']; 44 | if ( ! empty( $title ) ) { 45 | echo $args['before_title'] . $title . $args['after_title']; 46 | } 47 | 48 | ?> 49 |
    50 | 51 |
    52 | " placeholder="" class="form-input input-sm" /> 53 |
    54 |
    55 | 56 |
    57 |
    58 | defaults; 71 | 72 | return $instance; 73 | } 74 | 75 | /** 76 | * Return an associative array of default values 77 | * 78 | * These values are used in new widgets. 79 | * 80 | * @return array Array of default values for the Widget's options 81 | */ 82 | public function defaults() { 83 | return array( 84 | 'title' => '', 85 | ); 86 | } 87 | 88 | /** 89 | * Register this widget. 90 | */ 91 | public static function register() { 92 | register_widget( __CLASS__ ); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /widgets/class-widget-friends-list.php: -------------------------------------------------------------------------------- 1 | __( 'Shows a list of your friends.', 'friends' ), 29 | ) 30 | ); 31 | } 32 | 33 | /** 34 | * Render the widget. 35 | * 36 | * @param array $args Sidebar arguments. 37 | * @param array $instance Widget instance settings. 38 | */ 39 | public function widget( $args, $instance ) { 40 | $instance = wp_parse_args( $instance, $this->defaults() ); 41 | 42 | $all_friends = User_Query::all_friends(); 43 | $friend_requests = User_Query::all_friend_requests(); 44 | $subscriptions = User_Query::all_subscriptions(); 45 | 46 | // translators: %s is the number of your friends. 47 | $friends_title = ' ' . sprintf( _n( 'Friend %s', 'Friends %s', $all_friends->get_total(), 'friends' ), '' . $all_friends->get_total() . '' ); 48 | 49 | if ( $all_friends->get_total() > 0 || ( ! $friend_requests->get_total() && ! $subscriptions->get_total() ) ) { 50 | echo $args['before_widget']; 51 | $this->list_friends( 52 | array_merge( 53 | array( 54 | 'widget_id' => $args['widget_id'] . '-all', 55 | ), 56 | $args 57 | ), 58 | $friends_title, 59 | $all_friends 60 | ); 61 | 62 | if ( ! $all_friends->get_total() ) { 63 | ?> 64 | 67 | get_total() > 0 ) { 72 | echo $args['before_widget']; 73 | $this->list_friends( 74 | array_merge( 75 | array( 76 | 'widget_id' => $args['widget_id'] . '-requests', 77 | ), 78 | $args 79 | ), 80 | // translators: %1$s is the string "%s Friend", %2$s is a URL, %3$s is the number of open friend requests. 81 | sprintf( _n( '%1$s (%3$s request)', '%1$s (%3$s requests)', $friend_requests->get_total(), 'friends' ), $friends_title, '"' . esc_attr( self_admin_url( 'users.php?role=friend_request' ) ) . '" class="open-requests"', $friend_requests->get_total() ), 82 | $friend_requests 83 | ); 84 | echo $args['after_widget']; 85 | } 86 | 87 | if ( 0 !== $subscriptions->get_total() ) { 88 | echo $args['before_widget']; 89 | $this->list_friends( 90 | array_merge( 91 | array( 92 | 'widget_id' => $args['widget_id'] . '-subscriptions', 93 | ), 94 | $args 95 | ), 96 | ' ' . sprintf( 97 | // translators: %s is the number of subscriptions. 98 | _n( 'Subscription %s', 'Subscriptions %s', $subscriptions->get_total(), 'friends' ), 99 | '' . $subscriptions->get_total() . '' 100 | ), 101 | $subscriptions 102 | ); 103 | echo $args['after_widget']; 104 | } 105 | 106 | do_action( 'friends_widget_friend_list_after', $this, $args ); 107 | } 108 | } 109 | 110 | -------------------------------------------------------------------------------- /widgets/class-widget-header.php: -------------------------------------------------------------------------------- 1 | __( 'The header for your friends page.', 'friends' ), 29 | ) 30 | ); 31 | } 32 | 33 | /** 34 | * Render the widget. 35 | * 36 | * @param array $args Sidebar arguments. 37 | * @param array $instance Widget instance settings. 38 | */ 39 | public function widget( $args, $instance ) { 40 | $instance = wp_parse_args( $instance, $this->defaults() ); 41 | $friends = Friends::get_instance(); 42 | 43 | $title = apply_filters( 'friends_header_widget_title', $instance['title'] ); 44 | $title = apply_filters( 'wptexturize', $title ); 45 | $title = apply_filters( 'convert_chars', $title ); 46 | 47 | echo $args['before_widget']; 48 | if ( ! empty( $title ) ) { 49 | echo $args['before_title'] . ' ' . $title . $args['after_title']; 50 | } 51 | 52 | if ( $friends->frontend->author ) { 53 | ?> 54 |

    55 | your friends page.', 'friends' ), 60 | // translators: 1: a friend's display name, 2: a URL. 61 | '' . esc_html( sprintf( __( '%1$s\'s external site at %2$s', 'friends' ), $friends->frontend->author->display_name, preg_replace( '#https?://#', '', trim( $friends->frontend->author->user_url, '/' ) ) ) ) . '', 62 | '"' . esc_attr( home_url( '/friends/' ) ) . '"' 63 | ), 64 | array( 65 | 'a' => array( 66 | 'href' => array(), 67 | 'class' => array(), 68 | 'data-token' => array(), 69 | ), 70 | ) 71 | ); 72 | ?> 73 |

    74 | defaults(), $instance ); 87 | ?> 88 |

    89 | 92 |

    93 | __( 'Friends', 'friends' ), 120 | 'show_post_formats' => true, 121 | ); 122 | } 123 | 124 | /** 125 | * Register this widget. 126 | */ 127 | public static function register() { 128 | register_widget( __CLASS__ ); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /widgets/class-widget-new-private-post.php: -------------------------------------------------------------------------------- 1 | __( 'Allows the creation of a new private post from within the page.', 'friends' ), 29 | ) 30 | ); 31 | } 32 | 33 | /** 34 | * Render the widget. 35 | * 36 | * @param array $args Sidebar arguments. 37 | * @param array $instance Widget instance settings. 38 | */ 39 | public function widget( $args, $instance ) { 40 | $instance = wp_parse_args( $instance, $this->defaults() ); 41 | 42 | $title = apply_filters( 'widget_title', $instance['title'] ); 43 | echo $args['before_widget']; 44 | if ( ! empty( $title ) ) { 45 | echo $args['before_title'] . $title . $args['after_title']; 46 | } 47 | 48 | ?> 49 |
    50 | 51 | 52 | 53 |
    54 | 55 | 56 | WordPress editor and set %2$s to %3$s.)', 'friends' ), '"' . self_admin_url( 'post-new.php' ) . '"', __( 'Visibility' ), __( 'Private' ) ), array( 'a' => array( 'href' => array() ) ) ); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain 59 | ?> 60 | 61 | 62 |
    63 | defaults; 77 | 78 | return $instance; 79 | } 80 | 81 | /** 82 | * Return an associative array of default values 83 | * 84 | * These values are used in new widgets. 85 | * 86 | * @return array Array of default values for the Widget's options 87 | */ 88 | public function defaults() { 89 | return array( 90 | 'title' => __( 'Friends', 'friends' ), 91 | ); 92 | } 93 | 94 | /** 95 | * Register this widget. 96 | */ 97 | public static function register() { 98 | register_widget( __CLASS__ ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /widgets/class-widget-recent-friends-list.php: -------------------------------------------------------------------------------- 1 | __( 'Shows a list of your Recent friends and subscriptions.', 'friends' ), 29 | ) 30 | ); 31 | } 32 | 33 | /** 34 | * Render the widget. 35 | * 36 | * @param array $args Sidebar arguments. 37 | * @param array $instance Widget instance settings. 38 | */ 39 | public function widget( $args, $instance ) { 40 | $instance = wp_parse_args( $instance, $this->defaults() ); 41 | 42 | echo $args['before_widget']; 43 | $this->list_friends( 44 | $args, 45 | ' ' . __( 'Recent Friends', 'friends' ), 46 | User_Query::recent_friends_subscriptions( 5 ) 47 | ); 48 | 49 | do_action( 'friends_widget_lastest_friend_list_after', $this, $args ); 50 | 51 | echo $args['after_widget']; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /widgets/class-widget-refresh.php: -------------------------------------------------------------------------------- 1 | __( "Shows a refresh link to refetch your friends' posts.", 'friends' ), 29 | ) 30 | ); 31 | } 32 | 33 | /** 34 | * Render the widget. 35 | * 36 | * @param array $args Sidebar arguments. 37 | * @param array $instance Widget instance settings. 38 | */ 39 | public function widget( $args, $instance ) { 40 | $instance = wp_parse_args( $instance, $this->defaults() ); 41 | 42 | $title = apply_filters( 'widget_title', $instance['title'] ); 43 | echo $args['before_widget']; 44 | if ( ! empty( $title ) ) { 45 | echo $args['before_title'] . $title . $args['after_title']; 46 | } 47 | 48 | echo '
    ' . esc_html__( 'Refresh', 'friends' ) . '
    '; 49 | 50 | echo $args['after_widget']; 51 | } 52 | 53 | 54 | /** 55 | * Update widget configuration. 56 | * 57 | * @param array $new_instance New settings. 58 | * @param array $old_instance Old settings. 59 | * @return array Sanitized instance settings. 60 | */ 61 | public function update( $new_instance, $old_instance ) { 62 | $instance = $this->defaults(); 63 | 64 | return $instance; 65 | } 66 | 67 | /** 68 | * Return an associative array of default values 69 | * 70 | * These values are used in new widgets. 71 | * 72 | * @return array Array of default values for the Widget's options 73 | */ 74 | public function defaults() { 75 | return array( 76 | 'title' => '', 77 | ); 78 | } 79 | 80 | /** 81 | * Register this widget. 82 | */ 83 | public static function register() { 84 | register_widget( __CLASS__ ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /widgets/class-widget-starred-friends-list.php: -------------------------------------------------------------------------------- 1 | __( 'Shows a list of your starred friends and subscriptions.', 'friends' ), 29 | ) 30 | ); 31 | } 32 | 33 | /** 34 | * Render the widget. 35 | * 36 | * @param array $args Sidebar arguments. 37 | * @param array $instance Widget instance settings. 38 | */ 39 | public function widget( $args, $instance ) { 40 | $friends = User_Query::starred_friends_subscriptions(); 41 | if ( ! $friends->get_total() ) { 42 | return; 43 | } 44 | $instance = wp_parse_args( $instance, $this->defaults() ); 45 | 46 | echo $args['before_widget']; 47 | 48 | $this->list_friends( 49 | $args, 50 | ' ' . _x( 'Starred', 'Starred Friends', 'friends' ), 51 | $friends 52 | ); 53 | 54 | do_action( 'friends_widget_starred_friend_list_after', $this, $args ); 55 | 56 | echo $args['after_widget']; 57 | } 58 | } 59 | --------------------------------------------------------------------------------