*/ private static $events = array(); /** * Dedupe keys seen in this request. * * @var array */ private static $seen = array(); /** * Groups in display order. * * @return array */ public static function groups() { return array( 'core' => __( 'WordPress', 'pingpush' ), 'forms' => __( 'Forms', 'pingpush' ), 'ecommerce' => __( 'Ecommerce', 'pingpush' ), 'other' => __( 'Other', 'pingpush' ), ); } /** * Register an event. * * @param string $id Unique id (a-z, 0-9, _). * @param array $args Arguments (keys below). * - label (string): Label in settings. * - description (string): Help text. * - group (string): core|forms|ecommerce|other. * - source (string): Plugin name that provides the event. * - title (string): Default title template. * - message (string): Default message template. * - priority (int): Default priority (-2..1). * - sound (string): Default sound ('' = device default). * - enabled (bool): Enabled by default. * - placeholders (array): Placeholder names (without braces). * - options (array): Extra settings: key => [type, label, choices, default]. */ public static function register( $id, array $args ) { $id = sanitize_key( $id ); if ( '' === $id ) { return; } self::$events[ $id ] = wp_parse_args( $args, array( 'label' => $id, 'description' => '', 'group' => 'other', 'source' => '', 'title' => '{event}', 'message' => '{event}', 'priority' => 0, 'sound' => '', 'enabled' => false, 'placeholders' => array(), 'options' => array(), ) ); } /** * All events. * * @return array */ public static function all() { return self::$events; } /** * One event definition. * * @param string $id Id. * @return array|null */ public static function get( $id ) { return self::$events[ $id ] ?? null; } /** * Effective settings for an event (saved values over defaults). * * @param string $id Id. * @return array */ public static function settings_for( $id ) { $def = self::get( $id ); if ( ! $def ) { return array(); } $all = PingPush_Settings::get(); $saved = $all['events'][ $id ] ?? array(); $defaults = array( 'enabled' => $def['enabled'], 'priority' => 'default' === ( $def['priority'] ?? '' ) ? 'default' : (int) $def['priority'], 'sound' => (string) $def['sound'], 'title' => $def['title'], 'message' => $def['message'], ); foreach ( $def['options'] as $key => $opt ) { $defaults[ $key ] = $opt['default'] ?? ''; } $out = array_merge( $defaults, is_array( $saved ) ? $saved : array() ); if ( '' === trim( (string) $out['title'] ) ) { $out['title'] = $def['title']; } if ( '' === trim( (string) $out['message'] ) ) { $out['message'] = $def['message']; } return $out; } /** * Whether an event is turned on and keys exist. * * @param string $id Id. * @return bool */ public static function is_enabled( $id ) { if ( ! self::get( $id ) ) { return false; } $settings = PingPush_Settings::get(); if ( empty( $settings['token'] ) || empty( $settings['user_key'] ) ) { return false; } $event = self::settings_for( $id ); return ! empty( $event['enabled'] ); } /** * Trigger an event. * * @param string $id Event id. * @param array $data Placeholder data. 'fields' may hold form fields. * @param array $args Arguments (keys below). * - url (string): Supplementary URL. * - url_title (string): URL title. * - dedupe (string): Dedupe key; same id + key is sent once. * - dedupe_ttl (int): Seconds to remember the key across requests (0 = this request only). * - sync (bool): Send immediately instead of queueing. * @return bool Whether a notification was queued/sent. */ public static function trigger( $id, array $data = array(), array $args = array() ) { if ( ! self::is_enabled( $id ) ) { return false; } $args = wp_parse_args( $args, array( 'url' => '', 'url_title' => '', 'dedupe' => '', 'dedupe_ttl' => 120, 'sync' => false, ) ); if ( '' !== (string) $args['dedupe'] ) { $key = $id . '|' . $args['dedupe']; if ( isset( self::$seen[ $key ] ) ) { return false; } self::$seen[ $key ] = true; if ( (int) $args['dedupe_ttl'] > 0 ) { $transient = 'pingpush_dd_' . md5( $key ); if ( get_transient( $transient ) ) { return false; } set_transient( $transient, 1, (int) $args['dedupe_ttl'] ); } } $def = self::get( $id ); $event = self::settings_for( $id ); $settings = PingPush_Settings::get(); $data['event'] = $def['label']; /** * Last chance to stop a notification. * * @param bool $send Whether to send. * @param string $id Event id. * @param array $data Placeholder data. */ if ( ! apply_filters( 'pingpush_should_send', true, $id, $data ) ) { return false; } $title = PingPush_Templates::render( (string) $event['title'], $data ); $message = PingPush_Templates::render( (string) $event['message'], $data ); if ( ! empty( $settings['include_site_name'] ) ) { $site = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); $title = '' !== $site ? $site . ' – ' . $title : $title; } $priority = ( 'default' === $event['priority'] || '' === $event['priority'] ) ? $settings['default_priority'] : $event['priority']; $priority = PingPush_API::sanitize_priority( $priority ); /** Filters the title. */ $title = (string) apply_filters( 'pingpush_title', $title, $id, $data ); /** Filters the message. */ $message = (string) apply_filters( 'pingpush_message', $message, $id, $data ); /** Filters the priority: -2 (lowest), -1 (low), 0 (normal) or 1 (high). Other values become 0. */ $priority = PingPush_API::sanitize_priority( apply_filters( 'pingpush_priority', $priority, $id, $data ) ); $payload = array( 'event' => $id, 'title' => PingPush_Templates::truncate( $title, PingPush_API::MAX_TITLE ), 'message' => PingPush_Templates::truncate( $message, PingPush_API::MAX_MESSAGE ), 'priority' => $priority, 'sound' => (string) $event['sound'], 'timestamp' => time(), ); $url = esc_url_raw( (string) $args['url'] ); if ( '' !== $url && strlen( $url ) <= PingPush_API::MAX_URL ) { $payload['url'] = $url; $payload['url_title'] = PingPush_Templates::truncate( '' !== $args['url_title'] ? $args['url_title'] : __( 'Open', 'pingpush' ), PingPush_API::MAX_URL_TITLE ); } /** * Filters the full payload sent to Pushover (credentials are added at send time). * * @param array $payload Payload. * @param string $id Event id. * @param array $data Placeholder data. */ $payload = (array) apply_filters( 'pingpush_payload', $payload, $id, $data ); if ( $args['sync'] ) { PingPush_Queue::handle( $payload, PingPush_Queue::MAX_RETRIES ); } else { PingPush_Queue::push( $payload ); } return true; } }