Skip to content

Instantly share code, notes, and snippets.

@lightningspirit
Last active April 21, 2024 08:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lightningspirit/7a4e5abd77b5b63b3409086f1ac6aa55 to your computer and use it in GitHub Desktop.
Save lightningspirit/7a4e5abd77b5b63b3409086f1ac6aa55 to your computer and use it in GitHub Desktop.
Intercepts WordPress posts and terms changes and pings an external service

WordPress Ping Updates

This plugin intercepts WordPress posts and terms changes and pings an external service.

Usage

  1. Download this ZIP
  2. Add define('PING_UPDATES_URL', 'https://my-service.com/api'); to wp-config.php or ping_updates_url option in wp_options
  3. Optionally, add define('ENABLE_PING_UPDATES_ON_TERMS_POSTS', true); if you want to ping each associated post when a term is changed
  4. Add an option ping_updates_authz_token in wp_options where the value is the token to include in the Authorization header
  5. Upload to plugins of your WordPress
<?php
/**
* Plugin Name: Ping Updates
* Plugin URI: https://gist.github.com/lightningspirit/7a4e5abd77b5b63b3409086f1ac6aa55
* Description: Intercepts posts and terms changes and pings an external service
* Author: Move Your Digital, Inc.
* Author URI: https://moveyourdigital.com
* Version: 0.2.0
* License: GPLv2
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Update URI: https://gist.githubusercontent.com/lightningspirit/7a4e5abd77b5b63b3409086f1ac6aa55/raw/wp-update-info.json
* Text Domain: email-logs
* Domain Path: /languages
*
* @package Post_Updates
*/
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Load plugin translations and post type
*
* @since 0.1.0
*/
add_action(
'plugins_loaded',
function () {
include __DIR__ . '/updater.php';
}
);
/**
* Filters this plugin data
*
* @since 0.3.2
*/
add_filter(
'plugin_basename_file_' . plugin_basename( __DIR__ ),
function () {
return plugin_basename( __FILE__ );
}
);
/**
* @var $name
* @var $body
*/
function api_send_event(string $name, array $body = [])
{
$url = defined('PING_UPDATES_URL') ? constant('PING_UPDATES_URL') : get_option('ping_updates_url', home_url());
$token = get_option('ping_updates_authz_token');
$result = wp_remote_post($url, [
'method' => 'POST',
'timeout' => 30,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => $token,
],
'data_format' => 'body',
'body' => wp_json_encode(array_merge([
'name' => $name,
], $body)),
]);
if (is_wp_error($result)) {
error_log($result->get_error_message(), 0);
}
return $result;
}
/**
* Sends event of post update
*/
add_action("post_updated", function (int $post_id, \WP_Post $post) {
api_send_event("post_updated", [
"ID" => $post_id,
"uri" => wp_make_link_relative(get_permalink($post_id)),
"type" => $post->post_type,
]);
}, 10, 3);
/**
* Sends event of post delete
*/
add_action("delete_post", function (int $post_id, \WP_Post $post) {
api_send_event("post_deleted", [
"ID" => $post_id,
"uri" => wp_make_link_relative(get_permalink($post_id)),
"type" => $post->post_type,
]);
}, 10, 2);
/**
* Sends event of term saved
*/
add_action("saved_term", function (int $term_id, int $taxonomy_id, string $taxonomy) {
$term_url = get_term_link($term_id, $taxonomy);
api_send_event("term_updated", [
"ID" => $term_id,
"uri" => wp_make_link_relative($term_url),
"type" => $taxonomy,
]);
}, 10, 3);
/**
* Sends event of term deleted
* Also, optionally ping for all associated posts
*/
add_action("delete_term", function (int $term_id, int $tax_id, string $taxonomy, WP_Term $term, array $object_ids) {
$term_url = get_term_link($term, $taxonomy);
api_send_event("term_deleted", [
"ID" => $term_id,
"uri" => wp_make_link_relative($term_url),
"type" => $taxonomy,
]);
$ping_associated_posts = defined('ENABLE_PING_UPDATES_ON_TERMS_POSTS')
? !!constant('ENABLE_PING_UPDATES_ON_TERMS_POSTS')
: false;
if ($ping_associated_posts) {
$posts = get_posts([
'post__in' => $object_ids
]);
foreach ($posts as $post) {
api_send_event("post_updated", [
"ID" => $post->ID,
"uri" => wp_make_link_relative(get_permalink($post->ID)),
"type" => $post->post_type,
]);
}
}
}, 10, 5);
<?php
/**
* Hook plugin updater from git repository
*
* @package email-logs
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Gets and updates plugin Update URI
*
* @since 0.3.5
*/
add_filter(
'plugin_update_uri_' . plugin_basename( __DIR__ ),
function ( $delete = false ) {
if ( true === $delete ) {
delete_option( 'plugin_update_uri_' . plugin_basename( __DIR__ ) );
}
$update_uri = get_option( 'plugin_update_uri_' . plugin_basename( __DIR__ ) );
if ( ! $update_uri ) {
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$basename_file = apply_filters( 'plugin_basename_file_' . plugin_basename( __DIR__ ), '' );
$plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $basename_file );
$update_uri = $plugin_data['UpdateURI'];
update_option( 'plugin_update_uri_' . plugin_basename( __DIR__ ), $update_uri );
}
return $update_uri;
}
);
/**
* Fetch and return plugin data from declared remote
*
* @since 0.3.2
*
* @param false|object|array $default_result default data to return if fetch fails
*/
add_filter(
'plugin_update_remote_data_' . plugin_basename( __DIR__ ),
function ( $default_result = '' ) {
$remote_data = wp_remote_get(
apply_filters( 'plugin_update_uri_' . plugin_basename( __DIR__ ), null ),
array(
'timeout' => 10,
'headers' => array(
'Accept' => 'application/json',
),
)
);
if ( is_wp_error( $remote_data )
|| 200 !== wp_remote_retrieve_response_code( $remote_data )
|| empty( wp_remote_retrieve_body( $remote_data ) ) ) {
return $default_result;
}
return json_decode( wp_remote_retrieve_body( $remote_data ) );
}
);
/**
* Filters the response for the current WordPress.org Plugin Installation API request.
*
* Returning a non-false value will effectively short-circuit the WordPress.org API request.
*
* If `$action` is 'query_plugins' or 'plugin_information', an object MUST be passed.
* If `$action` is 'hot_tags' or 'hot_categories', an array should be passed.
*
* @since 2.7.0
*
* @param false|object|array $result The result object or array. Default false.
* @param string $action The type of information being requested from the Plugin Installation API.
* @param object $args Plugin API arguments.
*/
add_filter(
'plugins_api',
function ( $result, $action, $args ) {
if ( 'plugin_information' !== $action ) {
return $result;
}
if ( plugin_basename( __DIR__ ) !== $args->slug ) {
return $result;
}
$result = apply_filters( 'plugin_update_remote_data_' . plugin_basename( __DIR__ ), $result );
$result->slug = plugin_basename( __DIR__ );
$result->trunk = $result->download_url;
$result->sections = array(
'description' => $result->sections->description,
'installation' => $result->sections->installation,
);
$result->banners = array(
'low' => $result->banners->low,
'high' => $result->banners->high,
);
return $result;
},
20,
3
);
/**
* Fires once activated plugins have loaded.
*
* Pluggable functions are also available at this point in the loading order.
*
* @since 1.5.0
*/
add_action(
'init',
function () {
$update_uri = apply_filters( 'plugin_update_uri_' . plugin_basename( __DIR__ ), null );
$hostname = wp_parse_url( sanitize_url( $update_uri ), PHP_URL_HOST );
add_filter(
'update_plugins_' . $hostname,
function ( $update, $plugin_data, $plugin_file ) {
$basename_file = apply_filters( 'plugin_basename_file_' . plugin_basename( __DIR__ ), '' );
if ( $plugin_file !== $basename_file ) {
return $update;
}
if ( ! empty( $update ) ) {
return $update;
}
$remote_data = apply_filters( 'plugin_update_remote_data_' . plugin_basename( __DIR__ ), $update );
if ( ! $remote_data ) {
return $update;
}
if ( version_compare( $remote_data->version, $plugin_data['Version'], '<=' ) ) {
return $update;
}
if ( version_compare( get_bloginfo( 'version' ), $remote_data->requires, '<' ) ) {
return $update;
}
if ( version_compare( PHP_VERSION, $remote_data->requires_php, '<' ) ) {
return $update;
}
return array(
'slug' => plugin_basename( __DIR__ ),
'version' => $remote_data->version,
'url' => $plugin_data['PluginURI'],
'package' => $remote_data->download_url,
);
},
10,
4
);
}
);
/**
* Fires when the upgrader process is complete.
*
* See also {@see 'upgrader_package_options'}.
*
* @since 3.6.0
* @since 3.7.0 Added to WP_Upgrader::run().
* @since 4.6.0 `$translations` was added as a possible argument to `$hook_extra`.
*
* @param WP_Upgrader $upgrader WP_Upgrader instance. In other contexts this might be a
* Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader instance.
* @param array $hook_extra {
* Array of bulk item update data.
*
* @type string $action Type of action. Default 'update'.
* @type string $type Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'.
* @type bool $bulk Whether the update process is a bulk update. Default true.
* @type array $plugins Array of the basename paths of the plugins' main files.
* @type array $themes The theme slugs.
* @type array $translations {
* Array of translations update data.
*
* @type string $language The locale the translation is for.
* @type string $type Type of translation. Accepts 'plugin', 'theme', or 'core'.
* @type string $slug Text domain the translation is for. The slug of a theme/plugin or
* 'default' for core translations.
* @type string $version The version of a theme, plugin, or core.
* }
* }
*/
add_action(
'upgrader_process_complete',
function ( $upgrader_object, $options ) {
$basename_file = apply_filters( 'plugin_basename_file_' . plugin_basename( __DIR__ ), '' );
if ( 'update' === $options['action'] && 'plugin' === $options['type'] ) {
foreach ( $options['plugins'] as $each_plugin ) {
if ( $each_plugin === $basename_file ) {
apply_filters( 'plugin_update_uri_' . plugin_basename( __DIR__ ), true );
}
}
}
},
10,
2
);
{
"name": "Ping Updates",
"slug": "ping-updates",
"author": "<a href='https://github.com/moveyourdigital'>Move Your Digital</a>",
"author_profile": "https://github.com/moveyourdigital",
"version": "0.2.0",
"download_url": "https://gist.github.com/lightningspirit/7a4e5abd77b5b63b3409086f1ac6aa55/archive/71ab57f4d59d23de63d156168ec6210709cbb3e6.zip",
"requires": "5.8",
"tested": "6.5.2",
"requires_php": "7.4",
"last_updated": "2024-04-21 09:35:00",
"sections": {
"description": "Intercepts posts and terms changes and pings an external service.",
"installation": "Click the <i>activate</i> button. No further configuration."
},
"banners": {
"low": "https://eu-west-1-serve-cdn.ofloop.com/wp-ping-updates-plugin/banner-772x250.jpg",
"high": "https://eu-west-1-serve-cdn.ofloop.com/wp-ping-updates-plugin/banner-1544x500.jpg"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment