diff --git a/micropub.php b/micropub.php index 9909097..f5c67f5 100755 --- a/micropub.php +++ b/micropub.php @@ -5,7 +5,7 @@ Description: Micropub server. Author: Ryan Barrett Author URI: https://snarfed.org/ - Version: 0.3 + Version: 0.4 */ // Example command line for testing: @@ -20,6 +20,23 @@ // curl -i -d 'code=CODE&me=SITE&client_id=indieauth&redirect_uri=https://indieauth.com/success' 'https://tokens.indieauth.com/token' // 4. Extract the access_token parameter from the response body. +// For debugging purposes this will bypass Micropub authentication +// in favor of WordPress authentication +// Using this to test querying(q=) parameters quickly +if ( ! defined( 'MICROPUB_LOCAL_AUTH' ) ) + define('MICROPUB_LOCAL_AUTH', '0'); + +// Allows for a custom Authentication and Token Endpoint +if ( ! defined( 'MICROPUB_AUTHENTICATION_ENDPOINT' ) ) + define('MICROPUB_AUTHENTICATION_ENDPOINT', 'https://indieauth.com/auth'); +if ( ! defined( 'MICROPUB_TOKEN_ENDPOINT' ) ) + define('MICROPUB_TOKEN_ENDPOINT', 'https://tokens.indieauth.com/token'); + +// For debugging purposes this will set all Micropub posts to Draft +if ( ! defined( 'MICROPUB_DRAFT_MODE' ) ) + define('MICROPUB_DRAFT_MODE', '0'); + + if (!class_exists('Micropub')) : add_action('init', array('Micropub', 'init')); @@ -70,14 +87,26 @@ public static function parse_query($wp) { return; } header('Content-Type: text/plain; charset=' . get_option('blog_charset')); - - $user_id = Micropub::authorize(); + // For debug purposes be able to bypass Micropub auth with WordPress auth + if (MICROPUB_LOCAL_AUTH!=0) { + if (!is_user_logged_in()) { + auth_redirect(); + } + $user_id = wp_get_current_user(); + } + else { + $user_id = Micropub::authorize(); + } + // TODO: future development note to add JSON support // validate micropub request params - if (!isset($_POST['h']) && !isset($_POST['url'])) { - Micropub::error(400, 'requires either h= (for create) or url= (for update, delete, etc)'); + if (!isset($_POST['h']) && !isset($_POST['url']) && !isset($_GET['q'])) { + Micropub::error(400, 'Empty Micropub request. Either an "h", "url" or "q" property is required, e.g. h=entry or url=http://example.com/post/100 or q=syndicate-to'); + } + if (isset($_GET['q'])) { + Micropub::return_query($user_id); + exit; } - // support both action= and operation= parameter names if (!isset($_POST['action'])) { $_POST['action'] = isset($_POST['operation']) ? $_POST['operation'] @@ -89,11 +118,11 @@ public static function parse_query($wp) { $args['post_author'] = $user_id; } - if (!isset($_POST['url']) || $_POST['action'] == 'create') { + if (!isset($_POST['edit-of']) || !isset($_POST['url']) || $_POST['action'] == 'create') { if ($user_id && !user_can($user_id, 'publish_posts')) { Micropub::error(403, 'user id ' . $user_id . ' cannot publish posts'); } - $args['post_status'] = 'publish'; + $args['post_status'] = MICROPUB_DRAFT_MODE ? 'draft' : 'publish'; kses_remove_filters(); // prevent sanitizing HTML tags in post_content $args['ID'] = Micropub::check_error(wp_insert_post($args)); kses_init_filters(); @@ -103,7 +132,7 @@ public static function parse_query($wp) { } else { if ($args['ID'] == 0) { - Micropub::error(400, $_POST['url'] . ' not found'); + Micropub::error(400, $_POST['edit-of'] . ' not found'); } if ($_POST['action'] == 'edit' || !isset($_POST['action'])) { @@ -197,6 +226,24 @@ private static function authorize() { return NULL; } + private static function return_query($user_id) { + header('Content-type: application/x-www-form-urlencoded'); + switch($_GET['q']) { + case 'syndicate-to': + // Fallback + case 'mp-syndicate-to': + status_header(200); + // return empty syndication target with filter + $syndication = apply_filters('micropub_syndicate-to', array(), $user_id); + if (!empty($syndication)) { + echo 'syndicate-to[]=' . implode('&syndicate-to[]=', $syndication); + } + break; + default: + Micropub::error(400, 'unknown query ' . $_GET['q']); + } + } + private static function handle_authorize_error($code, $msg) { $home = untrailingslashit(home_url()); if ($home == 'http://localhost') { @@ -226,10 +273,14 @@ private static function generate_args() { } // these are transformed or looked up + if (isset($_POST['edit-of'])) { + $args['ID'] = url_to_postid($_POST['edit-of']); + } if (isset($_POST['url'])) { $args['ID'] = url_to_postid($_POST['url']); } + if (isset($_POST['published'])) { $args['post_date'] = iso8601_to_datetime($_POST['published']); $args['post_date_gmt'] = get_gmt_from_date($args['post_date']); @@ -252,6 +303,9 @@ private static function generate_args() { if (isset($_POST['content'])) { $args['post_content'] = $_POST['content']; } + else if (isset($_POST['summary'])) { + $args['post_content'] = $_POST['summary']; + } } // Else markup the content before passing it through else { @@ -377,24 +431,23 @@ private static function postprocess($post_id) { * https://indiewebcamp.com/WordPress_Data#Microformats_data */ private static function store_mf2($post_id) { - $props = array('category', 'content', 'description', 'end', 'h', 'in-reply-to', - 'like', 'like-of', 'location', 'name', 'photo', 'published', - 'repost', 'repost-of', 'rsvp', 'slug', 'start', 'summary'); - - foreach ($props as $prop) { - if (isset($_POST[$prop])) { - $vals = $_POST[$prop]; - if (!is_array($vals)) { - $vals = array($vals); - } - - $key = 'mf2_' . $prop; + // Do not store access_token or other optional parameters + $blacklist = array('access_token'); + foreach ($_POST as $key => $value) { + if (!is_array($value)) { + $value = array($value); + } + if (!in_array($key, $blacklist)) { + $key = 'mf2_' . $key; delete_post_meta($post_id, $key); // clear old value(s) - foreach ($vals as $val) { - add_post_meta($post_id, $key, $val); + foreach ($value as $val) { + if (!empty($val)) { + add_post_meta($post_id, $key, $val); + } } } } + } private static function error($code, $msg) { @@ -416,11 +469,9 @@ private static function check_error($result) { * The micropub autodicovery meta tags */ public static function html_header() { -?> - - - -'; + echo ''; + echo ''; } /** @@ -428,8 +479,8 @@ public static function html_header() { */ public static function http_header() { header('Link: <' . site_url('?micropub=endpoint') . '>; rel="micropub"', false); - header('Link: ; rel="authorization_endpoint"', false); - header('Link: ; rel="token_endpoint"', false); + header('Link: <' . MICROPUB_AUTHENTICATION_ENDPOINT . '>; rel="authorization_endpoint"', false); + header('Link: <' . MICROPUB_TOKEN_ENDPOINT . '>; rel="token_endpoint"', false); } /** @@ -439,9 +490,9 @@ public static function jrd_links($array) { $array['links'][] = array('rel' => 'micropub', 'href' => site_url('?micropub=endpoint')); $array['links'][] = array('rel' => 'authorization_endpoint', - 'href' => 'https://indieauth.com/auth'); + 'href' => MICROPUB_AUTHENTICATION_ENDPOINT); $array['links'][] = array('rel' => 'token_endpoint', - 'href' => 'https://tokens.indieauth.com/token'); + 'href' => MICROPUB_TOKEN_ENDPOINT); } } diff --git a/readme.txt b/readme.txt index dc9287d..8fad0a9 100644 --- a/readme.txt +++ b/readme.txt @@ -1,8 +1,8 @@ === Plugin Name === -Contributors: snarfed +Contributors: snarfed, dshanske Tags: micropub Requires at least: 3.0.1 -Tested up to: 4.1 +Tested up to: 4.2 Stable tag: trunk License: CC0 License URI: http://creativecommons.org/publicdomain/zero/1.0/ @@ -44,13 +44,18 @@ Micropub properties: * `summary` * `url` -Adds one WordPress filter, `before_micropub($wp_args)`, and one hook, -`after_micropub($post_id)`. +Adds the following filters: +* `before_micropub($wp_args)` +* `micropub_syndicate-to', array(), $user_id)` + +And the hook: +* `after_micropub($post_id)` Delegates token handling to -[tokens.indieauth.com](https://tokens.indieauth.com/). For ease of development, -if the WordPress site is running on `localhost`, it logs a warning if the access -token is missing or invalid and still allows the request. +[tokens.indieauth.com](https://tokens.indieauth.com/) by default. For ease of +development, if the WordPress site is running on `localhost`, it logs a warning +if the access token is missing or invalid and still allows the request. +There is also a wp-config option to use WordPress authentication. Stores [microformats2](http://microformats.org/wiki/microformats2) properties in [post metadata](http://codex.wordpress.org/Function_Reference/post_meta_Function_Examples) @@ -64,6 +69,18 @@ and pull requests are welcome! Install from the WordPress plugin directory or put `micropub.php` in your plugin directory. No setup needed. +== Configuration Options == + +These configuration options can be enabled by adding them to your wp-config.php + +* `define('MICROPUB_LOCAL_AUTH', '1')` - Bypasses Micropub authentication in +favor of WordPress authentication for testing purposes +* `define('MICROPUB_AUTHENTICATION_ENDPOINT'`, 'https://indieauth.com/auth') +Define a custom authentication endpoint +* `define('MICROPUB_TOKEN_ENDPOINT', 'https://tokens.indieauth.com/token')` - +Define a custom token endpoint +* `define('MICROPUB_DRAFT_MODE', '1')` - set all micropub posts to draft mode + == Frequently Asked Questions == None yet. @@ -78,6 +95,17 @@ TODO == Changelog == += 0.4 = +* Store all properties in post meta except those in a blacklist +* Support setting authentication and token endpoint in wp-config + (set MICROPUB_AUTHENTICATION_ENDPOINT and MICROPUB_TOKEN_ENDPOINT) +* Support setting all micropub posts to draft in wp-config for testing by +setting MICROPUB_DRAFT_MODE in wp-config. +* Support using local auth to authenticate as opposed to Indieauth +as by setting MICROPUB_LOCAL_AUTH in wp-config +* Set content to summary if no content provided +* Support querying for syndicate-to and future query options + = 0.3 = * Use the specific WordPress user whose URL matches the access token, if possible.