├── .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 |
33 |
34 | );
35 | },
36 | save: () => {
37 | const blockProps = useBlockProps.save();
38 |
39 | return (
40 |
41 |
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 |
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 |
40 |
41 |
42 | views(); ?>
43 |
44 |
54 |
55 | has_items() ) {
57 | $args['wp_list_table']->inline_edit();
58 | }
59 | ?>
60 |
61 |
62 |
--------------------------------------------------------------------------------
/templates/admin/browser-extension.php:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/templates/admin/dashboard-widget-welcome.php:
--------------------------------------------------------------------------------
1 |
9 |
10 |
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 |
77 |
--------------------------------------------------------------------------------
/templates/admin/edit-notifications.php:
--------------------------------------------------------------------------------
1 |
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 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/templates/admin/import-export.php:
--------------------------------------------------------------------------------
1 |
11 |
72 |
14 |
15 |
16 |
17 |
18 | |
19 | |
20 | |
21 |
22 |
23 |
24 |
25 |
26 |
27 | display_name ); ?>
28 |
29 | |
30 | user_registered ) ) ); ?> |
31 | get_role_name() ); ?> |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/templates/admin/logs.php:
--------------------------------------------------------------------------------
1 |
9 |
20 |
21 |
22 |
23 | |
24 | |
25 | |
26 |
27 |
28 |
29 |
32 |
33 | post_date ); ?> |
34 |
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 | |
50 | post_author ) ); ?> |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/templates/admin/opml.php:
--------------------------------------------------------------------------------
1 | ';
13 |
14 | ?>
15 |
16 |
17 |
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 |
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 |
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 |
18 | $data ) : ?>
19 |
20 |
21 |
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 |
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 |
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 |