├── .distignore ├── phpunit.xml.dist ├── .editorconfig ├── includes ├── feed-jf2-comments.php ├── feed-mf2-comments.php ├── feed-jf2.php ├── feed-mf2.php └── class-mf2-feed-entry.php ├── tests └── bootstrap.php ├── docker-compose.yml ├── package.json ├── phpcs.xml ├── languages └── mf2-feed.pot ├── LICENSE ├── composer.json ├── Gruntfile.js ├── bin └── install-wp-tests.sh ├── readme.md └── mf2-feed.php /.distignore: -------------------------------------------------------------------------------- 1 | /.wordpress-org 2 | /.git 3 | /.github 4 | /node_modules 5 | /bin 6 | /vendor 7 | /tests 8 | package.json 9 | composer.json 10 | composer.lock 11 | Gruntfile.js 12 | push.sh 13 | phpunit.xml 14 | phpcs.xml 15 | readme.txt 16 | .travis.yml 17 | .distignore 18 | .gitignore 19 | .gitattributes 20 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | ./tests/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | # WordPress Coding Standards 5 | # https://make.wordpress.org/core/handbook/coding-standards/ 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | indent_style = tab 15 | indent_size = 4 16 | 17 | [{.jshintrc,*.json,*.yml}] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [{*.txt,wp-config-sample.php}] 22 | end_of_line = crlf 23 | -------------------------------------------------------------------------------- /includes/feed-jf2-comments.php: -------------------------------------------------------------------------------- 1 | to_jf2(); 16 | } 17 | 18 | // filter output 19 | $items = apply_filters( 'jf2_feed_array', $items ); 20 | echo Mf2Feed::encode_json( $items ); 21 | -------------------------------------------------------------------------------- /includes/feed-mf2-comments.php: -------------------------------------------------------------------------------- 1 | to_mf2(); 16 | } 17 | 18 | // filter output 19 | $items = apply_filters( 'mf2_feed_array', $items ); 20 | echo Mf2Feed::encode_json( $items ); 21 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 'feed', 13 | 'name' => get_bloginfo( 'name' ), 14 | 'summary' => get_bloginfo( 'description' ), 15 | 'url' => get_self_link(), 16 | ); 17 | if ( ! empty( $featured ) ) { 18 | $items['featured'] = $featured; 19 | } 20 | 21 | while ( have_posts() ) { 22 | the_post(); 23 | $item = new Mf2_Feed_Entry( get_the_ID() ); 24 | $items['children'][] = $item->to_jf2(); 25 | } 26 | 27 | // filter output 28 | $items = apply_filters( 'jf2_feed_array', $items ); 29 | echo Mf2Feed::encode_json( $items ); 30 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | WordPress MF2 Feed Standards 4 | 5 | ./mf2-feed.php 6 | ./includes/ 7 | */includes/*\.(inc|css|js|svg) 8 | */vendor/* 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /includes/feed-mf2.php: -------------------------------------------------------------------------------- 1 | array( 13 | array( 14 | 'type' => array( 'h-feed' ), 15 | 'properties' => array( 16 | 'name' => array( get_bloginfo( 'name' ) ), 17 | 'summary' => array( get_bloginfo( 'description' ) ), 18 | 'url' => array( get_self_link() ), 19 | ), 20 | ), 21 | ), 22 | ); 23 | 24 | $featured = get_site_icon_url(); 25 | if ( ! empty( $featured ) ) { 26 | $items['items'][0]['properties']['featured'] = array( $featured ); 27 | } 28 | 29 | while ( have_posts() ) { 30 | the_post(); 31 | $item = new Mf2_Feed_Entry( get_the_ID() ); 32 | $items['items'][0]['children'][] = current( $item->to_mf2() ); 33 | } 34 | 35 | // filter output 36 | $items = apply_filters( 'mf2_feed_array', $items ); 37 | echo Mf2Feed::encode_json( $items ); 38 | -------------------------------------------------------------------------------- /languages/mf2-feed.pot: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 IndieWeb WordPress Outreach Club 2 | # This file is distributed under the MIT. 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: MF2 Feed 3.1.1\n" 6 | "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/mf2-feed\n" 7 | "POT-Creation-Date: 2022-05-25 07:47:35+00:00\n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=utf-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | "PO-Revision-Date: 2022-MO-DA HO:MI+ZONE\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language-Team: LANGUAGE \n" 14 | "X-Generator: grunt-wp-i18n1.0.2\n" 15 | 16 | #. Plugin Name of the plugin/theme 17 | msgid "MF2 Feed" 18 | msgstr "" 19 | 20 | #. Plugin URI of the plugin/theme 21 | msgid "http://github.com/indieweb/wordpress-mf2-feed/" 22 | msgstr "" 23 | 24 | #. Description of the plugin/theme 25 | msgid "Adds a Microformats2 JSON feed for every entry" 26 | msgstr "" 27 | 28 | #. Author of the plugin/theme 29 | msgid "IndieWeb WordPress Outreach Club" 30 | msgstr "" 31 | 32 | #. Author URI of the plugin/theme 33 | msgid "https://indieweb.org/WordPress_Outreach_Club" 34 | msgstr "" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Matthias Pfefferle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "indieweb/wordpress-mf2-feed", 3 | "description": "provides a Microformats2 JSON Feed for every WordPress URL.", 4 | "type": "wordpress-plugin", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Matthias Pfefferle", 9 | "homepage": "http://notiz.blog" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.3.0", 14 | "composer/installers": "~1.0" 15 | }, 16 | "extra": { 17 | "installer-name": "mf2-feed" 18 | }, 19 | "require-dev": { 20 | "phpunit/phpunit": "5.7.*", 21 | "squizlabs/php_codesniffer": "^2.2 || ^3.0.2", 22 | "phpcompatibility/php-compatibility": "*", 23 | "wp-coding-standards/wpcs": "*", 24 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3", 25 | "phpcompatibility/phpcompatibility-wp": "^1.0" 26 | }, 27 | "scripts": { 28 | "install-codestandards": [ 29 | "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run" 30 | ], 31 | "test": [ 32 | "composer update", 33 | "bin/install-wp-tests.sh wordpress wordpress wordpress", 34 | "vendor/bin/phpunit" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | // Project configuration. 3 | grunt.initConfig({ 4 | checktextdomain: { 5 | options:{ 6 | text_domain: 'mf2-feed', 7 | keywords: [ 8 | '__:1,2d', 9 | '_e:1,2d', 10 | '_x:1,2c,3d', 11 | 'esc_html__:1,2d', 12 | 'esc_html_e:1,2d', 13 | 'esc_html_x:1,2c,3d', 14 | 'esc_attr__:1,2d', 15 | 'esc_attr_e:1,2d', 16 | 'esc_attr_x:1,2c,3d', 17 | '_ex:1,2c,3d', 18 | '_n:1,2,4d', 19 | '_nx:1,2,4c,5d', 20 | '_n_noop:1,2,3d', 21 | '_nx_noop:1,2,3c,4d' 22 | ] 23 | }, 24 | files: { 25 | src: [ 26 | '**/*.php', // Include all files 27 | 'includes/*.php', // Include includes 28 | '!sass/**', // Exclude sass/ 29 | '!node_modules/**', // Exclude node_modules/ 30 | '!tests/**', // Exclude tests/ 31 | '!vendor/**', // Exclude vendor/ 32 | '!build/**', // Exclude build/ 33 | '!static/**', // Exclude static resources 34 | ], 35 | expand: true 36 | } 37 | }, 38 | 39 | wp_readme_to_markdown: { 40 | target: { 41 | files: { 42 | 'readme.md': 'readme.txt' 43 | }, 44 | }, 45 | }, 46 | makepot: { 47 | target: { 48 | options: { 49 | mainFile: 'mf2-feed.php', 50 | domainPath: '/languages', 51 | exclude: ['bin/.*', '.git/.*', 'vendor/.*'], 52 | potFilename: 'mf2-feed.pot', 53 | type: 'wp-plugin', 54 | updateTimestamp: true 55 | } 56 | } 57 | } 58 | }); 59 | 60 | grunt.loadNpmTasks('grunt-wp-readme-to-markdown'); 61 | grunt.loadNpmTasks('grunt-wp-i18n'); 62 | grunt.loadNpmTasks('grunt-checktextdomain'); 63 | 64 | // Default task(s). 65 | grunt.registerTask('default', ['wp_readme_to_markdown', 'makepot', 'checktextdomain']); 66 | }; 67 | -------------------------------------------------------------------------------- /bin/install-wp-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -lt 3 ]; then 4 | echo "usage: $0 [db-host] [wp-version]" 5 | exit 1 6 | fi 7 | 8 | DB_NAME=$1 9 | DB_USER=$2 10 | DB_PASS=$3 11 | DB_HOST=${4-localhost} 12 | WP_VERSION=${5-latest} 13 | 14 | WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} 15 | WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} 16 | 17 | download() { 18 | if [ `which curl` ]; then 19 | curl -s "$1" > "$2"; 20 | elif [ `which wget` ]; then 21 | wget -nv -O "$2" "$1" 22 | fi 23 | } 24 | 25 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then 26 | WP_TESTS_TAG="tags/$WP_VERSION" 27 | elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then 28 | WP_TESTS_TAG="trunk" 29 | else 30 | # http serves a single offer, whereas https serves multiple. we only want one 31 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json 32 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json 33 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') 34 | if [[ -z "$LATEST_VERSION" ]]; then 35 | echo "Latest WordPress version could not be found" 36 | exit 1 37 | fi 38 | WP_TESTS_TAG="tags/$LATEST_VERSION" 39 | fi 40 | 41 | set -ex 42 | 43 | install_wp() { 44 | 45 | if [ -d $WP_CORE_DIR ]; then 46 | return; 47 | fi 48 | 49 | mkdir -p $WP_CORE_DIR 50 | 51 | if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then 52 | mkdir -p /tmp/wordpress-nightly 53 | download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip 54 | unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/ 55 | mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR 56 | else 57 | if [ $WP_VERSION == 'latest' ]; then 58 | local ARCHIVE_NAME='latest' 59 | else 60 | local ARCHIVE_NAME="wordpress-$WP_VERSION" 61 | fi 62 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz 63 | tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR 64 | fi 65 | 66 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php 67 | } 68 | 69 | install_test_suite() { 70 | # portable in-place argument for both GNU sed and Mac OSX sed 71 | if [[ $(uname -s) == 'Darwin' ]]; then 72 | local ioption='-i .bak' 73 | else 74 | local ioption='-i' 75 | fi 76 | 77 | # set up testing suite if it doesn't yet exist 78 | if [ ! -d $WP_TESTS_DIR ]; then 79 | # set up testing suite 80 | mkdir -p $WP_TESTS_DIR 81 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes 82 | fi 83 | 84 | cd $WP_TESTS_DIR 85 | 86 | if [ ! -f wp-tests-config.php ]; then 87 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php 88 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php 89 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php 90 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php 91 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php 92 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php 93 | fi 94 | 95 | } 96 | 97 | install_db() { 98 | # parse DB_HOST for port or socket references 99 | local PARTS=(${DB_HOST//\:/ }) 100 | local DB_HOSTNAME=${PARTS[0]}; 101 | local DB_SOCK_OR_PORT=${PARTS[1]}; 102 | local EXTRA="" 103 | 104 | if ! [ -z $DB_HOSTNAME ] ; then 105 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then 106 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" 107 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then 108 | EXTRA=" --socket=$DB_SOCK_OR_PORT" 109 | elif ! [ -z $DB_HOSTNAME ] ; then 110 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" 111 | fi 112 | fi 113 | 114 | # create database 115 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA 116 | } 117 | 118 | install_wp 119 | install_test_suite 120 | install_db 121 | -------------------------------------------------------------------------------- /includes/class-mf2-feed-entry.php: -------------------------------------------------------------------------------- 1 | _id = $post->ID; 31 | $this->type = 'entry'; 32 | $this->name = get_the_title( $post ); 33 | // Eliminate IDs as names 34 | if ( $this->name = $this->_id ) { 35 | $this->name = null; 36 | } 37 | $this->published = get_post_time( DATE_W3C, false, $post ); 38 | $this->updated = get_post_modified_time( DATE_W3C, false, $post ); 39 | $content = get_the_content( null, false, $post ); 40 | if ( ! empty( $content ) ) { 41 | $this->content['html'] = get_the_content( null, false, $post ); 42 | $this->content['value'] = wp_strip_all_tags( $this->content['html'] ); 43 | } 44 | $this->summary = get_the_excerpt( $post ); 45 | $this->url = get_permalink( $post ); 46 | $this->uid = get_permalink( $post ); 47 | 48 | // Get a list of categories and extract their names 49 | $post_categories = get_the_terms( $post->ID, 'category' ); 50 | if ( ! empty( $post_categories ) && ! is_wp_error( $post_categories ) ) { 51 | $this->category = wp_list_pluck( $post_categories, 'name' ); 52 | } 53 | 54 | // Get a list of tags and extract their names 55 | $post_tags = get_the_terms( $post->ID, 'post_tag' ); 56 | if ( ! empty( $post_tags ) && ! is_wp_error( $post_tags ) ) { 57 | $this->category = array_merge( $this->category, wp_list_pluck( $post_tags, 'name' ) ); 58 | } 59 | 60 | if ( has_post_thumbnail( $post ) ) { 61 | $this->featured = wp_get_attachment_url( get_post_thumbnail_id( $post ), 'full' ); 62 | } 63 | 64 | $this->author['type'] = 'card'; 65 | $this->author['name'] = get_the_author_meta( 'display_name', $post->post_author ); 66 | $this->author['value'] = get_the_author_meta( 'display_name', $post->post_author ); 67 | $this->author['url'] = get_the_author_meta( 'user_url', $post->post_author ) ? get_the_author_meta( 'user_url', $post->post_author ) : get_author_posts_url( $post->post_author ); 68 | $this->author['photo'] = get_avatar_url( $post->post_author ); 69 | 70 | // add comments 71 | if ( $with_comments ) { 72 | foreach ( get_comments( array( 'post_id' => $post->ID ) ) as $post_comment ) { 73 | $comment = array(); 74 | $comment['type'] = 'cite'; 75 | $comment['content']['html'] = get_comment_text( $post_comment ); 76 | $comment['content']['value'] = wp_strip_all_tags( $comment['content']['html'] ); 77 | $comment['published'] = get_comment_date( DATE_W3C, $post_comment ); 78 | $comment['author']['type'] = 'card'; 79 | $comment['author']['name'] = get_comment_author( $post_comment ); 80 | $comment['author']['value'] = $comment['author']['name']; 81 | 82 | if ( $post_comment->comment_author_url ) { 83 | $comment['author']['url'] = get_comment_author_url( $post_comment ); 84 | } 85 | 86 | $this->comment[] = $comment; 87 | } 88 | } 89 | } 90 | 91 | public function to_mf2() { 92 | $entry = apply_filters( 'jf2_entry_array', get_object_vars( $this ), $this->_id ); 93 | $entry = array_filter( $entry ); 94 | $entry = apply_filters( 'mf2_entry_array', $this->jf2_to_mf2( $entry ), $this->_id ); 95 | return $entry; 96 | } 97 | 98 | public function to_jf2() { 99 | $entry = apply_filters( 'jf2_entry_array', get_object_vars( $this ), $this->_id ); 100 | return array_filter( $entry ); 101 | } 102 | 103 | public function jf2_to_mf2( $entry ) { 104 | if ( ! $entry || ! is_array( $entry ) | isset( $entry['properties'] ) ) { 105 | return $entry; 106 | } 107 | 108 | $return = array(); 109 | $return['type'] = array( 'h-' . $entry['type'] ); 110 | $return['properties'] = array(); 111 | 112 | if ( ! empty( $entry['value'] ) ) { 113 | $return['type'] = $entry['value']; 114 | } 115 | 116 | unset( $entry['type'] ); 117 | unset( $entry['value'] ); 118 | 119 | foreach ( $entry as $key => $value ) { 120 | if ( empty( $value ) ) { 121 | continue; 122 | } 123 | if ( ! wp_is_numeric_array( $value ) && is_array( $value ) && array_key_exists( 'type', $value ) ) { 124 | $value = $this->jf2_to_mf2( $value ); 125 | } elseif ( wp_is_numeric_array( $value ) && is_array( $value[0] ) && array_key_exists( 'type', $value[0] ) ) { 126 | foreach ( $value as $item ) { 127 | $items[] = $this->jf2_to_mf2( $item ); 128 | } 129 | $value = $items; 130 | } elseif ( wp_is_numeric_array( $value ) && ! is_array( $value[0] ) ) { 131 | $value = $value; 132 | } elseif ( ! wp_is_numeric_array( $value ) ) { 133 | $value = array( $value ); 134 | } else { 135 | continue; 136 | } 137 | 138 | $return['properties'][ $key ] = $value; 139 | } 140 | 141 | return array_filter( array( $return ) ); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # MF2 Feeds 2 | - Contributors: pfefferle, dshanske, indieweb 3 | - Donate link: https://opencollective.com/indieweb 4 | - Tags: microformats, mf2, jf2, rel-alternate, indieweb 5 | - Requires at least: 5.2 6 | - Tested up to: 6.9 7 | - Stable tag: 3.1.1 8 | - Requires PHP: 7.2 9 | - License: MIT 10 | - License URI: http://opensource.org/licenses/MIT 11 | 12 | Add Microformats2 Feeds for WordPress 13 | 14 | ## Description 15 | 16 | Provides a [Microformats2 JSON](http://microformats.org/wiki/microformats2-parsing) "Feed" for every WordPress URL, and helps to allow other sites to get pre-parsed [Microformats-JSON](https://indieweb.org/jf2) even if the theme 17 | does not support Microformats2. 18 | 19 | [Microformats2](https://indieweb.org/microformats) are a key [building-block](https://indieweb.org/Category:building-blocks) of the IndieWeb, but it is very hard (if not impossible) to get Microformats2 as a core feature for all WordPress themes. There are several themes that are supporting Microformats2, but everyone should choose his prefered theme and should not be limited to use one of the [few community themes](https://indieweb.org/WordPress/Themes). After [a lot of discussions](https://github.com/indieweb/wordpress-uf2/issues/30) and some different plugin approaches, we are trying to provide an alternate ([`rel=altenate`](https://indieweb.org/rel-alternate)) representation of the microformatted HTML. 20 | 21 | The plugin is inspired by the URL design of [p3k](https://github.com/aaronpk/p3k) of [@aaronpk](https://github.com/aaronpk). 22 | 23 | p3k Example: 24 | 25 | * Original: 26 | * Microformats2 JSON: 27 | * JF2: 28 | 29 | WordPress Example: 30 | 31 | * Original: 32 | * Microformats2 JSON: 33 | * JF2: 34 | 35 | ## FAQ 36 | 37 | ### What are Microformats 2? 38 | 39 | Microformats are a simple way to markup structured information in HTML using classes. WordPress incorporates some classic Microformats. Microformats 2 supersedes classic microformats. 40 | 41 | ## Installation 42 | 43 | Follow the normal instructions for [installing WordPress plugins](https://codex.wordpress.org/Managing_Plugins#Installing_Plugins). 44 | 45 | ### Automatic Plugin Installation 46 | 47 | To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins): 48 | 49 | 1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen). 50 | 1. Type "`mf2-feed`" into the **Search Plugins** box. 51 | 1. Find the WordPress Plugin you wish to install. 52 | 1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin. 53 | 1. Click **Install Now** to install the WordPress Plugin. 54 | 1. The resulting installation screen will list the installation as successful or note any problems during the install. 55 | 1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. 56 | 57 | ### Manual Plugin Installation 58 | 59 | There are a few cases when manually installing a WordPress Plugin is appropriate. 60 | 61 | * If you wish to control the placement and the process of installing a WordPress Plugin. 62 | * If your server does not permit automatic installation of a WordPress Plugin. 63 | * If you want to try the [latest development version](https://github.com/indieweb/wordpress-mf2-feed). 64 | 65 | Installation of a WordPress Plugin manually requires FTP familiarity and the awareness that you may put your site at risk if you install a WordPress Plugin incompatible with the current version or from an unreliable source. 66 | 67 | Backup your site completely before proceeding. 68 | 69 | To install a WordPress Plugin manually: 70 | 71 | * Download your WordPress Plugin to your desktop. 72 | * Download from [the WordPress directory](https://wordpress.org/plugins/mf2-feed/) 73 | * Download from [GitHub](https://github.com/indieweb/wordpress-mf2-feed/releases) 74 | * If downloaded as a zip archive, extract the Plugin folder to your desktop. 75 | * With your FTP program, upload the Plugin folder to the `wp-content/plugins` folder in your WordPress directory online. 76 | * Go to [Plugins screen](https://codex.wordpress.org/Administration_Screens#Plugins) and find the newly uploaded Plugin in the list. 77 | * Click **Activate** to activate it. 78 | 79 | ## Changelog 80 | 81 | Project actively developed on Github at [indieweb/wordpress-mf2-feed](https://github.com/indieweb/wordpress-mf2-feed). Please file support issues there. 82 | 83 | ### 3.1.1 84 | 85 | * Small tweaks and dependency updates 86 | 87 | ### 3.1.0 88 | 89 | * Support Content Negotiation 90 | 91 | ### 3.0.0 92 | 93 | * Refactored to match the configuration of feeds built into WordPress 94 | * Bumped PHP Version requirement to PHP5.6 to match WordPress 5.3 95 | * Bumped minimum WordPress version to 5.2 as this allows for the version of get_content that includes a $post parameter 96 | * Fixed incorrect PHPCS configuration 97 | * Enabled JSON Pretty Print by default as originally disabled due a PHP5.4 requirement 98 | * Changed Post Item Generation Class to use WordPress functions instead of directly accessing the data where applicable 99 | * Adjusted jf2 feed to comply with jf2feed spec (https://jf2.spec.indieweb.org/#jf2feed) 100 | 101 | ### 2.1.0 102 | 103 | * Fixed JSON output 104 | * Fixed "flush rewrite rules" again 105 | 106 | ### 2.0.1 107 | 108 | * Fixed "flush rewrite rules" 109 | * Added filter to extend the mf2/jf2 data 110 | 111 | ### 2.0.0 112 | 113 | * Complete re-write to match the latest ideas of rel-alternate: https://github.com/indieweb/wordpress-uf2/issues/38 114 | 115 | ### 1.0.0 116 | 117 | * Initial plugin 118 | -------------------------------------------------------------------------------- /mf2-feed.php: -------------------------------------------------------------------------------- 1 | 173 | 174 | 175 | 178 | 179 | 180 |