diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..b46aef3 --- /dev/null +++ b/composer.json @@ -0,0 +1,4 @@ +{ + "name": "hookpress", + "type": "wordpress-plugin" +} diff --git a/hookpress.php b/hookpress.php index 9cab3ee..f6fd5a4 100644 --- a/hookpress.php +++ b/hookpress.php @@ -3,14 +3,14 @@ Plugin Name: HookPress Plugin URI: http://mitcho.com/code/hookpress/ Description: HookPress turns all of your WordPress-internal hooks into webhooks. Possible uses include generating push notifications or using non-PHP web technology to extend WordPress. Read more about webhooks at the webhooks site. -Version: 1.14 +Version: 1.16 Author: mitcho (Michael Yoshitaka Erlewine) Author URI: http://mitcho.com/ Donate link: http://tinyurl.com/donatetomitcho */ define('HOOKPRESS_PRIORITY',12838790321); -$hookpress_version = "1.14"; +$hookpress_version = "1.16"; require('includes.php'); function hookpress_init() { @@ -21,9 +21,11 @@ function hookpress_init() { update_option('hookpress_version',$hookpress_version); add_action('admin_menu', 'hookpress_config_page'); + hookpress_register_hooks(); + } + add_action('init', 'hookpress_init'); -hookpress_register_hooks(); // register ajax service add_action('wp_ajax_hookpress_get_fields', 'hookpress_ajax_get_fields'); diff --git a/includes.php b/includes.php index 467b3d7..50eca36 100644 --- a/includes.php +++ b/includes.php @@ -27,14 +27,22 @@ function hookpress_get_fields( $type ) { } // if it's a POST, we have a URL for it as well. - if ($type == 'POST' || $type == 'PARENT_POST') + if ($type == 'POST' || $type == 'PARENT_POST') { + $fields[] = 'post_url'; + $meta_keys = $wpdb->get_col("select distinct(meta_key) from $wpdb->postmeta"); + + $fields = array_merge($fields, $meta_keys); + } + if ($type == 'PARENT_POST') - $fields = array_map(create_function('$x','return "parent_$x";'),$fields); + $fields = array_map(function ($x) { return "parent_$x"; }, $fields); if ($type == 'OLD_USER_OBJ') - $fields = array_map(create_function('$x','return "old_$x";'),$fields); + $fields = array_map(function ($x) { return "old_$x"; }, $fields); + + $fields = apply_filters('hookpress_get_fields', $fields, $type); return array_unique($fields); } @@ -43,12 +51,14 @@ function hookpress_print_edit_webhook( $id ){ ?> @@ -58,7 +68,7 @@ function hookpress_print_edit_webhook( $id ){
', $desc['fields'] ); } else $fields = esc_html( $desc['fields'][0] ); - + $edit = '' . __('Edit') . ''; - + $activeornot = $desc['enabled'] ? 'active' : 'inactive'; $html_safe['hook'] = esc_html( $desc['hook'] ); @@ -205,10 +217,10 @@ function hookpress_print_webhooks_table() { $desc) : - - if( !empty( $desc ) ): + + if( !empty( $desc ) ): hookpress_print_webhook_row( $id ); endif; endforeach; @@ -224,24 +236,28 @@ function hookpress_print_webhooks_table() { function hookpress_register_hooks() { global $hookpress_callbacks, $hookpress_actions, $hookpress_filters; $hookpress_callbacks = array(); - + $all_hooks = hookpress_get_hooks( ); - + if (!is_array( $all_hooks ) ) return; foreach ( $all_hooks as $id => $desc) { if (count($desc) && $desc['enabled']) { - $hookpress_callbacks[$id] = create_function('',' + + $hookpress_callbacks[$id] = function() use ($id) { $args = func_get_args(); - return hookpress_generic_action('.$id.',$args); - '); + + return hookpress_generic_action($id, $args); + }; $arg_count = 0; if (isset($desc['type']) && $desc['type'] == 'filter') $arg_count = count($hookpress_filters[$desc['hook']]); - else - $arg_count = count($hookpress_actions[$desc['hook']]); + else { + $hooks = apply_filters( 'hookpress_actions', $hookpress_actions ); + $arg_count = count($hooks[$desc['hook']]); + } add_filter($desc['hook'], $hookpress_callbacks[$id], HOOKPRESS_PRIORITY, $arg_count); } @@ -250,30 +266,37 @@ function hookpress_register_hooks() { function hookpress_generic_action($id,$args) { global $hookpress_version, $wpdb, $hookpress_actions, $hookpress_filters, $wp_version; - + $webhooks = hookpress_get_hooks( ); $desc = $webhooks[$id]; do_action( 'hookpress_hook_fired', $desc ); $obj = array(); - + // generate the expected argument names if (isset($desc['type']) && $desc['type'] == 'filter') - $arg_names = $hookpress_filters[$desc['hook']]; - else - $arg_names = $hookpress_actions[$desc['hook']]; - + $arg_names = $hookpress_filters[$desc['hook']]; + else { + $hooks = apply_filters( 'hookpress_actions', $hookpress_actions ); + $arg_names = $hooks[$desc['hook']]; + } + foreach($args as $i => $arg) { - $newobj = array(); + $newobj = apply_filters('hookpress_get_data', $obj, $arg_names[$i], $arg); + switch($arg_names[$i]) { case 'POST': case 'ATTACHMENT': $newobj = get_post($arg,ARRAY_A); - if ($arg_names[$i] == 'POST') + if ($arg_names[$i] == 'POST') { $newobj["post_url"] = get_permalink($newobj["ID"]); - + + $meta = get_post_meta($newobj["ID"], '', true); + $newobj = array_merge($meta, $newobj); + } + if (wp_is_post_revision($arg)) { $parent = get_post(wp_is_post_revision($arg)); foreach ($parent as $key => $val) { @@ -281,7 +304,7 @@ function hookpress_generic_action($id,$args) { } $newobj["parent_post_url"] = get_permalink($newobj["parent_ID"]); } - + break; case 'COMMENT': $arg = (int) $arg; @@ -302,20 +325,20 @@ function hookpress_generic_action($id,$args) { case 'USER_OBJ': $newobj = (array) $arg; case 'OLD_USER_OBJ': - $newobj = array_map(create_function('$x','return "old_$x";'), (array) $arg); + $newobj = array_map(function ($x) { return "old_$x"; }, (array) $arg); default: $newobj[$arg_names[$i]] = $arg; } $obj = array_merge($obj,$newobj); } - + // take only the fields we care about $obj_to_post = array_intersect_key($obj,array_flip($desc['fields'])); $obj_to_post['hook'] = $desc['hook']; - + $user_agent = "HookPress/{$hookpress_version} (compatible; WordPress {$wp_version}; +http://mitcho.com/code/hookpress/)"; - + $request = apply_filters( 'hookpress_request', array('user-agent' => $user_agent, 'body' => $obj_to_post, 'referer' => get_bloginfo('url')) ); - + return wp_remote_post($desc['url'], $request); } diff --git a/readme.txt b/readme.md similarity index 87% rename from readme.txt rename to readme.md index 110dc8d..54e5be7 100644 --- a/readme.txt +++ b/readme.md @@ -1,5 +1,6 @@ -=== HookPress === -Contributors: mitchoyoshitaka, automattic +# HookPress + +Contributors: mitchoyoshitaka, automattic, kollegorna Author: mitcho (Michael Yoshitaka Erlewine) Author URI: http://mitcho.com/ Plugin URI: http://mitcho.com/code/ @@ -7,11 +8,11 @@ Donate link: http://tinyurl.com/donatetomitcho Tags: hook, filter, action, plugin, webhook, webhooks, notification, internal Requires at least: 3.6 Tested up to: 4.1 -Stable tag: 1.14 +Stable tag: 1.16 HookPress turns your WordPress-internal hooks into webhooks. Possible uses include generating push notifications or extending WordPress with non-PHP. -== Description == +## Description Webhooks are a simple paradigm for developing instant notifications and mashups based on simple HTTP requests. With HookPress you can set up webhooks so that a specified URL (a public service or something you set up) is requested when certain WordPress actions occur. Possible uses include generating push notifications or using non-PHP web technology to extend WordPress. @@ -26,74 +27,106 @@ A tutorial video is available [on WordPress.tv](http://wordpress.tv/2009/09/13/i **To write and host a target script** The easiest option is to set up a script on your own server to catch POST requests and act on them. [Requestbin](http://requestb.in/) is a nice, free service which will host an endpoint, collect all requests, and let you inspect them, which is a great way to test requests generated by your webhooks. There is also a PHP script which does a simple version of this, `test.php`, included with HookPress. -== Installation == +## Installation Upload the HookPress plugin to your blog's `wp-content/plugins/` directory and activate. In the admin section, go to Settings > Webhooks to add new webhooks. -== Frequently Asked Questions == +## Frequently Asked Questions If you have a feature request or question, please use the [HookPress support forum](http://wordpress.org/tags/hookpress). -= How does HookPress affect performance? = +### How does HookPress affect performance? HookPress currently makes requests synchronously so can measurably affect performance. I highly recommend using a caching plugin such as [WP-SuperCache](http://ocaoimh.ie/wp-super-cache/) to stem the performance hit. If your filters' results are time-sensitive or dependent on external data sources as well, make sure to set an appropriate cache expiration time. -== Changelog == +## Changelog ## + +### 1.16 + +* Added support for PHP 7. + +### 1.15 + +* Added custom fields to post related hooks. +* Added hooks around action handlers to allow addition of hooks from an external plugin. + +### 1.14 -= 1.14 = * Additional security hardening for `test.php`, now no longer bundled as a `.php` -= 1.13 = +### 1.13 + * Important security fix to the test endpoint, `test.php`. * Code cleanup, fix bugs introduced in previous version. -= 1.12 = +### 1.12 + * Upgraded to work properly with jQuery 1.9+. [Props liquidgecha](https://github.com/mitcho/hookpress/commit/0b21dfec8136d51971a21fb6cbdd4ff2b8d60753). * Dropped the initial 0. in the version number, as that was just ridiculous. :) -= 0.1.11 = +### 0.1.11 + * Fix to register the right number of incoming arguments for actions. -= 0.1.10 = + +### 0.1.10 + * No longer depends on the Snoopy library; uses `wp_remote_post()` instead. Note that the HTTP referer may no longer be sent correctly. * Added the `hookpress_request` filter. * Code cleanup -= 0.1.9 = + +### 0.1.9 + * New snazzy options screen, with [help from Automattic](http://en.blog.wordpress.com/2010/04/14/hook-line-and-sinker/) - * added webhook editing + * added webhook editing * Various miscellaneous features: added nonces for security, modularized the code a bit, etc. -= 0.1.8 = -* Added more filtersÑnow covers basic + comment filters + +### 0.1.8 + +* Added more filters: now covers basic + comment filters * Marking as compatible through 2.9.9, because it should be. * Added version checking and beta offers to the options screen. -= 0.1.7 = + +### 0.1.7 + * Now supports basically all actions. (Still no actions with no arguments.) -* Added more filter optionsÑnow covers all basic database read filters. -= 0.1.6 = +* Added more filter options: now covers all basic database read filters. + +### 0.1.6 + * Added another batch of actions. (Still no actions with no arguments, though... something to consider.) * Fixed hooks which referred to the users and links tables. -= 0.1.5 = + +### 0.1.5 + * Now enforces sending the first field in filters and highlights the first field. * Added FAQ note on performance concerns and caching. -= 0.1.4 = + +### 0.1.4 + * Bugfix: hooks with ID 0 can now be deleted * Made HookPress fully localizable - please email before you start localizing to claim your language. -= 0.1.3 = + +### 0.1.3 + * A small bugfix to the filters list for `save_pre` * Initial support for filters with an short list of supported filters * Updated `test.php` to return first parameter (to trivially support filters) -= 0.1.2 = + +### 0.1.2 * Added support for the `post_url` field * Added support for `parent_*` post fields for `save_post` which are sent in case the post is a revision of a previous draft. * Fixes a PHP error which displayed on install * Disallowed redirects on the webhook - corrects duplicate records when used with PostBin -= 0.1.1 = + +### 0.1.1 * Fixed namespace collision with [Yet Another Related Posts Plugin](http://mitcho.com/code/yarpp/). * Minor documentation changes. -= 0.1 = + +### 0.1 * Initial release - * supports webhooks based on WP actions + * supports webhooks based on WP actions -= Future plans = +## Future plans * Editing webhooks (rather than deleting and adding) * More custmization on a per-webhook basis diff --git a/services.php b/services.php index 8f6b9c0..deef967 100644 --- a/services.php +++ b/services.php @@ -2,15 +2,17 @@ function hookpress_ajax_get_fields() { global $wpdb, $hookpress_actions, $hookpress_filters; - if ($_POST['type'] == 'action') - $args = $hookpress_actions[$_POST['hook']]; + if ($_POST['type'] == 'action') { + $hooks = apply_filters( 'hookpress_actions', $hookpress_actions ); + $args = $hooks[$_POST['hook']]; + } if ($_POST['type'] == 'filter') $args = $hookpress_filters[$_POST['hook']]; $fields = array(); if (is_array($args)) { foreach ($args as $arg) { - if (ereg('[A-Z]+',$arg)) + if (preg_match('[A-Z]+',$arg)) $fields = array_merge($fields,hookpress_get_fields($arg)); else $fields[] = $arg; @@ -46,7 +48,7 @@ function hookpress_ajax_add_fields() { 'type'=>$_POST['type'], 'hook'=>$_POST['hook'], 'enabled'=>$_POST['enabled'], - 'fields'=>split(',',$_POST['fields']) + 'fields'=>explode(',',$_POST['fields']) ); hookpress_update_hook( $id, $edithook ); @@ -57,7 +59,7 @@ function hookpress_ajax_add_fields() { 'url'=>$_POST['url'], 'type'=>$_POST['type'], 'hook'=>$_POST['hook'], - 'fields'=>split(',',$_POST['fields']), + 'fields'=>explode(',',$_POST['fields']), 'enabled'=>true ); $id = hookpress_add_hook($newhook); @@ -119,8 +121,10 @@ function hookpress_ajax_edit_hook( $id ) { function hookpress_ajax_get_hooks() { global $wpdb, $hookpress_actions, $hookpress_filters; - if ($_POST['type'] == 'action') - $hooks = array_keys($hookpress_actions); + if ($_POST['type'] == 'action') { + $hooks = apply_filters( 'hookpress_actions', $hookpress_actions ); + $hooks = array_keys($hooks); + } if ($_POST['type'] == 'filter') $hooks = array_keys($hookpress_filters);