diff --git a/includes/class-accepted-actions.php b/includes/class-accepted-actions.php index 5e96ac61..bf4071d8 100644 --- a/includes/class-accepted-actions.php +++ b/includes/class-accepted-actions.php @@ -37,6 +37,7 @@ class Accepted_Actions { 'network_user_updated' => 'User_Updated', 'newspack_network_woo_membership_updated' => 'Woocommerce_Membership_Updated', 'network_manual_sync_user' => 'User_Manually_Synced', + 'network_nodes_synced' => 'Nodes_Synced', ]; /** @@ -54,5 +55,6 @@ class Accepted_Actions { 'network_user_updated', 'newspack_network_woo_membership_updated', 'network_manual_sync_user', + 'network_nodes_synced', ]; } diff --git a/includes/class-data-listeners.php b/includes/class-data-listeners.php index 319f1b1f..6468c612 100644 --- a/includes/class-data-listeners.php +++ b/includes/class-data-listeners.php @@ -36,6 +36,7 @@ public static function register_listeners() { Data_Events::register_listener( 'woocommerce_subscription_status_changed', 'newspack_node_subscription_changed', [ __CLASS__, 'item_changed' ] ); Data_Events::register_listener( 'woocommerce_order_status_changed', 'newspack_node_order_changed', [ __CLASS__, 'item_changed' ] ); Data_Events::register_listener( 'newspack_network_user_updated', 'network_user_updated', [ __CLASS__, 'user_updated' ] ); + Data_Events::register_listener( 'newspack_network_nodes_synced', 'network_nodes_synced', [ __CLASS__, 'nodes_synced' ] ); } /** @@ -85,4 +86,14 @@ public static function item_changed( $item_id, $status_from, $status_to, $item ) public static function user_updated( $user_data ) { return $user_data; } + + /** + * Filters the nodes data for the event being triggered + * + * @param array $nodes_data The nodes data. + * @return array + */ + public static function nodes_synced( $nodes_data ) { + return [ 'nodes_data' => $nodes_data ]; + } } diff --git a/includes/hub/class-node.php b/includes/hub/class-node.php index 8d7dc316..98eff433 100644 --- a/includes/hub/class-node.php +++ b/includes/hub/class-node.php @@ -15,6 +15,10 @@ * Class to represent one Node of the netowrk */ class Node { + /** + * HUB_NODES_SYNCED_OPTION for network nodes. + */ + const HUB_NODES_SYNCED_OPTION = 'newspack_hub_nodes_synced'; /** * The WP_Post object for this Node @@ -116,13 +120,13 @@ public function get_connect_link() { } /** - * Gets a collection of bookmarks for this Node + * Generates a collection of bookmarks for this Node * + * @param string $url The URL of the Node. * @return array */ - public function get_bookmarks() { - - $base_url = trailingslashit( $this->get_url() ); + public static function generate_bookmarks( $url ) { + $base_url = trailingslashit( $url ); return [ [ @@ -155,4 +159,15 @@ public function get_bookmarks() { ], ]; } + + /** + * Gets a collection of bookmarks for this Node. + * + * @return array + */ + public function get_bookmarks() { + $base_url = $this->get_url(); + + return self::generate_bookmarks( $base_url ); + } } diff --git a/includes/hub/class-nodes.php b/includes/hub/class-nodes.php index 6c84dce5..d04eccf0 100644 --- a/includes/hub/class-nodes.php +++ b/includes/hub/class-nodes.php @@ -14,7 +14,6 @@ * Class to handle Nodes post type */ class Nodes { - /** * POST_TYPE_SLUG for the Nodes. */ @@ -28,6 +27,11 @@ class Nodes { public static function init() { add_action( 'init', [ __CLASS__, 'register_post_type' ] ); add_action( 'save_post', [ __CLASS__, 'save_post' ] ); + add_action( 'trashed_post', [ __CLASS__, 'trashed_node' ] ); + add_action( 'untrashed_post', [ __CLASS__, 'untrashed_node' ] ); + add_action( 'newspack_network_node_saved', [ __CLASS__, 'sync_nodes' ] ); + add_action( 'newspack_network_node_trashed', [ __CLASS__, 'sync_nodes' ] ); + add_action( 'newspack_network_node_untrashed', [ __CLASS__, 'sync_nodes' ] ); } /** @@ -98,7 +102,6 @@ public static function filter_editor_settings( $settings, $editor_id ) { * @return void */ public static function register_post_type() { - $labels = array( 'name' => _x( 'Nodes', 'Post Type General Name', 'newspack-network' ), 'singular_name' => _x( 'Node', 'Post Type Singular Name', 'newspack-network' ), @@ -272,4 +275,67 @@ public static function save_post( $post_id ) { */ do_action( 'newspack_network_node_saved', $post_id ); } + + /** + * Trashed post callback + * + * @param int $post_id The ID of the post being trashed. + * @return void + */ + public static function trashed_node( $post_id ) { + if ( self::POST_TYPE_SLUG !== get_post_type( $post_id ) ) { + return; + } + + /** + * Fires an action when a node is successfully trashed in the Hub admin + * + * @param int $post_id The ID of the node post. + */ + do_action( 'newspack_network_node_trashed', $post_id ); + } + + /** + * Untrashed post callback + * + * @param int $post_id The ID of the post being untrashed. + * @return void + */ + public static function untrashed_node( $post_id ) { + if ( self::POST_TYPE_SLUG !== get_post_type( $post_id ) ) { + return; + } + + /** + * Fires an action when a node is successfully untrashed in the Hub admin + * + * @param int $post_id The ID of the node post. + */ + do_action( 'newspack_network_node_untrashed', $post_id ); + } + + /** + * Sync nodes data to all nodes in network. + * + * @param int $post_id The ID of the post being saved. + * @return void + */ + public static function sync_nodes( $post_id ) { + $nodes = self::get_all_nodes(); + + if ( empty( $nodes ) ) { + return; + } + + $nodes_data = []; + foreach ( $nodes as $node ) { + $nodes_data[] = [ + 'id' => $node->get_id(), + 'title' => $node->get_name(), + 'url' => $node->get_url(), + ]; + } + + do_action( 'newspack_network_nodes_synced', $nodes_data ); + } } diff --git a/includes/hub/stores/event-log-items/class-nodes-synced.php b/includes/hub/stores/event-log-items/class-nodes-synced.php new file mode 100644 index 00000000..baefa0d6 --- /dev/null +++ b/includes/hub/stores/event-log-items/class-nodes-synced.php @@ -0,0 +1,25 @@ +get_data(); + + // If the data is empty, return early. + if ( empty( $data ) ) { + Debugger::log( 'No data passed for network_nodes_synced event.' ); + return; + } + + $nodes_data = $data->nodes_data; + + // If the nodes data is empty, return early. + if ( empty( $nodes_data ) ) { + Debugger::log( 'No nodes data passed for network_nodes_synced event.' ); + return; + } + + foreach ( $nodes_data as $key => $node ) { + // We don't need top store data for the current node. + if ( $node['url'] === get_site_url() ) { + unset( $nodes_data[ $key ] ); + } + } + + $updated = update_option( Node::HUB_NODES_SYNCED_OPTION, $nodes_data ); + + if ( $updated ) { + Debugger::log( 'network_nodes_synced event processed. Synced ' . count( $nodes_data ) . ' nodes.' ); + } else { + Debugger::log( 'Error processing network_nodes_synced event.' ); + } + } +} diff --git a/includes/node/class-settings.php b/includes/node/class-settings.php index 4e0e1532..46edb0ad 100644 --- a/includes/node/class-settings.php +++ b/includes/node/class-settings.php @@ -9,6 +9,8 @@ use Newspack_Network\Admin; use Newspack_Network\Crypto; +use Newspack_Network\Hub\Node as Hub_Node; +use Newspack_Network\Hub\Nodes as Hub_Nodes; use WP_Error; /** @@ -48,6 +50,7 @@ public static function init() { add_action( 'admin_menu', [ __CLASS__, 'add_menu' ] ); add_filter( 'allowed_options', [ __CLASS__, 'allowed_options' ] ); add_action( 'admin_init', [ __CLASS__, 'process_connection_form' ] ); + add_action( 'admin_bar_menu', [ __CLASS__, 'admin_bar_menu' ], 100 ); } /** @@ -542,7 +545,7 @@ public static function notice_connection_success() {
@@ -564,4 +567,42 @@ public static function notice_connection_error() {
0, + 'url' => self::get_hub_url(), + 'title' => __( 'Hub', 'newspack-network' ), + ]; + + foreach ( $nodes_data as $node ) { + $item_id = 'node-' . $node['id']; + $wp_admin_bar->add_node( + [ + 'id' => $item_id, + 'title' => $node['title'], + 'href' => $node['url'], + 'parent' => 'site-name', + ] + ); + + foreach ( Hub_Node::generate_bookmarks( $node['url'] ) as $bookmark ) { + $wp_admin_bar->add_node( + [ + 'id' => $item_id . '-' . sanitize_title( $bookmark['label'] ), + 'title' => $bookmark['label'], + 'href' => $bookmark['url'], + 'parent' => $item_id, + ] + ); + } + } + } }