Plugin Directory

Changeset 1871614


Ignore:
Timestamp:
05/09/2018 04:11:42 PM (8 years ago)
Author:
pressshack
Message:

Releasing 1.12.1

Location:
publishpress/trunk
Files:
2 deleted
8 edited

Legend:

Unmodified
Added
Removed
  • publishpress/trunk/includes.php

    r1860640 r1871614  
    4141
    4242    // Define contants
    43     define('PUBLISHPRESS_VERSION', '1.12.0');
     43    define('PUBLISHPRESS_VERSION', '1.12.1');
    4444    define('PUBLISHPRESS_BASE_PATH', __DIR__);
    4545    define('PUBLISHPRESS_FILE_PATH', PUBLISHPRESS_BASE_PATH . '/' . basename(__FILE__));
  • publishpress/trunk/libraries/Notifications/Traits/Dependency_Injector.php

    r1860640 r1871614  
    1717     * Instance of the Pimple container
    1818     */
    19     protected $pimple_container;
     19    protected $container;
    2020
    2121    /**
     
    3131    public function get_service($service_name)
    3232    {
    33         if (empty($this->pimple_container))
     33        if (empty($this->container))
    3434        {
    3535            $this->init_pimple();
    3636        }
    3737
    38         if (!isset($this->pimple_container[$service_name]))
     38        if (!isset($this->container[$service_name]))
    3939        {
    4040            throw new \Exception("Service \"{$service_name}\" not found in the container");
    4141        }
    4242
    43         return $this->pimple_container[$service_name];
     43        return $this->container[$service_name];
    4444    }
    4545
    4646    protected function init_pimple()
    4747    {
    48         $this->pimple_container = Pimple_Container::get_instance();
     48        $this->container = Pimple_Container::get_instance();
    4949    }
    5050}
  • publishpress/trunk/modules/async-notifications/async-notifications.php

    r1860640 r1871614  
    3333use PublishPress\Notifications\Traits\PublishPress_Module;
    3434
    35 if (!class_exists('PP_Async_Notifications'))
    36 {
    37     /**
    38      * class PP_Async_Notifications. Depends on the Improved Notifications module.
    39      */
    40     class PP_Async_Notifications extends PP_Module
    41     {
    42         use Dependency_Injector, PublishPress_Module;
    43 
    44         const SETTINGS_SLUG = 'pp-async-notifications-settings';
    45 
    46         const POST_STATUS_QUEUED = 'queued';
    47 
    48         const POST_STATUS_SENT = 'sent';
    49 
    50         const POST_STATUS_FAILED = 'failed';
    51 
    52         public $module_name = 'async-notifications';
    53 
    54         public $module_url;
    55 
    56         /**
    57          * Instace for the module
    58          *
    59          * @var stdClass
    60          */
    61         public $module;
    62 
    63         /**
    64          * Construct the Notifications class
    65          */
    66         public function __construct()
    67         {
    68             global $publishpress;
    69 
    70             $this->twigPath = dirname(dirname(dirname(__FILE__))) . '/twig';
    71 
    72             $this->module_url = $this->get_module_url(__FILE__);
    73 
    74             // Register the module with PublishPress
    75             $args = [
    76                 'title'                => __('Async Notifications', 'publishpress'),
    77                 'short_description'    => false,
    78                 'extended_description' => false,
    79                 'module_url'           => $this->module_url,
    80                 'icon_class'           => 'dashicons dashicons-feedback',
    81                 'slug'                 => 'async-notifications',
    82                 'default_options'      => [
    83                     'enabled' => 'on',
    84                 ],
    85                 'options_page'         => false,
    86             ];
    87 
    88             // Apply a filter to the default options
    89             $args['default_options'] = apply_filters('publishpress_async_notif_default_options', $args['default_options']);
    90             $this->module            = $publishpress->register_module(
    91                 PublishPress\Legacy\Util::sanitize_module_name($this->module_name),
    92                 $args
    93             );
    94 
    95             Auto_loader::register('\\PublishPress\\AsyncNotifications\\', __DIR__ . '/library');
    96 
    97             parent::__construct();
    98         }
    99 
    100         /**
    101          * Initialize the module. Conditionally loads if the module is enabled
    102          *
    103          * @throws Exception
    104          */
    105         public function init()
    106         {
    107             add_filter('publishpress_notif_workflow_run_action', [$this, 'filter_workflow_run_action'], 10, 3);
    108 
    109             add_action('publishpress_notif_queue', [$this, 'action_notif_queue'], 10, 5);
    110 
    111             add_action('publishpress_cron_notify', [$this, 'action_cron_notify'], 10, 8);
    112         }
    113 
    114         /**
    115          * Load default editorial metadata the first time the module is loaded
    116          *
    117          * @since 0.7
    118          */
    119         public function install()
    120         {
    121         }
    122 
    123         /**
    124          * Upgrade our data in case we need to
    125          *
    126          * @since 0.7
    127          */
    128         public function upgrade($previous_version)
    129         {
    130         }
    131 
    132         /**
    133          * @param string                               $action
    134          * @param PublishPress\Notifications\Workflow\ $workflow
    135          * @param string                               $channel
    136          *
    137          * @return string
    138          */
    139         public function filter_workflow_run_action($action, $workflow, $channel)
    140         {
    141             // Change the action to send the notification to the queue, instead sending to receiver, directly.
    142             $action = 'publishpress_notif_queue';
    143 
    144             return $action;
    145         }
    146 
    147         /**
    148          * Enqueue the notification inse
    149          *
    150          * @param $workflow_post
    151          * @param $action_args
    152          * @param $receiver
    153          * @param $content
    154          * @param $channel
    155          *
    156          * @throws Exception;
    157          */
    158         public function action_notif_queue($workflow_post, $action_args, $receiver, $content, $channel)
    159         {
    160             $queue = $this->get_service('notification_queue');
    161 
    162             $queue->enqueueNotification($workflow_post, $action_args, $receiver, $content, $channel);
    163         }
    164 
    165         /**
    166          * @param $workflowPostId
    167          * @param $action
    168          * @param $postId
    169          * @param $content
    170          * @param $oldStatus
    171          * @param $newStatus
    172          * @param $channel
    173          * @param $receiver
    174          */
    175         public function action_cron_notify($workflowPostId, $action, $postId, $content, $oldStatus, $newStatus, $channel, $receiver)
    176         {
    177             $workflowPost = get_post($workflowPostId);
    178             $actionArgs   = [
    179                 'action'     => $action,
    180                 'post'       => get_post($postId),
    181                 'new_status' => $newStatus,
    182                 'old_status' => $oldStatus,
    183             ];
    184             $receivers    = [$receiver];
    185 
    186             // Decode the content
    187             $content = base64_decode(maybe_unserialize($content));
    188 
    189             /**
    190              * Triggers the notification. This can be caught by notification channels.
    191              *
    192              * @param WP_Post $workflow_post
    193              * @param array   $action_args
    194              * @param array   $receivers
    195              * @param array   $content
    196              * @param array   $channel
    197              */
    198             do_action('publishpress_notif_send_notification_' . $channel, $workflowPost, $actionArgs, $receivers, $content, $channel);
    199         }
    200     }
     35if ( ! class_exists( 'PP_Async_Notifications' ) ) {
     36    /**
     37     * class PP_Async_Notifications. Depends on the Improved Notifications module.
     38     */
     39    class PP_Async_Notifications extends PP_Module {
     40        use Dependency_Injector, PublishPress_Module;
     41
     42        const SETTINGS_SLUG = 'pp-async-notifications-settings';
     43
     44        const POST_STATUS_QUEUED = 'queued';
     45
     46        const POST_STATUS_SENT = 'sent';
     47
     48        const POST_STATUS_FAILED = 'failed';
     49
     50        const DEFAULT_DUPLICATED_NOTIFICATION_TIMEOUT = 60;
     51
     52        public $module_name = 'async-notifications';
     53
     54        public $module_url;
     55
     56        /**
     57         * Instace for the module
     58         *
     59         * @var stdClass
     60         */
     61        public $module;
     62
     63        /**
     64         * Construct the Notifications class
     65         */
     66        public function __construct() {
     67            global $publishpress;
     68
     69            $this->twigPath = dirname( dirname( dirname( __FILE__ ) ) ) . '/twig';
     70
     71            $this->module_url = $this->get_module_url( __FILE__ );
     72
     73            // Register the module with PublishPress
     74            $args = [
     75                'title'                => __( 'Async Notifications', 'publishpress' ),
     76                'short_description'    => false,
     77                'extended_description' => false,
     78                'module_url'           => $this->module_url,
     79                'icon_class'           => 'dashicons dashicons-feedback',
     80                'slug'                 => 'async-notifications',
     81                'default_options'      => [
     82                    'enabled' => 'on',
     83                ],
     84                'options_page'         => false,
     85            ];
     86
     87            // Apply a filter to the default options
     88            $args['default_options'] = apply_filters( 'publishpress_async_notif_default_options',
     89                $args['default_options'] );
     90            $this->module            = $publishpress->register_module(
     91                PublishPress\Legacy\Util::sanitize_module_name( $this->module_name ),
     92                $args
     93            );
     94
     95            Auto_loader::register( '\\PublishPress\\AsyncNotifications\\', __DIR__ . '/library' );
     96
     97            parent::__construct();
     98        }
     99
     100        /**
     101         * Initialize the module. Conditionally loads if the module is enabled
     102         *
     103         * @throws Exception
     104         */
     105        public function init() {
     106            add_filter( 'publishpress_notif_workflow_run_action', [ $this, 'filter_workflow_run_action' ], 10, 3 );
     107
     108            add_action( 'publishpress_notif_queue', [ $this, 'action_notif_queue' ], 10, 5 );
     109
     110            add_action( 'publishpress_cron_notify', [ $this, 'action_cron_notify' ], 10, 8 );
     111        }
     112
     113        /**
     114         * Load default editorial metadata the first time the module is loaded
     115         *
     116         * @since 0.7
     117         */
     118        public function install() {
     119        }
     120
     121        /**
     122         * Upgrade our data in case we need to
     123         *
     124         * @since 0.7
     125         */
     126        public function upgrade( $previous_version ) {
     127        }
     128
     129        /**
     130         * @param string                               $action
     131         * @param PublishPress\Notifications\Workflow\ $workflow
     132         * @param string                               $channel
     133         *
     134         * @return string
     135         */
     136        public function filter_workflow_run_action( $action, $workflow, $channel ) {
     137            // Change the action to send the notification to the queue, instead sending to receiver, directly.
     138            $action = 'publishpress_notif_queue';
     139
     140            return $action;
     141        }
     142
     143        /**
     144         * Enqueue the notification inse
     145         *
     146         * @param $workflow_post
     147         * @param $action_args
     148         * @param $receiver
     149         * @param $content
     150         * @param $channel
     151         *
     152         * @throws Exception;
     153         */
     154        public function action_notif_queue( $workflow_post, $action_args, $receiver, $content, $channel ) {
     155            $queue = $this->get_service( 'notification_queue' );
     156
     157            $queue->enqueueNotification( $workflow_post, $action_args, $receiver, $content, $channel );
     158        }
     159
     160        /**
     161         * Check if the notification was just sent, to avoid duplicated notifications when
     162         * multiple requests try to run the same job.
     163         *
     164         * @param $args
     165         *
     166         * @return bool
     167         */
     168        protected function is_duplicated_notification( $args ) {
     169            // Calculate unique ID to avoid repeated notifications.
     170            $uid = md5( maybe_serialize( func_get_args() ) );
     171
     172            $transientName = 'ppnotif_' . $uid;
     173
     174            // Check if we already have the transient.
     175            if ( get_transient( $transientName ) ) {
     176                // Yes, duplicated notification.
     177                return true;
     178            }
     179
     180            // No, set the flag and return as non-duplicated.
     181            set_transient( $transientName, 1, self::DEFAULT_DUPLICATED_NOTIFICATION_TIMEOUT );
     182
     183            return false;
     184        }
     185
     186        /**
     187         * @param $workflowPostId
     188         * @param $action
     189         * @param $postId
     190         * @param $content
     191         * @param $oldStatus
     192         * @param $newStatus
     193         * @param $channel
     194         * @param $receiver
     195         */
     196        public function action_cron_notify(
     197            $workflowPostId,
     198            $action,
     199            $postId,
     200            $content,
     201            $oldStatus,
     202            $newStatus,
     203            $channel,
     204            $receiver
     205        ) {
     206            // Check if this is a duplicated notification and skip it.
     207            // I hope this is a temporary fix. When scheduled, some notifications seems to be triggered multiple times
     208            // by the same cron task.
     209            if ( $this->is_duplicated_notification( func_get_args() ) ) {
     210                return;
     211            }
     212
     213            // Work the notification
     214            $workflowPost = get_post( $workflowPostId );
     215            $actionArgs   = [
     216                'action'     => $action,
     217                'post'       => get_post( $postId ),
     218                'new_status' => $newStatus,
     219                'old_status' => $oldStatus,
     220            ];
     221            $receivers    = [ $receiver ];
     222
     223            // Decode the content
     224            $content = base64_decode( maybe_unserialize( $content ) );
     225
     226            /**
     227             * Triggers the notification. This can be caught by notification channels.
     228             *
     229             * @param WP_Post $workflow_post
     230             * @param array   $action_args
     231             * @param array   $receivers
     232             * @param array   $content
     233             * @param array   $channel
     234             */
     235            do_action( 'publishpress_notif_send_notification_' . $channel, $workflowPost, $actionArgs, $receivers,
     236                $content, $channel );
     237        }
     238    }
    201239}
  • publishpress/trunk/modules/content-overview/content-overview.php

    r1860640 r1871614  
    147147        add_action('admin_init', array($this, 'handle_form_date_range_change'));
    148148
    149         include_once PUBLISHPRESS_BASE_PATH . '/common/php/' . 'screen-options.php';
    150 
    151         if (function_exists('add_screen_options_panel'))
    152         {
    153             add_screen_options_panel(
    154                 self::USERMETA_KEY_PREFIX . 'screen_columns',
    155                 __('Screen Layout', 'publishpress'),
    156                 array($this, 'print_column_prefs'),
    157                 self::SCREEN_ID,
    158                 array($this, 'save_column_prefs'),
    159                 true
    160             );
    161         }
     149        add_action('admin_init', array($this, 'handle_screen_options'));
    162150
    163151        // Register the columns of data appearing on every term. This is hooked into admin_init
     
    171159        add_action('admin_enqueue_scripts', array($this, 'action_enqueue_admin_styles'));
    172160    }
     161
     162    public function handle_screen_options() {
     163        include_once PUBLISHPRESS_BASE_PATH . '/common/php/' . 'screen-options.php';
     164
     165        if (function_exists('add_screen_options_panel'))
     166        {
     167            add_screen_options_panel(
     168                self::USERMETA_KEY_PREFIX . 'screen_columns',
     169                __('Screen Layout', 'publishpress'),
     170                array($this, 'print_column_prefs'),
     171                self::SCREEN_ID,
     172                array($this, 'save_column_prefs'),
     173                true
     174            );
     175        }
     176    }
     177
    173178
    174179    /**
     
    860865                $post_author = get_userdata($post->post_author);
    861866
    862                 return $post_author->display_name;
     867                $author_name = is_object( $post_author ) ? $post_author->display_name : '';
     868
     869                // @todo: Make this compatible with Multiple Authors
     870                $author_name = apply_filters( 'the_author', $author_name );
     871
     872                return $author_name;
    863873                break;
    864874            case 'post_date':
  • publishpress/trunk/modules/notifications/notifications.php

    r1860640 r1871614  
    2929 */
    3030
    31 if (!defined('PP_NOTIFICATION_USE_CRON'))
    32 {
    33     define('PP_NOTIFICATION_USE_CRON', false);
     31if ( ! defined( 'PP_NOTIFICATION_USE_CRON' ) ) {
     32    define( 'PP_NOTIFICATION_USE_CRON', false );
    3433}
    3534
    36 if (!class_exists('PP_Notifications'))
    37 {
    38     /**
    39      * Class PP_Notifications
    40      * Notifications for PublishPress and more
    41      */
    42     class PP_Notifications extends PP_Module
    43     {
    44 
    45         // Taxonomy name used to store users which will be notified for changes in the posts.
    46         public $notify_user_taxonomy = 'pp_notify_user';
    47 
    48         // Taxonomy name used to store roles which will be notified for changes in the posts.
    49         public $notify_role_taxonomy = 'pp_notify_role';
    50 
    51         public $module;
    52 
    53         public $edit_post_subscriptions_cap = 'edit_post_subscriptions';
    54 
    55         /**
    56          * Register the module with PublishPress but don't do anything else
    57          */
    58         public function __construct()
    59         {
    60 
    61             // Register the module with PublishPress
    62             $this->module_url = $this->get_module_url(__FILE__);
    63             $args             = array(
    64                 'title'                 => __('Default Notifications', 'publishpress'),
    65                 'short_description'     => false,
    66                 'extended_description'  => false,
    67                 'module_url'            => $this->module_url,
    68                 'icon_class'            => 'dashicons dashicons-email',
    69                 'slug'                  => 'notifications',
    70                 'default_options'       => array(
    71                     'enabled'                   => 'on',
    72                     'post_types'                => array(
    73                         'post' => 'on',
    74                         'page' => 'on',
    75                     ),
    76                     'notify_author_by_default'  => '1',
    77                     'notify_current_user_by_default' => '1',
    78                 ),
    79                 'configure_page_cb'     => 'print_configure_view',
    80                 'post_type_support'     => 'pp_notification',
    81                 'autoload'              => false,
    82                 'settings_help_tab'     => array(
    83                     'id'      => 'pp-notifications-overview',
    84                     'title'   => __('Overview', 'publishpress'),
    85                     'content' => __('<p>Notifications ensure you keep up to date with progress your most important content. Users can be subscribed to notifications on a post one by one or by selecting roles.</p><p>When enabled, notifications can be sent when a post changes status or an editorial comment is left by a writer or an editor.</p>', 'publishpress'),
    86                 ),
    87                 'settings_help_sidebar' => __('<p><strong>For more information:</strong></p><p><a href="https://publishpress.com/features/notifications/">Notifications Documentation</a></p><p><a href="https://github.com/ostraining/PublishPress">PublishPress on Github</a></p>', 'publishpress'),
    88                 'general_options'       => true,
    89             );
    90             $this->module     = PublishPress()->register_module('notifications', $args);
    91         }
    92 
    93         /**
    94          * Initialize the notifications class if the plugin is enabled
    95          */
    96         public function init()
    97         {
    98 
    99             // Register our taxonomies for managing relationships
    100             $this->register_taxonomies();
    101 
    102             // Allow users to use a different user capability for editing post subscriptions
    103             $this->edit_post_subscriptions_cap = apply_filters('pp_edit_post_subscriptions_cap', $this->edit_post_subscriptions_cap);
    104 
    105             // Set up metabox and related actions
    106             add_action('add_meta_boxes', array($this, 'add_post_meta_box'));
    107 
    108             // Saving post actions
    109             // self::save_post_subscriptions() is hooked into transition_post_status so we can ensure role data
    110             // is properly saved before sending notifs
    111             add_action('transition_post_status', array($this, 'notification_status_change'), PP_NOTIFICATION_PRIORITY_STATUS_CHANGE, 3);
    112             add_action('pp_post_insert_editorial_comment', array($this, 'notification_comment'));
    113             add_action('delete_user', array($this, 'delete_user_action'));
    114             add_action('pp_send_scheduled_notification', array($this, 'send_single_email'), 10, 4);
    115 
    116             add_action('admin_init', array($this, 'register_settings'));
    117 
    118             // Javascript and CSS if we need it
    119             add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
    120             add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles'));
    121 
    122             // Add a "Notify" link to posts
    123             if (apply_filters('pp_notifications_show_notify_link', true))
    124             {
    125                 // A little extra JS for the Notify button
    126                 add_action('admin_head', array($this, 'action_admin_head_notify_js'));
    127                 // Manage Posts
    128                 add_filter('post_row_actions', array($this, 'filter_post_row_actions'), 10, 2);
    129                 add_filter('page_row_actions', array($this, 'filter_post_row_actions'), 10, 2);
    130                 // Calendar and Content Overview
    131                 add_filter('pp_calendar_item_actions', array($this, 'filter_post_row_actions'), 10, 2);
    132                 add_filter('pp_story_budget_item_actions', array($this, 'filter_post_row_actions'), 10, 2);
    133             }
    134 
    135             add_filter('pp_notification_auto_subscribe_post_author', array($this, 'filter_pp_notification_auto_subscribe_post_author'), 10, 2);
    136             add_filter('pp_notification_auto_subscribe_current_user', array($this, 'filter_pp_notification_auto_subscribe_current_user'), 10, 2);
    137 
    138             add_action('save_post', array($this, 'action_save_post'), 10);
    139 
    140             // Ajax for saving notification updates
    141             add_action('wp_ajax_pp_notifications_user_post_subscription', array($this, 'handle_user_post_subscription'));
    142 
    143             add_action('pp_send_notification_status_update', array($this, 'send_notification_status_update'));
    144             add_action('pp_send_notification_comment', array($this, 'send_notification_comment'));
    145         }
    146 
    147         /**
    148          * Load the capabilities onto users the first time the module is run
    149          *
    150          * @since 0.7
    151          */
    152         public function install()
    153         {
    154             // Considering we could be moving from Edit Flow, we need to migrate the following users.
    155             $this->migrateLegacyFollowingTerms();
    156         }
    157 
    158         /**
    159          * Upgrade our data in case we need to
    160          *
    161          * @since 0.7
    162          */
    163         public function upgrade($previous_version)
    164         {
    165             global $publishpress;
    166 
    167             // Upgrade path to v0.7
    168             if (version_compare($previous_version, '0.7', '<'))
    169             {
    170                 // Migrate whether notifications were enabled or not
    171                 if ($enabled = get_option('publishpress_notifications_enabled'))
    172                 {
    173                     $enabled = 'on';
    174                 } else
    175                 {
    176                     $enabled = 'off';
    177                 }
    178                 $publishpress->update_module_option($this->module->name, 'enabled', $enabled);
    179                 delete_option('publishpress_notifications_enabled');
    180                 // Migrate whether to always notify the admin
    181                 // @todo: Remove after sometime. The setting always notify admin was removed.
    182                 if ($always_notify_admin = get_option('publishpress_always_notify_admin'))
    183                 {
    184                     $always_notify_admin = 'on';
    185                 } else
    186                 {
    187                     $always_notify_admin = 'off';
    188                 }
    189                 $publishpress->update_module_option($this->module->name, 'always_notify_admin', $always_notify_admin);
    190                 delete_option('publishpress_always_notify_admin');
    191 
    192                 // Technically we've run this code before so we don't want to auto-install new data
    193                 $publishpress->update_module_option($this->module->name, 'loaded_once', true);
    194             }
    195 
    196             if (version_compare($previous_version, '1.10', '<=')) {
    197                 $this->migrateLegacyFollowingTerms();
    198             }
    199         }
    200 
    201 
    202         protected function migrateLegacyFollowingTerms()
    203         {
    204             global $wpdb;
    205 
    206             // Migrate Following Users
    207             $query = "UPDATE {$wpdb->prefix}term_taxonomy SET taxonomy = '{$this->notify_user_taxonomy}' WHERE taxonomy = 'following_users'";
    208             $wpdb->query($query);
    209         }
    210 
    211         /**
    212          * Register the taxonomies we use to manage relationships
    213          *
    214          * @since 0.7
    215          *
    216          * @uses  register_taxonomy()
    217          */
    218         public function register_taxonomies()
    219         {
    220             // Load the currently supported post types so we only register against those
    221             $supported_post_types = $this->get_post_types_for_module($this->module);
    222 
    223             $args = array(
    224                 'hierarchical'          => false,
    225                 'update_count_callback' => '_update_post_term_count',
    226                 'label'                 => false,
    227                 'query_var'             => false,
    228                 'rewrite'               => false,
    229                 'public'                => false,
    230                 'show_ui'               => false,
    231             );
    232 
    233             register_taxonomy($this->notify_user_taxonomy, $supported_post_types, $args);
    234             register_taxonomy($this->notify_role_taxonomy, $supported_post_types, $args);
    235         }
    236 
    237         /**
    238          * Enqueue necessary admin scripts
    239          *
    240          * @since 0.7
    241          *
    242          * @uses  wp_enqueue_script()
    243          */
    244         public function enqueue_admin_scripts()
    245         {
    246             if ($this->is_whitelisted_functional_view())
    247             {
    248                 wp_enqueue_script(
    249                     'publishpress-notifications-js',
    250                     $this->module_url . 'assets/notifications.js',
    251                     array(
    252                         'jquery',
    253                     ),
    254                     PUBLISHPRESS_VERSION,
    255                     true
    256                 );
    257 
    258                 wp_enqueue_script('publishpress-chosen-js', PUBLISHPRESS_URL . '/common/libs/chosen/chosen.jquery.js',
    259                     ['jquery'], PUBLISHPRESS_VERSION);
    260             }
    261         }
    262 
    263         /**
    264          * Enqueue necessary admin styles, but only on the proper pages
    265          *
    266          * @since 0.7
    267          *
    268          * @uses  wp_enqueue_style()
    269          */
    270         public function enqueue_admin_styles()
    271         {
    272             if ($this->is_whitelisted_functional_view() || $this->is_whitelisted_settings_view())
    273             {
    274                 wp_enqueue_style('jquery-listfilterizer');
    275                 wp_enqueue_style(
    276                     'publishpress-notifications-css',
    277                     $this->module->module_url . 'assets/notifications.css',
    278                     false,
    279                     PUBLISHPRESS_VERSION
    280                 );
    281 
    282                 wp_enqueue_style('publishpress-chosen-css', PUBLISHPRESS_URL . '/common/libs/chosen/chosen.css', false,
    283                     PUBLISHPRESS_VERSION);
    284             }
    285         }
    286 
    287         /**
    288          * JS required for the Notify link to work
    289          *
    290          * @since 0.8
    291          */
    292         public function action_admin_head_notify_js()
    293         {
    294             ?>
     35if ( ! class_exists( 'PP_Notifications' ) ) {
     36    /**
     37     * Class PP_Notifications
     38     * Notifications for PublishPress and more
     39     */
     40    class PP_Notifications extends PP_Module {
     41
     42        // Taxonomy name used to store users which will be notified for changes in the posts.
     43        public $notify_user_taxonomy = 'pp_notify_user';
     44
     45        // Taxonomy name used to store roles which will be notified for changes in the posts.
     46        public $notify_role_taxonomy = 'pp_notify_role';
     47
     48        public $module;
     49
     50        public $edit_post_subscriptions_cap = 'edit_post_subscriptions';
     51
     52        /**
     53         * Register the module with PublishPress but don't do anything else
     54         */
     55        public function __construct() {
     56
     57            // Register the module with PublishPress
     58            $this->module_url = $this->get_module_url( __FILE__ );
     59            $args             = [
     60                'title'                 => __( 'Default Notifications', 'publishpress' ),
     61                'short_description'     => false,
     62                'extended_description'  => false,
     63                'module_url'            => $this->module_url,
     64                'icon_class'            => 'dashicons dashicons-email',
     65                'slug'                  => 'notifications',
     66                'default_options'       => [
     67                    'enabled'                        => 'on',
     68                    'post_types'                     => [
     69                        'post' => 'on',
     70                        'page' => 'on',
     71                    ],
     72                    'notify_author_by_default'       => '1',
     73                    'notify_current_user_by_default' => '1',
     74                ],
     75                'configure_page_cb'     => 'print_configure_view',
     76                'post_type_support'     => 'pp_notification',
     77                'autoload'              => false,
     78                'settings_help_tab'     => [
     79                    'id'      => 'pp-notifications-overview',
     80                    'title'   => __( 'Overview', 'publishpress' ),
     81                    'content' => __( '<p>Notifications ensure you keep up to date with progress your most important content. Users can be subscribed to notifications on a post one by one or by selecting roles.</p><p>When enabled, notifications can be sent when a post changes status or an editorial comment is left by a writer or an editor.</p>',
     82                        'publishpress' ),
     83                ],
     84                'settings_help_sidebar' => __( '<p><strong>For more information:</strong></p><p><a href="https://publishpress.com/features/notifications/">Notifications Documentation</a></p><p><a href="https://github.com/ostraining/PublishPress">PublishPress on Github</a></p>',
     85                    'publishpress' ),
     86                'general_options'       => true,
     87            ];
     88            $this->module     = PublishPress()->register_module( 'notifications', $args );
     89        }
     90
     91        /**
     92         * Initialize the notifications class if the plugin is enabled
     93         */
     94        public function init() {
     95
     96            // Register our taxonomies for managing relationships
     97            $this->register_taxonomies();
     98
     99            // Allow users to use a different user capability for editing post subscriptions
     100            $this->edit_post_subscriptions_cap = apply_filters( 'pp_edit_post_subscriptions_cap',
     101                $this->edit_post_subscriptions_cap );
     102
     103            // Set up metabox and related actions
     104            add_action( 'add_meta_boxes', [ $this, 'add_post_meta_box' ] );
     105
     106            // Saving post actions
     107            // self::save_post_subscriptions() is hooked into transition_post_status so we can ensure role data
     108            // is properly saved before sending notifs
     109            add_action( 'transition_post_status', [ $this, 'notification_status_change' ],
     110                PP_NOTIFICATION_PRIORITY_STATUS_CHANGE, 3 );
     111            add_action( 'pp_post_insert_editorial_comment', [ $this, 'notification_comment' ] );
     112            add_action( 'delete_user', [ $this, 'delete_user_action' ] );
     113            add_action( 'pp_send_scheduled_notification', [ $this, 'send_single_email' ], 10, 4 );
     114
     115            add_action( 'admin_init', [ $this, 'register_settings' ] );
     116
     117            // Javascript and CSS if we need it
     118            add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
     119            add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_styles' ] );
     120
     121            // Add a "Notify" link to posts
     122            if ( apply_filters( 'pp_notifications_show_notify_link', true ) ) {
     123                // A little extra JS for the Notify button
     124                add_action( 'admin_head', [ $this, 'action_admin_head_notify_js' ] );
     125                // Manage Posts
     126                add_filter( 'post_row_actions', [ $this, 'filter_post_row_actions' ], 10, 2 );
     127                add_filter( 'page_row_actions', [ $this, 'filter_post_row_actions' ], 10, 2 );
     128                // Calendar and Content Overview
     129                add_filter( 'pp_calendar_item_actions', [ $this, 'filter_post_row_actions' ], 10, 2 );
     130                add_filter( 'pp_story_budget_item_actions', [ $this, 'filter_post_row_actions' ], 10, 2 );
     131            }
     132
     133            add_filter( 'pp_notification_auto_subscribe_post_author',
     134                [ $this, 'filter_pp_notification_auto_subscribe_post_author' ], 10, 2 );
     135            add_filter( 'pp_notification_auto_subscribe_current_user',
     136                [ $this, 'filter_pp_notification_auto_subscribe_current_user' ], 10, 2 );
     137
     138            add_action( 'save_post', [ $this, 'action_save_post' ], 10 );
     139
     140            // Ajax for saving notification updates
     141            add_action( 'wp_ajax_pp_notifications_user_post_subscription', [ $this, 'handle_user_post_subscription' ] );
     142
     143            add_action( 'pp_send_notification_status_update', [ $this, 'send_notification_status_update' ] );
     144            add_action( 'pp_send_notification_comment', [ $this, 'send_notification_comment' ] );
     145        }
     146
     147        /**
     148         * Load the capabilities onto users the first time the module is run
     149         *
     150         * @since 0.7
     151         */
     152        public function install() {
     153            // Considering we could be moving from Edit Flow, we need to migrate the following users.
     154            $this->migrateLegacyFollowingTerms();
     155        }
     156
     157        /**
     158         * Upgrade our data in case we need to
     159         *
     160         * @since 0.7
     161         */
     162        public function upgrade( $previous_version ) {
     163            global $publishpress;
     164
     165            // Upgrade path to v0.7
     166            if ( version_compare( $previous_version, '0.7', '<' ) ) {
     167                // Migrate whether notifications were enabled or not
     168                if ( $enabled = get_option( 'publishpress_notifications_enabled' ) ) {
     169                    $enabled = 'on';
     170                } else {
     171                    $enabled = 'off';
     172                }
     173                $publishpress->update_module_option( $this->module->name, 'enabled', $enabled );
     174                delete_option( 'publishpress_notifications_enabled' );
     175                // Migrate whether to always notify the admin
     176                // @todo: Remove after sometime. The setting always notify admin was removed.
     177                if ( $always_notify_admin = get_option( 'publishpress_always_notify_admin' ) ) {
     178                    $always_notify_admin = 'on';
     179                } else {
     180                    $always_notify_admin = 'off';
     181                }
     182                $publishpress->update_module_option( $this->module->name, 'always_notify_admin', $always_notify_admin );
     183                delete_option( 'publishpress_always_notify_admin' );
     184
     185                // Technically we've run this code before so we don't want to auto-install new data
     186                $publishpress->update_module_option( $this->module->name, 'loaded_once', true );
     187            }
     188
     189            if ( version_compare( $previous_version, '1.10', '<=' ) ) {
     190                $this->migrateLegacyFollowingTerms();
     191            }
     192        }
     193
     194
     195        protected function migrateLegacyFollowingTerms() {
     196            global $wpdb;
     197
     198            // Migrate Following Users
     199            $query = "UPDATE {$wpdb->prefix}term_taxonomy SET taxonomy = '{$this->notify_user_taxonomy}' WHERE taxonomy = 'following_users'";
     200            $wpdb->query( $query );
     201        }
     202
     203        /**
     204         * Register the taxonomies we use to manage relationships
     205         *
     206         * @since 0.7
     207         *
     208         * @uses  register_taxonomy()
     209         */
     210        public function register_taxonomies() {
     211            // Load the currently supported post types so we only register against those
     212            $supported_post_types = $this->get_post_types_for_module( $this->module );
     213
     214            $args = [
     215                'hierarchical'          => false,
     216                'update_count_callback' => '_update_post_term_count',
     217                'label'                 => false,
     218                'query_var'             => false,
     219                'rewrite'               => false,
     220                'public'                => false,
     221                'show_ui'               => false,
     222            ];
     223
     224            register_taxonomy( $this->notify_user_taxonomy, $supported_post_types, $args );
     225            register_taxonomy( $this->notify_role_taxonomy, $supported_post_types, $args );
     226        }
     227
     228        /**
     229         * Enqueue necessary admin scripts
     230         *
     231         * @since 0.7
     232         *
     233         * @uses  wp_enqueue_script()
     234         */
     235        public function enqueue_admin_scripts() {
     236            if ( $this->is_whitelisted_functional_view() ) {
     237                wp_enqueue_script(
     238                    'publishpress-notifications-js',
     239                    $this->module_url . 'assets/notifications.js',
     240                    [
     241                        'jquery',
     242                    ],
     243                    PUBLISHPRESS_VERSION,
     244                    true
     245                );
     246
     247                wp_enqueue_script( 'publishpress-chosen-js', PUBLISHPRESS_URL . '/common/libs/chosen/chosen.jquery.js',
     248                    [ 'jquery' ], PUBLISHPRESS_VERSION );
     249            }
     250        }
     251
     252        /**
     253         * Enqueue necessary admin styles, but only on the proper pages
     254         *
     255         * @since 0.7
     256         *
     257         * @uses  wp_enqueue_style()
     258         */
     259        public function enqueue_admin_styles() {
     260            if ( $this->is_whitelisted_functional_view() || $this->is_whitelisted_settings_view() ) {
     261                wp_enqueue_style( 'jquery-listfilterizer' );
     262                wp_enqueue_style(
     263                    'publishpress-notifications-css',
     264                    $this->module->module_url . 'assets/notifications.css',
     265                    false,
     266                    PUBLISHPRESS_VERSION
     267                );
     268
     269                wp_enqueue_style( 'publishpress-chosen-css', PUBLISHPRESS_URL . '/common/libs/chosen/chosen.css', false,
     270                    PUBLISHPRESS_VERSION );
     271            }
     272        }
     273
     274        /**
     275         * JS required for the Notify link to work
     276         *
     277         * @since 0.8
     278         */
     279        public function action_admin_head_notify_js() {
     280            ?>
    295281            <script type='text/javascript'>
    296                 (function ($) {
    297                     $(document).ready(function ($) {
    298                         /**
    299                          * Action to Notify / Stop Notifying posts on the manage posts screen
    300                          */
    301                         $('.wp-list-table, #pp-calendar-view, #pp-story-budget-wrap').on('click', '.pp_notify_link a', function (e) {
    302 
    303                             e.preventDefault();
    304 
    305                             var link = $(this);
    306 
    307                             $.ajax({
    308                                 type: 'GET',
    309                                 url: link.attr('href'),
    310                                 success: function (data) {
    311                                     if ('success' === data.status) {
    312                                         link.attr('href', data.message.link);
    313                                         link.attr('title', data.message.title);
    314                                         link.text(data.message.text);
    315                                     }
    316                                     // @todo expose the error somehow
    317                                 }
    318                             });
    319 
    320                             return false;
    321                         });
    322                     });
    323                 })(jQuery);
     282              (function ($) {
     283                $(document).ready(function ($) {
     284                  /**
     285                   * Action to Notify / Stop Notifying posts on the manage posts screen
     286                   */
     287                  $('.wp-list-table, #pp-calendar-view, #pp-story-budget-wrap').on('click', '.pp_notify_link a', function (e) {
     288
     289                    e.preventDefault()
     290
     291                    var link = $(this)
     292
     293                    $.ajax({
     294                      type: 'GET',
     295                      url: link.attr('href'),
     296                      success: function (data) {
     297                        if ('success' === data.status) {
     298                          link.attr('href', data.message.link)
     299                          link.attr('title', data.message.title)
     300                          link.text(data.message.text)
     301                        }
     302                        // @todo expose the error somehow
     303                      }
     304                    })
     305
     306                    return false
     307                  })
     308                })
     309              })(jQuery)
    324310            </script>
    325             <?php
    326         }
    327 
    328         /**
    329          * Add a "Notify" link to supported post types Manage Posts view
    330          *
    331          * @since 0.8
    332          *
    333          * @param array      $actions Any existing item actions
    334          * @param int|object $post    Post id or object
    335          * @return array     $actions   The follow link has been appended
    336          */
    337         public function filter_post_row_actions($actions, $post)
    338         {
    339             $post = get_post($post);
    340 
    341             if (!in_array($post->post_type, $this->get_post_types_for_module($this->module)))
    342             {
    343                 return $actions;
    344             }
    345 
    346             if (!current_user_can($this->edit_post_subscriptions_cap) || !current_user_can('edit_post', $post->ID))
    347             {
    348                 return $actions;
    349             }
    350 
    351             $parts                     = $this->get_notify_action_parts($post);
    352             $actions['pp_notify_link'] = '<a title="' . esc_attr($parts['title']) . '" href="' . esc_url($parts['link']) . '">' . $parts['text'] . '</a>';
    353 
    354             return $actions;
    355         }
    356 
    357         /**
    358          * Get an action parts for a user to set Notify or Stop Notify for a post
    359          *
    360          * @since 0.8
    361          */
    362         private function get_notify_action_parts($post)
    363         {
    364             $args = array(
    365                 'action'  => 'pp_notifications_user_post_subscription',
    366                 'post_id' => $post->ID,
    367             );
    368 
    369             $user_to_notify = $this->get_users_to_notify($post->ID);
    370 
    371             if (in_array(wp_get_current_user()->user_login, $user_to_notify))
    372             {
    373                 $args['method'] = 'stop_notifying';
    374                 $title_text     = __('Click to stop being notified on updates for this post', 'publishpress');
    375                 $link_text      = __('Stop notifying me', 'publishpress');
    376             } else
    377             {
    378                 $args['method'] = 'start_notifying';
    379                 $title_text     = __('Click to start being notified on updates for this post', 'publishpress');
    380                 $link_text      = __('Notify me', 'publishpress');
    381             }
    382 
    383             // wp_nonce_url() has encoding issues: http://core.trac.wordpress.org/ticket/20771
    384             $args['_wpnonce'] = wp_create_nonce('pp_notifications_user_post_subscription');
    385 
    386             return array(
    387                 'title' => $title_text,
    388                 'text'  => $link_text,
    389                 'link'  => add_query_arg($args, admin_url('admin-ajax.php')),
    390             );
    391         }
    392 
    393         /**
    394          * Add the subscriptions meta box to relevant post types
    395          */
    396         public function add_post_meta_box()
    397         {
    398             if (!current_user_can($this->edit_post_subscriptions_cap))
    399             {
    400                 return;
    401             }
    402 
    403             $role_post_types = $this->get_post_types_for_module($this->module);
    404             foreach ($role_post_types as $post_type)
    405             {
    406                 add_meta_box(
    407                     'publishpress-notifications',
    408                     __('Notify', 'publishpress'),
    409                     array($this, 'notifications_meta_box'),
    410                     $post_type,
    411                     'side',
    412                     'high'
    413                 );
    414             }
    415         }
    416 
    417         /**
    418          * Outputs box used to subscribe users and roles to Posts
    419          *
    420          * @todo add_cap to set subscribers for posts; default to Admin and editors
    421          */
    422         public function notifications_meta_box()
    423         {
    424             global $post, $post_ID, $publishpress;
    425 
    426             ?>
     311            <?php
     312        }
     313
     314        /**
     315         * Add a "Notify" link to supported post types Manage Posts view
     316         *
     317         * @since 0.8
     318         *
     319         * @param array      $actions Any existing item actions
     320         * @param int|object $post    Post id or object
     321         *
     322         * @return array     $actions   The follow link has been appended
     323         */
     324        public function filter_post_row_actions( $actions, $post ) {
     325            $post = get_post( $post );
     326
     327            if ( ! in_array( $post->post_type, $this->get_post_types_for_module( $this->module ) ) ) {
     328                return $actions;
     329            }
     330
     331            if ( ! current_user_can( $this->edit_post_subscriptions_cap ) || ! current_user_can( 'edit_post',
     332                    $post->ID ) ) {
     333                return $actions;
     334            }
     335
     336            $parts                     = $this->get_notify_action_parts( $post );
     337            $actions['pp_notify_link'] = '<a title="' . esc_attr( $parts['title'] ) . '" href="' . esc_url( $parts['link'] ) . '">' . $parts['text'] . '</a>';
     338
     339            return $actions;
     340        }
     341
     342        /**
     343         * Get an action parts for a user to set Notify or Stop Notify for a post
     344         *
     345         * @since 0.8
     346         */
     347        private function get_notify_action_parts( $post ) {
     348            $args = [
     349                'action'  => 'pp_notifications_user_post_subscription',
     350                'post_id' => $post->ID,
     351            ];
     352
     353            $user_to_notify = $this->get_users_to_notify( $post->ID );
     354
     355            if ( in_array( wp_get_current_user()->user_login, $user_to_notify ) ) {
     356                $args['method'] = 'stop_notifying';
     357                $title_text     = __( 'Click to stop being notified on updates for this post', 'publishpress' );
     358                $link_text      = __( 'Stop notifying me', 'publishpress' );
     359            } else {
     360                $args['method'] = 'start_notifying';
     361                $title_text     = __( 'Click to start being notified on updates for this post', 'publishpress' );
     362                $link_text      = __( 'Notify me', 'publishpress' );
     363            }
     364
     365            // wp_nonce_url() has encoding issues: http://core.trac.wordpress.org/ticket/20771
     366            $args['_wpnonce'] = wp_create_nonce( 'pp_notifications_user_post_subscription' );
     367
     368            return [
     369                'title' => $title_text,
     370                'text'  => $link_text,
     371                'link'  => add_query_arg( $args, admin_url( 'admin-ajax.php' ) ),
     372            ];
     373        }
     374
     375        /**
     376         * Add the subscriptions meta box to relevant post types
     377         */
     378        public function add_post_meta_box() {
     379            if ( ! current_user_can( $this->edit_post_subscriptions_cap ) ) {
     380                return;
     381            }
     382
     383            $role_post_types = $this->get_post_types_for_module( $this->module );
     384            foreach ( $role_post_types as $post_type ) {
     385                add_meta_box(
     386                    'publishpress-notifications',
     387                    __( 'Notify', 'publishpress' ),
     388                    [ $this, 'notifications_meta_box' ],
     389                    $post_type,
     390                    'side',
     391                    'high'
     392                );
     393            }
     394        }
     395
     396        /**
     397         * Outputs box used to subscribe users and roles to Posts
     398         *
     399         * @todo add_cap to set subscribers for posts; default to Admin and editors
     400         */
     401        public function notifications_meta_box() {
     402            global $post, $post_ID, $publishpress;
     403
     404            ?>
    427405            <div id="pp_post_notify_box">
    428406                <a name="subscriptions"></a>
    429407
    430408                <p>
    431                     <?php _e('Select the users and roles that should receive notifications from workflows.', 'publishpress'); ?>
     409                    <?php _e( 'Select the users and roles that should receive notifications from workflows.',
     410                        'publishpress' ); ?>
    432411                </p>
    433412
     
    439418                    $selected = array_merge($users_to_notify, $roles_to_notify);
    440419
    441                     $select_form_args = array(
     420                    $select_form_args = [
    442421                        'list_class' => 'pp_post_notify_list',
    443                     );
     422                    ];
    444423                    $this->users_select_form($selected , $select_form_args);
    445424                    ?>
     
    449428
    450429                <p>
    451                     <a href="https://publishpress.com/docs/notifications/"><?php _e('Click to read more about notifications', 'publishpress'); ?></a>
     430                    <a href="https://publishpress.com/docs/notifications/"><?php _e( 'Click to read more about notifications',
     431                            'publishpress' ); ?></a>
    452432                </p>
    453433
     
    455435
    456436                <input type="hidden" name="pp_save_notify" value="1"/> <?php // Extra protection against autosaves
    457                 ?>
    458 
    459                 <?php wp_nonce_field('save_roles', 'pp_notifications_nonce', false); ?>
     437                ?>
     438
     439                <?php wp_nonce_field( 'save_roles', 'pp_notifications_nonce', false ); ?>
    460440            </div>
    461441
    462             <?php
    463         }
    464 
    465         public function action_save_post($postId)
    466         {
    467             if (!isset($_POST['pp_notifications_nonce']) || !wp_verify_nonce($_POST['pp_notifications_nonce'], 'save_roles')) {
    468                 return;
    469             }
    470 
    471             if (isset($_POST['to_notify'])) {
    472                 // Remove current users
    473                 $terms = get_the_terms($postId, $this->notify_user_taxonomy);
    474                 $users = array();
    475                 if (!empty($terms)) {
    476                     foreach ($terms as $term) {
    477                         $users[] = $term->term_id;
    478                     }
    479                 }
    480                 wp_remove_object_terms($postId, $users, $this->notify_user_taxonomy);
    481 
    482                 // Remove current roles
    483                 $terms = get_the_terms($postId, $this->notify_role_taxonomy);
    484                 $roles = array();
    485                 if (!empty($terms)) {
    486                     foreach ($terms as $term) {
    487                         $roles[] = $term->term_id;
    488                     }
    489                 }
    490                 wp_remove_object_terms($postId, $roles, $this->notify_role_taxonomy);
    491 
    492                 foreach ($_POST['to_notify'] as $id) {
    493                     if (is_numeric($id)) {
    494                         // User id
    495                         $this->post_set_users_to_notify($postId, (int)$id, true);
    496                     } else {
    497                         // Role name
    498                         $this->post_set_roles_to_notify($postId, $id, true);
    499                     }
    500                 }
    501             }
    502         }
    503 
    504         /**
    505          * Handle a request to update a user's post subscription
    506          *
    507          * @since 0.8
    508          */
    509         public function handle_user_post_subscription()
    510         {
    511             if (!wp_verify_nonce($_GET['_wpnonce'], 'pp_notifications_user_post_subscription'))
    512             {
    513                 $this->print_ajax_response('error', $this->module->messages['nonce-failed']);
    514             }
    515 
    516             if (!current_user_can($this->edit_post_subscriptions_cap))
    517             {
    518                 $this->print_ajax_response('error', $this->module->messages['invalid-permissions']);
    519             }
    520 
    521             $post = get_post(($post_id = $_GET['post_id']));
    522 
    523             if (!$post)
    524             {
    525                 $this->print_ajax_response('error', $this->module->messages['missing-post']);
    526             }
    527 
    528             if ('start_notifying' === $_GET['method'])
    529             {
    530                 $retval = $this->post_set_users_to_notify($post, get_current_user_id());
    531             } else
    532             {
    533                 $retval = $this->post_set_users_stop_notify($post, get_current_user_id());
    534             }
    535 
    536             if (is_wp_error($retval))
    537             {
    538                 $this->print_ajax_response('error', $retval->get_error_message());
    539             }
    540 
    541             $this->print_ajax_response('success', (object )$this->get_notify_action_parts($post));
    542         }
    543 
    544         /**
    545          * @param $default
    546          * @param $context
    547          * @return bool
    548          */
    549         public function filter_pp_notification_auto_subscribe_post_author($default, $context)
    550         {
    551             if (!isset($this->module->options->notify_author_by_default))
    552             {
    553                 return $default;
    554             }
    555 
    556             return (booL)$this->module->options->notify_author_by_default;
    557         }
    558 
    559         /**
    560          * @param $default
    561          * @param $context
    562          * @return bool
    563          */
    564         public function filter_pp_notification_auto_subscribe_current_user($default, $context)
    565         {
    566             if (!isset($this->module->options->notify_current_user_by_default))
    567             {
    568                 return $default;
    569             }
    570 
    571             return (booL)$this->module->options->notify_current_user_by_default;
    572         }
    573 
    574         /**
    575          * Sets users to be notified for the specified post
    576          *
    577          * @param int $post ID of the post
    578          */
    579         public function save_post_notify_users($post, $users = null)
    580         {
    581             if (!is_array($users))
    582             {
    583                 $users = array();
    584             }
    585 
    586             // Add current user to notify list
    587             $user = wp_get_current_user();
    588             if ($user && apply_filters('pp_notification_auto_subscribe_current_user', true, 'subscription_action'))
    589             {
    590                 $users[] = $user->ID;
    591             }
    592 
    593             // Add post author to notify list
    594             if (apply_filters('pp_notification_auto_subscribe_post_author', true, 'subscription_action'))
    595             {
    596                 $users[] = $post->post_author;
    597             }
    598 
    599             $users = array_unique(array_map('intval', $users));
    600 
    601             $this->post_set_users_to_notify($post, $users, false);
    602         }
    603 
    604         /**
    605          * Sets roles to be notified for the specified post
    606          *
    607          * @param int   $post       ID of the post
    608          * @param array $roles   Roles to be notified for posts
    609          */
    610         public function save_post_notify_roles($post, $roles = null)
    611         {
    612             if (!is_array($roles))
    613             {
    614                 $roles = array();
    615             }
    616             $roles = array_map('intval', $roles);
    617 
    618             $this->add_role_to_notify($post, $roles, false);
    619         }
    620 
    621         /**
    622          * Set up and send post status change a notification
    623          */
    624         public function notification_status_change($new_status, $old_status, $post)
    625         {
    626             global $publishpress;
    627 
    628 
    629             // Kill switch for notification
    630             if (!apply_filters('pp_notification_status_change', $new_status, $old_status, $post) || !apply_filters("pp_notification_{$post->post_type}_status_change", $new_status, $old_status, $post))
    631             {
    632                 return false;
    633             }
    634 
    635             $supported_post_types = $this->get_post_types_for_module($this->module);
    636             if (!in_array($post->post_type, $supported_post_types))
    637             {
    638                 return;
    639             }
    640 
    641             // No need to notify if it's a revision, auto-draft, or if post status wasn't changed
    642             $ignored_statuses = apply_filters('pp_notification_ignored_statuses', array($old_status, 'inherit', 'auto-draft'), $post->post_type);
    643 
    644             if (!in_array($new_status, $ignored_statuses))
    645             {
    646                 $args = array(
    647                     'new_status' => $new_status,
    648                     'old_status' => $old_status,
    649                     'post'       => $post,
    650                 );
    651 
    652                 do_action('pp_send_notification_status_update', $args);
    653             }
    654         }
    655 
    656         /**
    657          * Set up and set editorial comment notification email
    658          */
    659         public function notification_comment($comment)
    660         {
    661             $post = get_post($comment->comment_post_ID);
    662 
    663             $supported_post_types = $this->get_post_types_for_module($this->module);
    664             if (!in_array($post->post_type, $supported_post_types))
    665             {
    666                 return;
    667             }
    668 
    669             // Kill switch for notification
    670             if (!apply_filters('pp_notification_editorial_comment', $comment, $post))
    671             {
    672                 return false;
    673             }
    674 
    675             $user         = get_userdata($post->post_author);
    676             $current_user = wp_get_current_user();
    677 
    678             $post_id    = $post->ID;
    679             $post_type  = get_post_type_object($post->post_type)->labels->singular_name;
    680             $post_title = pp_draft_or_post_title($post_id);
    681 
    682             // Check if this a reply
    683             //$parent_ID = isset( $comment->comment_parent_ID ) ? $comment->comment_parent_ID : 0;
    684             //if( $parent_ID ) $parent = get_comment( $parent_ID );
    685 
    686             // Set user to be notified for a post, but make it filterable
    687             if (apply_filters('pp_notification_auto_subscribe_current_user', true, 'comment'))
    688             {
    689                 $this->post_set_users_to_notify($post, (int )$current_user->ID);
    690             }
    691 
    692             // Set the post author to be notified for the post but make it filterable
    693             if (apply_filters('pp_notification_auto_subscribe_post_author', true, 'comment'))
    694             {
    695                 $this->post_set_users_to_notify($post, (int )$post->post_author);
    696             }
    697 
    698             $blogname = get_option('blogname');
    699 
    700             // Send the notification
    701             $args = array(
    702                 'blogname'     => $blogname,
    703                 'post'         => $post,
    704                 'post_title'   => $post_title,
    705                 'post_id'      => $post_id,
    706                 'post_type'    => $post_type,
    707                 'current_user' => $current_user,
    708                 'comment'      => $comment,
    709             );
    710 
    711             do_action('pp_send_notification_comment', $args);
    712         }
    713 
    714         public function get_notification_footer($post)
    715         {
    716             $body = "";
    717             $body .= "\r\n--------------------\r\n";
    718             $body .= sprintf(__('You are receiving this email because you are subscribed to "%s".', 'publishpress'), pp_draft_or_post_title($post->ID));
    719             $body .= "\r\n";
    720             $body .= sprintf(__('This email was sent %s.', 'publishpress'), date('r'));
    721             $body .= "\r\n \r\n";
    722             $body .= get_option('blogname') . " | " . get_bloginfo('url') . " | " . admin_url('/') . "\r\n";
    723 
    724             return $body;
    725         }
    726 
    727         /**
    728          * send_email()
    729          */
    730         public function send_email($action, $post, $subject, $message, $message_headers = '', $recipients = null)
    731         {
    732             if (is_null($recipients))
    733             {
    734                 // Get list of email recipients -- set them CC
    735                 $recipients = $this->_get_notification_recipients($post, true);
    736             }
    737 
    738             if ($recipients && !is_array($recipients))
    739             {
    740                 $recipients = explode(',', $recipients);
    741             }
    742 
    743             $subject         = apply_filters('pp_notification_send_email_subject', $subject, $action, $post);
    744             $message         = apply_filters('pp_notification_send_email_message', $message, $action, $post);
    745             $message_headers = apply_filters('pp_notification_send_email_message_headers', $message_headers, $action, $post);
    746 
    747             if (PP_NOTIFICATION_USE_CRON)
    748             {
    749                 $this->schedule_emails($recipients, $subject, $message, $message_headers);
    750             } else if (!empty($recipients))
    751             {
    752                 foreach ($recipients as $recipient)
    753                 {
    754                     $this->send_single_email($recipient, $subject, $message, $message_headers);
    755                 }
    756             }
    757         }
    758 
    759         /**
    760          * Schedules emails to be sent in succession
    761          *
    762          * @param mixed  $recipients      Individual email or array of emails
    763          * @param string $subject         Subject of the email
    764          * @param string $message         Body of the email
    765          * @param string $message_headers . (optional ) Message headers
    766          * @param int    $time_offset     (optional ) Delay in seconds per email
    767          */
    768         public function schedule_emails($recipients, $subject, $message, $message_headers = '', $time_offset = 1)
    769         {
    770             $recipients = (array)$recipients;
    771 
    772             $send_time = time();
    773 
    774             foreach ($recipients as $recipient)
    775             {
    776                 wp_schedule_single_event($send_time, 'pp_send_scheduled_notification', array($recipient, $subject, $message, $message_headers));
    777                 $send_time += $time_offset;
    778             }
    779         }
    780 
    781         /**
    782          * Sends an individual email
    783          *
    784          * @param mixed  $to              Email to send to
    785          * @param string $subject         Subject of the email
    786          * @param string $message         Body of the email
    787          * @param string $message_headers . (optional ) Message headers
    788          */
    789         public function send_single_email($to, $subject, $message, $message_headers = '')
    790         {
    791             wp_mail($to, $subject, $message, $message_headers);
    792         }
    793 
    794         /**
    795          * Returns a list of recipients for a given post
    796          *
    797          * @param $post   object
    798          * @param $string bool Whether to return recipients as comma-delimited string or array
    799          * @return string or array of recipients to receive notification
    800          */
    801         private function _get_notification_recipients($post, $string = false)
    802         {
    803             global $publishpress;
    804 
    805             $post_id = $post->ID;
    806             if (!$post_id)
    807             {
    808                 return;
    809             }
    810 
    811             $authors    = array();
    812             $admins     = array();
    813             $recipients = array();
    814 
    815             $role_users = array();
    816 
    817             // Get users and roles to notify
    818             $roles = $this->get_roles_to_notify($post_id, 'slugs');
    819             foreach ((array )$roles as $role_id)
    820             {
    821                 $users = get_users(
    822                     [
    823                         'role' => $role_id,
    824                     ]
    825                 );
    826 
    827                 if (!empty($users)) {
    828                     foreach ($users as $user)
    829                     {
    830                         if (is_user_member_of_blog($user->ID))
    831                         {
    832                             $role_users[] = $user->user_email;
    833                         }
    834                     }
    835                 }
    836             }
    837 
    838             $users = $this->get_users_to_notify($post_id, 'user_email');
    839 
    840             // Merge arrays and filter any duplicates
    841             $recipients = array_merge($authors, $admins, $users, $role_users);
    842             $recipients = array_unique($recipients);
    843 
    844             // Process the recipients for this email to be sent
    845             foreach ($recipients as $key => $user_email)
    846             {
    847                 // Get rid of empty email entries
    848                 if (empty($recipients[$key]))
    849                 {
    850                     unset($recipients[$key]);
    851                 }
    852                 // Don't send the email to the current user unless we've explicitly indicated they should receive it
    853                 if (false === apply_filters('publishpress_notify_current_user', false) && wp_get_current_user()->user_email == $user_email)
    854                 {
    855                     unset($recipients[$key]);
    856                 }
    857             }
    858 
    859             // Filter to allow further modification of recipients
    860             $recipients = apply_filters('pp_notification_recipients', $recipients, $post, $string);
    861 
    862             // If string set to true, return comma-delimited
    863             if ($string && is_array($recipients))
    864             {
    865                 return implode(',', $recipients);
    866             } else
    867             {
    868                 return $recipients;
    869             }
    870         }
    871 
    872         /**
    873          * Set a user or users to be notified for a post
    874          *
    875          * @param int|object   $post   Post object or ID
    876          * @param string|array $users  User or users to subscribe to post updates
    877          * @param bool         $append Whether users should be added to pp_notify_user list or replace existing list
    878          *
    879          * @return true|WP_Error     $response  True on success, WP_Error on failure
    880          */
    881         public function post_set_users_to_notify($post, $users, $append = true)
    882         {
    883             $post = get_post($post);
    884             if (!$post)
    885             {
    886                 return new WP_Error('missing-post', $this->module->messages['missing-post']);
    887             }
    888 
    889             if (!is_array($users))
    890             {
    891                 $users = array($users);
    892             }
    893 
    894             $user_terms = array();
    895 
    896             foreach ($users as $user)
    897             {
    898                 if (is_int($user))
    899                 {
    900                     $user = get_user_by('id', $user);
    901                 } else if (is_string($user))
    902                 {
    903                     $user = get_user_by('login', $user);
    904                 }
    905 
    906                 if (!is_object($user))
    907                 {
    908                     continue;
    909                 }
    910 
    911                 $name = $user->user_login;
    912 
    913                 // Add user as a term if they don't exist
    914                 $term = $this->add_term_if_not_exists($name, $this->notify_user_taxonomy);
    915 
    916                 if (!is_wp_error($term))
    917                 {
    918                     $user_terms[] = $name;
    919                 }
    920             }
    921 
    922             $set = wp_set_object_terms($post->ID, $user_terms, $this->notify_user_taxonomy, $append);
    923 
    924             if (is_wp_error($set))
    925             {
    926                 return $set;
    927             } else
    928             {
    929                 return true;
    930             }
    931         }
    932 
    933         /**
    934          * Set a role or roles to be notified for a post
    935          *
    936          * @param int|object   $post   Post object or ID
    937          * @param string|array $roles  Role or roles to subscribe to post updates
    938          * @param bool         $append Whether roles should be added to pp_notify_role list or replace existing list
    939          *
    940          * @return true|WP_Error     $response  True on success, WP_Error on failure
    941          */
    942         public function post_set_roles_to_notify($post, $roles, $append = true)
    943         {
    944             $post = get_post($post);
    945             if (!$post)
    946             {
    947                 return new WP_Error('missing-post', $this->module->messages['missing-post']);
    948             }
    949 
    950             if (!is_array($roles))
    951             {
    952                 $roles = array($roles);
    953             }
    954 
    955             $role_terms = array();
    956 
    957             foreach ($roles as $role)
    958             {
    959                 $role = get_role($role);
    960 
    961                 if (!is_object($role))
    962                 {
    963                     continue;
    964                 }
    965 
    966                 // Add user as a term if they don't exist
    967                 $term = $this->add_term_if_not_exists($role->name, $this->notify_role_taxonomy);
    968 
    969                 if (!is_wp_error($term))
    970                 {
    971                     $role_terms[] = $role->name;
    972                 }
    973             }
    974 
    975             $set = wp_set_object_terms($post->ID, $role_terms, $this->notify_role_taxonomy, $append);
    976 
    977             if (is_wp_error($set))
    978             {
    979                 return $set;
    980             } else
    981             {
    982                 return true;
    983             }
    984         }
    985 
    986         /**
    987          * Removes user from pp_notify_user taxonomy for the given Post,
    988          * so they no longer receive future notifications.
    989          *
    990          * @param object           $post  Post object or ID
    991          * @param int|string|array $users One or more users to stop being notified for the post
    992          * @return true|WP_Error     $response  True on success, WP_Error on failure
    993          */
    994         public function post_set_users_stop_notify($post, $users)
    995         {
    996             $post = get_post($post);
    997             if (!$post)
    998             {
    999                 return new WP_Error('missing-post', $this->module->messages['missing-post']);
    1000             }
    1001 
    1002             if (!is_array($users))
    1003             {
    1004                 $users = array($users);
    1005             }
    1006 
    1007             $terms = get_the_terms($post->ID, $this->notify_user_taxonomy);
    1008             if (is_wp_error($terms))
    1009             {
    1010                 return $terms;
    1011             }
    1012 
    1013             $user_terms = wp_list_pluck($terms, 'slug');
    1014             foreach ($users as $user)
    1015             {
    1016                 if (is_int($user))
    1017                 {
    1018                     $user = get_user_by('id', $user);
    1019                 } else if (is_string($user))
    1020                 {
    1021                     $user = get_user_by('login', $user);
    1022                 }
    1023 
    1024                 if (!is_object($user))
    1025                 {
    1026                     continue;
    1027                 }
    1028 
    1029                 $key = array_search($user->user_login, $user_terms);
    1030                 if (false !== $key)
    1031                 {
    1032                     unset($user_terms[$key]);
    1033                 }
    1034             }
    1035             $set = wp_set_object_terms($post->ID, $user_terms, $this->notify_user_taxonomy, false);
    1036 
    1037             if (is_wp_error($set))
    1038             {
    1039                 return $set;
    1040             } else
    1041             {
    1042                 return true;
    1043             }
    1044         }
    1045 
    1046         /**
    1047          * add_role_to_notify()
    1048          *
    1049          */
    1050         public function add_role_to_notify($post, $roles = 0, $append = true)
    1051         {
    1052             $post_id = (is_int($post)) ? $post : $post->ID;
    1053             if (!is_array($roles))
    1054             {
    1055                 $roles = array($roles);
    1056             }
    1057 
    1058             // make sure each role id is an integer and not a number stored as a string
    1059             foreach ($roles as $key => $role)
    1060             {
    1061                 $roles[$key] = intval($role);
    1062             }
    1063 
    1064             wp_set_object_terms($post_id, $roles, $this->notify_role_taxonomy, $append);
    1065 
    1066             return;
    1067         }
    1068 
    1069         /**
    1070          * Removes users that are deleted from receiving future notifications (i.e. makes them out of notify list for posts FOREVER! )
    1071          *
    1072          * @param $id int ID of the user
    1073          */
    1074         public function delete_user_action($id)
    1075         {
    1076             if (!$id)
    1077             {
    1078                 return;
    1079             }
    1080 
    1081             // get user data
    1082             $user = get_userdata($id);
    1083 
    1084             if ($user)
    1085             {
    1086                 // Delete term from the pp_notify_user taxonomy
    1087                 $notify_user_term = get_term_by('name', $user->user_login, $this->notify_user_taxonomy);
    1088                 if ($notify_user_term)
    1089                 {
    1090                     wp_delete_term($notify_user_term->term_id, $this->notify_user_taxonomy);
    1091                 }
    1092             }
    1093 
    1094             return;
    1095         }
    1096 
    1097         /**
    1098          * Add user as a term if they aren't already
    1099          *
    1100          * @param $term     string term to be added
    1101          * @param $taxonomy string taxonomy to add term to
    1102          * @return WP_error if insert fails, true otherwise
    1103          */
    1104         public function add_term_if_not_exists($term, $taxonomy)
    1105         {
    1106             if (!term_exists($term, $taxonomy))
    1107             {
    1108                 $args = array('slug' => sanitize_title($term));
    1109 
    1110                 return wp_insert_term($term, $taxonomy, $args);
    1111             }
    1112 
    1113             return true;
    1114         }
    1115 
    1116         /**
    1117          * Gets a list of the users to be notified for the specified post
    1118          *
    1119          * @param int    $post_id The ID of the post
    1120          * @param string $return  The field to return
    1121          * @return array $users Users to notify for the specified posts
    1122          */
    1123         public function get_users_to_notify($post_id, $return = 'user_login')
    1124         {
    1125             // Get pp_notify_user terms for the post
    1126             $users = wp_get_object_terms($post_id, $this->notify_user_taxonomy, array('fields' => 'names'));
    1127 
    1128             // Don't have any users to notify
    1129             if (!$users || is_wp_error($users))
    1130             {
    1131                 return array();
    1132             }
    1133 
    1134             // if just want user_login, return as is
    1135             if ($return == 'user_login')
    1136             {
    1137                 return $users;
    1138             }
    1139 
    1140             foreach ((array )$users as $key => $user)
    1141             {
    1142                 switch ($user)
    1143                 {
    1144                     case is_int($user):
    1145                         $search = 'id';
    1146                         break;
    1147                     case is_email($user):
    1148                         $search = 'email';
    1149                         break;
    1150                     default:
    1151                         $search = 'login';
    1152                         break;
    1153                 }
    1154                 $new_user = get_user_by($search, $user);
    1155                 if (!$new_user || !is_user_member_of_blog($new_user->ID))
    1156                 {
    1157                     unset($users[$key]);
    1158                     continue;
    1159                 }
    1160                 switch ($return)
    1161                 {
    1162                     case 'user_login':
    1163                         $users[$key] = $new_user->user_login;
    1164                         break;
    1165                     case 'id':
    1166                         $users[$key] = $new_user->ID;
    1167                         break;
    1168                     case 'user_email':
    1169                         $users[$key] = $new_user->user_email;
    1170                         break;
    1171                     case 'object':
    1172                         $users[$key] = $new_user;
    1173                         break;
    1174                 }
    1175             }
    1176             if (!$users || is_wp_error($users))
    1177             {
    1178                 $users = array();
    1179             }
    1180 
    1181             return $users;
    1182         }
    1183 
    1184         /**
    1185          * Gets a list of the roles that should be notified for the specified post
    1186          *
    1187          * @param int $post_id
    1188          * @return array $roles All of the role slugs
    1189          */
    1190         public function get_roles_to_notify($post_id, $return = 'all')
    1191         {
    1192             global $publishpress;
    1193 
    1194             // Workaround for the fact that get_object_terms doesn't return just slugs
    1195             if ($return == 'slugs')
    1196             {
    1197                 $fields = 'all';
    1198             } else
    1199             {
    1200                 $fields = $return;
    1201             }
    1202 
    1203             $roles = wp_get_object_terms($post_id, $this->notify_role_taxonomy, array('fields' => $fields));
    1204 
    1205             if ($return == 'slugs')
    1206             {
    1207                 $slugs = array();
    1208                 foreach ($roles as $role)
    1209                 {
    1210                     $slugs[] = $role->slug;
    1211                 }
    1212                 $roles = $slugs;
    1213             }
    1214 
    1215             return $roles;
    1216         }
    1217 
    1218         /**
    1219          * Gets a list of posts that a user is selected to be notified
    1220          *
    1221          * @param string|int $user user_login or id of user
    1222          * @param array      $args
    1223          * @return array $posts Posts a user is selected to be notified
    1224          */
    1225         public function get_user_to_notify_posts($user = 0, $args = null)
    1226         {
    1227             if (!$user)
    1228             {
    1229                 $user = (int )wp_get_current_user()->ID;
    1230             }
    1231 
    1232             if (is_int($user))
    1233             {
    1234                 $user = get_userdata($user)->user_login;
    1235             }
    1236 
    1237             $post_args = array(
    1238                 'tax_query'      => array(
    1239                     array(
    1240                         'taxonomy' => $this->notify_user_taxonomy,
    1241                         'field'    => 'slug',
    1242                         'terms'    => $user,
    1243                     ),
    1244                 ),
    1245                 'posts_per_page' => '10',
    1246                 'orderby'        => 'modified',
    1247                 'order'          => 'DESC',
    1248                 'post_status'    => 'any',
    1249             );
    1250             $post_args = apply_filters('pp_user_to_notify_posts_query_args', $post_args);
    1251             $posts     = get_posts($post_args);
    1252 
    1253             return $posts;
    1254         }
    1255 
    1256         /**
    1257          * Register settings for notifications so we can partially use the Settings API
    1258          * (We use the Settings API for form generation, but not saving )
    1259          *
    1260          * @since 0.7
    1261          */
    1262         public function register_settings()
    1263         {
    1264             add_settings_section($this->module->options_group_name . '_general', false, '__return_false', $this->module->options_group_name);
    1265             add_settings_field(
    1266                 'post_types',
    1267                 __('Show the "Notify me" and "Stop notifying me" links for these post types:', 'publishpress'),
    1268                 array($this, 'settings_post_types_option'),
    1269                 $this->module->options_group_name,
    1270                 $this->module->options_group_name . '_general'
    1271             );
    1272 
    1273             add_settings_field(
    1274                 'email_from',
    1275                 __('Email from:', 'publishpress'),
    1276                 array($this, 'settings_email_from_option'),
    1277                 $this->module->options_group_name,
    1278                 $this->module->options_group_name . '_general'
    1279             );
    1280 
    1281             add_settings_field(
    1282                 'notify_author_by_default',
    1283                 __('Always notify the author of the content:', 'publishpress'),
    1284                 array($this, 'settings_notify_author_by_default_option'),
    1285                 $this->module->options_group_name,
    1286                 $this->module->options_group_name . '_general'
    1287             );
    1288 
    1289             add_settings_field(
    1290                 'notify_current_user_by_default',
    1291                 __('Always notify users who have edited the content:', 'publishpress'),
    1292                 array($this, 'settings_notify_current_user_by_default_option'),
    1293                 $this->module->options_group_name,
    1294                 $this->module->options_group_name . '_general'
    1295             );
    1296         }
    1297 
    1298         /**
    1299          * Chose the post types for notifications
    1300          *
    1301          * @since 0.7
    1302          */
    1303         public function settings_post_types_option()
    1304         {
    1305             global $publishpress;
    1306             $publishpress->settings->helper_option_custom_post_type($this->module);
    1307         }
    1308 
    1309         public function get_email_from()
    1310         {
    1311             if (!isset($this->module->options->email_from_name))
    1312             {
    1313                 $name = get_bloginfo('name');
    1314             } else
    1315             {
    1316                 $name = $this->module->options->email_from_name;
    1317             }
    1318 
    1319             if (!isset($this->module->options->email_from))
    1320             {
    1321                 $email = get_bloginfo('admin_email');
    1322             } else
    1323             {
    1324                 $email = $this->module->options->email_from;
    1325             }
    1326 
    1327             return array(
    1328                 'name'  => $name,
    1329                 'email' => $email,
    1330             );
    1331         }
    1332 
    1333         /**
    1334          * Field to customize the email for the "email from".
    1335          */
    1336         public function settings_email_from_option()
    1337         {
    1338             $email_from = $this->get_email_from();
    1339 
    1340             echo '<input
     442            <?php
     443        }
     444
     445        public function action_save_post( $postId ) {
     446            if ( ! isset( $_POST['pp_notifications_nonce'] ) || ! wp_verify_nonce( $_POST['pp_notifications_nonce'],
     447                    'save_roles' ) ) {
     448                return;
     449            }
     450
     451            if ( isset( $_POST['to_notify'] ) ) {
     452                // Remove current users
     453                $terms = get_the_terms( $postId, $this->notify_user_taxonomy );
     454                $users = [];
     455                if ( ! empty( $terms ) ) {
     456                    foreach ( $terms as $term ) {
     457                        $users[] = $term->term_id;
     458                    }
     459                }
     460                wp_remove_object_terms( $postId, $users, $this->notify_user_taxonomy );
     461
     462                // Remove current roles
     463                $terms = get_the_terms( $postId, $this->notify_role_taxonomy );
     464                $roles = [];
     465                if ( ! empty( $terms ) ) {
     466                    foreach ( $terms as $term ) {
     467                        $roles[] = $term->term_id;
     468                    }
     469                }
     470                wp_remove_object_terms( $postId, $roles, $this->notify_role_taxonomy );
     471
     472                foreach ( $_POST['to_notify'] as $id ) {
     473                    if ( is_numeric( $id ) ) {
     474                        // User id
     475                        $this->post_set_users_to_notify( $postId, (int) $id, true );
     476                    } else {
     477                        // Role name
     478                        $this->post_set_roles_to_notify( $postId, $id, true );
     479                    }
     480                }
     481            }
     482        }
     483
     484        /**
     485         * Handle a request to update a user's post subscription
     486         *
     487         * @since 0.8
     488         */
     489        public function handle_user_post_subscription() {
     490            if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'pp_notifications_user_post_subscription' ) ) {
     491                $this->print_ajax_response( 'error', $this->module->messages['nonce-failed'] );
     492            }
     493
     494            if ( ! current_user_can( $this->edit_post_subscriptions_cap ) ) {
     495                $this->print_ajax_response( 'error', $this->module->messages['invalid-permissions'] );
     496            }
     497
     498            $post = get_post( ( $post_id = $_GET['post_id'] ) );
     499
     500            if ( ! $post ) {
     501                $this->print_ajax_response( 'error', $this->module->messages['missing-post'] );
     502            }
     503
     504            if ( 'start_notifying' === $_GET['method'] ) {
     505                $retval = $this->post_set_users_to_notify( $post, get_current_user_id() );
     506            } else {
     507                $retval = $this->post_set_users_stop_notify( $post, get_current_user_id() );
     508            }
     509
     510            if ( is_wp_error( $retval ) ) {
     511                $this->print_ajax_response( 'error', $retval->get_error_message() );
     512            }
     513
     514            $this->print_ajax_response( 'success', (object ) $this->get_notify_action_parts( $post ) );
     515        }
     516
     517        /**
     518         * @param $default
     519         * @param $context
     520         *
     521         * @return bool
     522         */
     523        public function filter_pp_notification_auto_subscribe_post_author( $default, $context ) {
     524            if ( ! isset( $this->module->options->notify_author_by_default ) ) {
     525                return $default;
     526            }
     527
     528            return (booL) $this->module->options->notify_author_by_default;
     529        }
     530
     531        /**
     532         * @param $default
     533         * @param $context
     534         *
     535         * @return bool
     536         */
     537        public function filter_pp_notification_auto_subscribe_current_user( $default, $context ) {
     538            if ( ! isset( $this->module->options->notify_current_user_by_default ) ) {
     539                return $default;
     540            }
     541
     542            return (booL) $this->module->options->notify_current_user_by_default;
     543        }
     544
     545        /**
     546         * Sets users to be notified for the specified post
     547         *
     548         * @param int $post ID of the post
     549         */
     550        public function save_post_notify_users( $post, $users = null ) {
     551            if ( ! is_array( $users ) ) {
     552                $users = [];
     553            }
     554
     555            // Add current user to notify list
     556            $user = wp_get_current_user();
     557            if ( $user && apply_filters( 'pp_notification_auto_subscribe_current_user', true,
     558                    'subscription_action' ) ) {
     559                $users[] = $user->ID;
     560            }
     561
     562            // Add post author to notify list
     563            if ( apply_filters( 'pp_notification_auto_subscribe_post_author', true, 'subscription_action' ) ) {
     564                $users[] = $post->post_author;
     565            }
     566
     567            $users = array_unique( array_map( 'intval', $users ) );
     568
     569            $this->post_set_users_to_notify( $post, $users, false );
     570        }
     571
     572        /**
     573         * Sets roles to be notified for the specified post
     574         *
     575         * @param int   $post  ID of the post
     576         * @param array $roles Roles to be notified for posts
     577         */
     578        public function save_post_notify_roles( $post, $roles = null ) {
     579            if ( ! is_array( $roles ) ) {
     580                $roles = [];
     581            }
     582            $roles = array_map( 'intval', $roles );
     583
     584            $this->add_role_to_notify( $post, $roles, false );
     585        }
     586
     587        /**
     588         * Set up and send post status change a notification
     589         */
     590        public function notification_status_change( $new_status, $old_status, $post ) {
     591            global $publishpress;
     592
     593
     594            // Kill switch for notification
     595            if ( ! apply_filters( 'pp_notification_status_change', $new_status, $old_status,
     596                    $post ) || ! apply_filters( "pp_notification_{$post->post_type}_status_change", $new_status,
     597                    $old_status, $post ) ) {
     598                return false;
     599            }
     600
     601            $supported_post_types = $this->get_post_types_for_module( $this->module );
     602            if ( ! in_array( $post->post_type, $supported_post_types ) ) {
     603                return;
     604            }
     605
     606            // No need to notify if it's a revision, auto-draft, or if post status wasn't changed
     607            $ignored_statuses = apply_filters( 'pp_notification_ignored_statuses',
     608                [ $old_status, 'inherit', 'auto-draft' ], $post->post_type );
     609
     610            if ( ! in_array( $new_status, $ignored_statuses ) ) {
     611                $args = [
     612                    'new_status' => $new_status,
     613                    'old_status' => $old_status,
     614                    'post'       => $post,
     615                ];
     616
     617                do_action( 'pp_send_notification_status_update', $args );
     618            }
     619        }
     620
     621        /**
     622         * Set up and set editorial comment notification email
     623         */
     624        public function notification_comment( $comment ) {
     625            $post = get_post( $comment->comment_post_ID );
     626
     627            $supported_post_types = $this->get_post_types_for_module( $this->module );
     628            if ( ! in_array( $post->post_type, $supported_post_types ) ) {
     629                return;
     630            }
     631
     632            // Kill switch for notification
     633            if ( ! apply_filters( 'pp_notification_editorial_comment', $comment, $post ) ) {
     634                return false;
     635            }
     636
     637            $user         = get_userdata( $post->post_author );
     638            $current_user = wp_get_current_user();
     639
     640            $post_id    = $post->ID;
     641            $post_type  = get_post_type_object( $post->post_type )->labels->singular_name;
     642            $post_title = pp_draft_or_post_title( $post_id );
     643
     644            // Check if this a reply
     645            //$parent_ID = isset( $comment->comment_parent_ID ) ? $comment->comment_parent_ID : 0;
     646            //if( $parent_ID ) $parent = get_comment( $parent_ID );
     647
     648            // Set user to be notified for a post, but make it filterable
     649            if ( apply_filters( 'pp_notification_auto_subscribe_current_user', true, 'comment' ) ) {
     650                $this->post_set_users_to_notify( $post, (int ) $current_user->ID );
     651            }
     652
     653            // Set the post author to be notified for the post but make it filterable
     654            if ( apply_filters( 'pp_notification_auto_subscribe_post_author', true, 'comment' ) ) {
     655                $this->post_set_users_to_notify( $post, (int ) $post->post_author );
     656            }
     657
     658            $blogname = get_option( 'blogname' );
     659
     660            // Send the notification
     661            $args = [
     662                'blogname'     => $blogname,
     663                'post'         => $post,
     664                'post_title'   => $post_title,
     665                'post_id'      => $post_id,
     666                'post_type'    => $post_type,
     667                'current_user' => $current_user,
     668                'comment'      => $comment,
     669            ];
     670
     671            do_action( 'pp_send_notification_comment', $args );
     672        }
     673
     674        public function get_notification_footer( $post ) {
     675            $body = "";
     676            $body .= "\r\n--------------------\r\n";
     677            $body .= sprintf( __( 'You are receiving this email because you are subscribed to "%s".', 'publishpress' ),
     678                pp_draft_or_post_title( $post->ID ) );
     679            $body .= "\r\n";
     680            $body .= sprintf( __( 'This email was sent %s.', 'publishpress' ), date( 'r' ) );
     681            $body .= "\r\n \r\n";
     682            $body .= get_option( 'blogname' ) . " | " . get_bloginfo( 'url' ) . " | " . admin_url( '/' ) . "\r\n";
     683
     684            return $body;
     685        }
     686
     687        /**
     688         * send_email()
     689         */
     690        public function send_email( $action, $post, $subject, $message, $message_headers = '', $recipients = null ) {
     691            if ( is_null( $recipients ) ) {
     692                // Get list of email recipients -- set them CC
     693                $recipients = $this->_get_notification_recipients( $post, true );
     694            }
     695
     696            if ( $recipients && ! is_array( $recipients ) ) {
     697                $recipients = explode( ',', $recipients );
     698            }
     699
     700            $subject         = apply_filters( 'pp_notification_send_email_subject', $subject, $action, $post );
     701            $message         = apply_filters( 'pp_notification_send_email_message', $message, $action, $post );
     702            $message_headers = apply_filters( 'pp_notification_send_email_message_headers', $message_headers, $action,
     703                $post );
     704
     705            if ( PP_NOTIFICATION_USE_CRON ) {
     706                $this->schedule_emails( $recipients, $subject, $message, $message_headers );
     707            } elseif ( ! empty( $recipients ) ) {
     708                foreach ( $recipients as $recipient ) {
     709                    $this->send_single_email( $recipient, $subject, $message, $message_headers );
     710                }
     711            }
     712        }
     713
     714        /**
     715         * Schedules emails to be sent in succession
     716         *
     717         * @param mixed  $recipients      Individual email or array of emails
     718         * @param string $subject         Subject of the email
     719         * @param string $message         Body of the email
     720         * @param string $message_headers . (optional ) Message headers
     721         * @param int    $time_offset     (optional ) Delay in seconds per email
     722         */
     723        public function schedule_emails( $recipients, $subject, $message, $message_headers = '', $time_offset = 1 ) {
     724            $recipients = (array) $recipients;
     725
     726            $send_time = time();
     727
     728            foreach ( $recipients as $recipient ) {
     729                wp_schedule_single_event( $send_time, 'pp_send_scheduled_notification',
     730                    [ $recipient, $subject, $message, $message_headers ] );
     731                $send_time += $time_offset;
     732            }
     733        }
     734
     735        /**
     736         * Sends an individual email
     737         *
     738         * @param mixed  $to              Email to send to
     739         * @param string $subject         Subject of the email
     740         * @param string $message         Body of the email
     741         * @param string $message_headers . (optional ) Message headers
     742         */
     743        public function send_single_email( $to, $subject, $message, $message_headers = '' ) {
     744            wp_mail( $to, $subject, $message, $message_headers );
     745        }
     746
     747        /**
     748         * Returns a list of recipients for a given post
     749         *
     750         * @param $post   object
     751         * @param $string bool Whether to return recipients as comma-delimited string or array
     752         *
     753         * @return string|array
     754         */
     755        private function _get_notification_recipients( $post, $string = false ) {
     756            $post_id = $post->ID;
     757            if ( ! $post_id ) {
     758                return [];
     759            }
     760
     761            $authors    = [];
     762            $admins     = [];
     763            $role_users = [];
     764
     765            // Get users and roles to notify
     766            $roles = $this->get_roles_to_notify( $post_id, 'slugs' );
     767            foreach ( (array ) $roles as $role_id ) {
     768                $users = get_users(
     769                    [
     770                        'role' => $role_id,
     771                    ]
     772                );
     773
     774                if ( ! empty( $users ) ) {
     775                    foreach ( $users as $user ) {
     776                        if ( is_user_member_of_blog( $user->ID ) ) {
     777                            $role_users[] = $user->user_email;
     778                        }
     779                    }
     780                }
     781            }
     782
     783            $users = $this->get_users_to_notify( $post_id, 'user_email' );
     784
     785            // Merge arrays and filter any duplicates
     786            $recipients = array_merge( $authors, $admins, $users, $role_users );
     787            $recipients = array_unique( $recipients );
     788
     789            // Process the recipients for this email to be sent
     790            foreach ( $recipients as $key => $user_email ) {
     791                // Get rid of empty email entries
     792                if ( empty( $recipients[ $key ] ) ) {
     793                    unset( $recipients[ $key ] );
     794                }
     795                // Don't send the email to the current user unless we've explicitly indicated they should receive it
     796                if ( false === apply_filters( 'publishpress_notify_current_user',
     797                        false ) && wp_get_current_user()->user_email == $user_email ) {
     798                    unset( $recipients[ $key ] );
     799                }
     800            }
     801
     802            // Filter to allow further modification of recipients
     803            $recipients = apply_filters( 'pp_notification_recipients', $recipients, $post, $string );
     804
     805            // If string set to true, return comma-delimited
     806            if ( $string && is_array( $recipients ) ) {
     807                return implode( ',', $recipients );
     808            } else {
     809                return $recipients;
     810            }
     811        }
     812
     813        /**
     814         * Set a user or users to be notified for a post
     815         *
     816         * @param int|object   $post   Post object or ID
     817         * @param string|array $users  User or users to subscribe to post updates
     818         * @param bool         $append Whether users should be added to pp_notify_user list or replace existing list
     819         *
     820         * @return true|WP_Error     $response  True on success, WP_Error on failure
     821         */
     822        public function post_set_users_to_notify( $post, $users, $append = true ) {
     823            $post = get_post( $post );
     824            if ( ! $post ) {
     825                return new WP_Error( 'missing-post', $this->module->messages['missing-post'] );
     826            }
     827
     828            if ( ! is_array( $users ) ) {
     829                $users = [ $users ];
     830            }
     831
     832            $user_terms = [];
     833
     834            foreach ( $users as $user ) {
     835                if ( is_int( $user ) ) {
     836                    $user = get_user_by( 'id', $user );
     837                } elseif ( is_string( $user ) ) {
     838                    $user = get_user_by( 'login', $user );
     839                }
     840
     841                if ( ! is_object( $user ) ) {
     842                    continue;
     843                }
     844
     845                $name = $user->user_login;
     846
     847                // Add user as a term if they don't exist
     848                $term = $this->add_term_if_not_exists( $name, $this->notify_user_taxonomy );
     849
     850                if ( ! is_wp_error( $term ) ) {
     851                    $user_terms[] = $name;
     852                }
     853            }
     854
     855            $set = wp_set_object_terms( $post->ID, $user_terms, $this->notify_user_taxonomy, $append );
     856
     857            if ( is_wp_error( $set ) ) {
     858                return $set;
     859            } else {
     860                return true;
     861            }
     862        }
     863
     864        /**
     865         * Set a role or roles to be notified for a post
     866         *
     867         * @param int|object   $post   Post object or ID
     868         * @param string|array $roles  Role or roles to subscribe to post updates
     869         * @param bool         $append Whether roles should be added to pp_notify_role list or replace existing list
     870         *
     871         * @return true|WP_Error     $response  True on success, WP_Error on failure
     872         */
     873        public function post_set_roles_to_notify( $post, $roles, $append = true ) {
     874            $post = get_post( $post );
     875            if ( ! $post ) {
     876                return new WP_Error( 'missing-post', $this->module->messages['missing-post'] );
     877            }
     878
     879            if ( ! is_array( $roles ) ) {
     880                $roles = [ $roles ];
     881            }
     882
     883            $role_terms = [];
     884
     885            foreach ( $roles as $role ) {
     886                $role = get_role( $role );
     887
     888                if ( ! is_object( $role ) ) {
     889                    continue;
     890                }
     891
     892                // Add user as a term if they don't exist
     893                $term = $this->add_term_if_not_exists( $role->name, $this->notify_role_taxonomy );
     894
     895                if ( ! is_wp_error( $term ) ) {
     896                    $role_terms[] = $role->name;
     897                }
     898            }
     899
     900            $set = wp_set_object_terms( $post->ID, $role_terms, $this->notify_role_taxonomy, $append );
     901
     902            if ( is_wp_error( $set ) ) {
     903                return $set;
     904            } else {
     905                return true;
     906            }
     907        }
     908
     909        /**
     910         * Removes user from pp_notify_user taxonomy for the given Post,
     911         * so they no longer receive future notifications.
     912         *
     913         * @param object           $post  Post object or ID
     914         * @param int|string|array $users One or more users to stop being notified for the post
     915         *
     916         * @return true|WP_Error     $response  True on success, WP_Error on failure
     917         */
     918        public function post_set_users_stop_notify( $post, $users ) {
     919            $post = get_post( $post );
     920            if ( ! $post ) {
     921                return new WP_Error( 'missing-post', $this->module->messages['missing-post'] );
     922            }
     923
     924            if ( ! is_array( $users ) ) {
     925                $users = [ $users ];
     926            }
     927
     928            $terms = get_the_terms( $post->ID, $this->notify_user_taxonomy );
     929            if ( is_wp_error( $terms ) ) {
     930                return $terms;
     931            }
     932
     933            $user_terms = wp_list_pluck( $terms, 'slug' );
     934            foreach ( $users as $user ) {
     935                if ( is_int( $user ) ) {
     936                    $user = get_user_by( 'id', $user );
     937                } elseif ( is_string( $user ) ) {
     938                    $user = get_user_by( 'login', $user );
     939                }
     940
     941                if ( ! is_object( $user ) ) {
     942                    continue;
     943                }
     944
     945                $key = array_search( $user->user_login, $user_terms );
     946                if ( false !== $key ) {
     947                    unset( $user_terms[ $key ] );
     948                }
     949            }
     950            $set = wp_set_object_terms( $post->ID, $user_terms, $this->notify_user_taxonomy, false );
     951
     952            if ( is_wp_error( $set ) ) {
     953                return $set;
     954            } else {
     955                return true;
     956            }
     957        }
     958
     959        /**
     960         * add_role_to_notify()
     961         *
     962         */
     963        public function add_role_to_notify( $post, $roles = 0, $append = true ) {
     964            $post_id = ( is_int( $post ) ) ? $post : $post->ID;
     965            if ( ! is_array( $roles ) ) {
     966                $roles = [ $roles ];
     967            }
     968
     969            // make sure each role id is an integer and not a number stored as a string
     970            foreach ( $roles as $key => $role ) {
     971                $roles[ $key ] = intval( $role );
     972            }
     973
     974            wp_set_object_terms( $post_id, $roles, $this->notify_role_taxonomy, $append );
     975
     976            return;
     977        }
     978
     979        /**
     980         * Removes users that are deleted from receiving future notifications (i.e. makes them out of notify list for posts FOREVER! )
     981         *
     982         * @param $id int ID of the user
     983         */
     984        public function delete_user_action( $id ) {
     985            if ( ! $id ) {
     986                return;
     987            }
     988
     989            // get user data
     990            $user = get_userdata( $id );
     991
     992            if ( $user ) {
     993                // Delete term from the pp_notify_user taxonomy
     994                $notify_user_term = get_term_by( 'name', $user->user_login, $this->notify_user_taxonomy );
     995                if ( $notify_user_term ) {
     996                    wp_delete_term( $notify_user_term->term_id, $this->notify_user_taxonomy );
     997                }
     998            }
     999
     1000            return;
     1001        }
     1002
     1003        /**
     1004         * Add user as a term if they aren't already
     1005         *
     1006         * @param $term     string term to be added
     1007         * @param $taxonomy string taxonomy to add term to
     1008         *
     1009         * @return WP_error if insert fails, true otherwise
     1010         */
     1011        public function add_term_if_not_exists( $term, $taxonomy ) {
     1012            if ( ! term_exists( $term, $taxonomy ) ) {
     1013                $args = [ 'slug' => sanitize_title( $term ) ];
     1014
     1015                return wp_insert_term( $term, $taxonomy, $args );
     1016            }
     1017
     1018            return true;
     1019        }
     1020
     1021        /**
     1022         * Gets a list of the users to be notified for the specified post
     1023         *
     1024         * @param int    $post_id The ID of the post
     1025         * @param string $return  The field to return
     1026         *
     1027         * @return array $users Users to notify for the specified posts
     1028         */
     1029        public function get_users_to_notify( $post_id, $return = 'user_login' ) {
     1030            // Get pp_notify_user terms for the post
     1031            $users = wp_get_object_terms( $post_id, $this->notify_user_taxonomy, [ 'fields' => 'names' ] );
     1032
     1033            // Don't have any users to notify
     1034            if ( ! $users || is_wp_error( $users ) ) {
     1035                return [];
     1036            }
     1037
     1038            // if just want user_login, return as is
     1039            if ( $return == 'user_login' ) {
     1040                return $users;
     1041            }
     1042
     1043            foreach ( (array ) $users as $key => $user ) {
     1044                switch ( $user ) {
     1045                    case is_int( $user ):
     1046                        $search = 'id';
     1047                        break;
     1048                    case is_email( $user ):
     1049                        $search = 'email';
     1050                        break;
     1051                    default:
     1052                        $search = 'login';
     1053                        break;
     1054                }
     1055                $new_user = get_user_by( $search, $user );
     1056                if ( ! $new_user || ! is_user_member_of_blog( $new_user->ID ) ) {
     1057                    unset( $users[ $key ] );
     1058                    continue;
     1059                }
     1060                switch ( $return ) {
     1061                    case 'user_login':
     1062                        $users[ $key ] = $new_user->user_login;
     1063                        break;
     1064                    case 'id':
     1065                        $users[ $key ] = $new_user->ID;
     1066                        break;
     1067                    case 'user_email':
     1068                        $users[ $key ] = $new_user->user_email;
     1069                        break;
     1070                    case 'object':
     1071                        $users[ $key ] = $new_user;
     1072                        break;
     1073                }
     1074            }
     1075            if ( ! $users || is_wp_error( $users ) ) {
     1076                $users = [];
     1077            }
     1078
     1079            return $users;
     1080        }
     1081
     1082        /**
     1083         * Gets a list of the roles that should be notified for the specified post
     1084         *
     1085         * @param int $post_id
     1086         *
     1087         * @return array $roles All of the role slugs
     1088         */
     1089        public function get_roles_to_notify( $post_id, $return = 'all' ) {
     1090            global $publishpress;
     1091
     1092            // Workaround for the fact that get_object_terms doesn't return just slugs
     1093            if ( $return == 'slugs' ) {
     1094                $fields = 'all';
     1095            } else {
     1096                $fields = $return;
     1097            }
     1098
     1099            $roles = wp_get_object_terms( $post_id, $this->notify_role_taxonomy, [ 'fields' => $fields ] );
     1100
     1101            if ( $return == 'slugs' ) {
     1102                $slugs = [];
     1103                foreach ( $roles as $role ) {
     1104                    $slugs[] = $role->slug;
     1105                }
     1106                $roles = $slugs;
     1107            }
     1108
     1109            return $roles;
     1110        }
     1111
     1112        /**
     1113         * Gets a list of posts that a user is selected to be notified
     1114         *
     1115         * @param string|int $user user_login or id of user
     1116         * @param array      $args
     1117         *
     1118         * @return array $posts Posts a user is selected to be notified
     1119         */
     1120        public function get_user_to_notify_posts( $user = 0, $args = null ) {
     1121            if ( ! $user ) {
     1122                $user = (int ) wp_get_current_user()->ID;
     1123            }
     1124
     1125            if ( is_int( $user ) ) {
     1126                $user = get_userdata( $user )->user_login;
     1127            }
     1128
     1129            $post_args = [
     1130                'tax_query'      => [
     1131                    [
     1132                        'taxonomy' => $this->notify_user_taxonomy,
     1133                        'field'    => 'slug',
     1134                        'terms'    => $user,
     1135                    ],
     1136                ],
     1137                'posts_per_page' => '10',
     1138                'orderby'        => 'modified',
     1139                'order'          => 'DESC',
     1140                'post_status'    => 'any',
     1141            ];
     1142            $post_args = apply_filters( 'pp_user_to_notify_posts_query_args', $post_args );
     1143            $posts     = get_posts( $post_args );
     1144
     1145            return $posts;
     1146        }
     1147
     1148        /**
     1149         * Register settings for notifications so we can partially use the Settings API
     1150         * (We use the Settings API for form generation, but not saving )
     1151         *
     1152         * @since 0.7
     1153         */
     1154        public function register_settings() {
     1155            add_settings_section( $this->module->options_group_name . '_general', false, '__return_false',
     1156                $this->module->options_group_name );
     1157            add_settings_field(
     1158                'post_types',
     1159                __( 'Show the "Notify me" and "Stop notifying me" links for these post types:', 'publishpress' ),
     1160                [ $this, 'settings_post_types_option' ],
     1161                $this->module->options_group_name,
     1162                $this->module->options_group_name . '_general'
     1163            );
     1164
     1165            add_settings_field(
     1166                'email_from',
     1167                __( 'Email from:', 'publishpress' ),
     1168                [ $this, 'settings_email_from_option' ],
     1169                $this->module->options_group_name,
     1170                $this->module->options_group_name . '_general'
     1171            );
     1172
     1173            add_settings_field(
     1174                'notify_author_by_default',
     1175                __( 'Always notify the author of the content:', 'publishpress' ),
     1176                [ $this, 'settings_notify_author_by_default_option' ],
     1177                $this->module->options_group_name,
     1178                $this->module->options_group_name . '_general'
     1179            );
     1180
     1181            add_settings_field(
     1182                'notify_current_user_by_default',
     1183                __( 'Always notify users who have edited the content:', 'publishpress' ),
     1184                [ $this, 'settings_notify_current_user_by_default_option' ],
     1185                $this->module->options_group_name,
     1186                $this->module->options_group_name . '_general'
     1187            );
     1188        }
     1189
     1190        /**
     1191         * Chose the post types for notifications
     1192         *
     1193         * @since 0.7
     1194         */
     1195        public function settings_post_types_option() {
     1196            global $publishpress;
     1197            $publishpress->settings->helper_option_custom_post_type( $this->module );
     1198        }
     1199
     1200        public function get_email_from() {
     1201            if ( ! isset( $this->module->options->email_from_name ) ) {
     1202                $name = get_bloginfo( 'name' );
     1203            } else {
     1204                $name = $this->module->options->email_from_name;
     1205            }
     1206
     1207            if ( ! isset( $this->module->options->email_from ) ) {
     1208                $email = get_bloginfo( 'admin_email' );
     1209            } else {
     1210                $email = $this->module->options->email_from;
     1211            }
     1212
     1213            return [
     1214                'name'  => $name,
     1215                'email' => $email,
     1216            ];
     1217        }
     1218
     1219        /**
     1220         * Field to customize the email for the "email from".
     1221         */
     1222        public function settings_email_from_option() {
     1223            $email_from = $this->get_email_from();
     1224
     1225            echo '<input
    13411226                    id="' . $this->module->slug . '_email_from_name"
    13421227                    type="text"
    13431228                    style="min-width: 300px"
    1344                     placeholder="' . get_bloginfo('name') . '"
     1229                    placeholder="' . get_bloginfo( 'name' ) . '"
    13451230                    name="' . $this->module->options_group_name . '[email_from_name]"
    13461231                    value="' . $email_from['name'] . '" />
    13471232                </label>';
    1348             echo '<br />';
    1349             echo '<input
     1233            echo '<br />';
     1234            echo '<input
    13501235                    id="' . $this->module->slug . '_email_from"
    13511236                    type="email"
    13521237                    style="min-width: 300px"
    1353                     placeholder="' . get_bloginfo('admin_email') . '"
     1238                    placeholder="' . get_bloginfo( 'admin_email' ) . '"
    13541239                    name="' . $this->module->options_group_name . '[email_from]"
    13551240                    value="' . $email_from['email'] . '" />
    13561241                </label>';
    1357         }
    1358 
    1359         /**
    1360          * Field to choose between auto select author for notifications.
    1361          */
    1362         public function settings_notify_author_by_default_option()
    1363         {
    1364             $checked = '1';
    1365             if (isset($this->module->options->notify_author_by_default))
    1366             {
    1367                 $checked = $this->module->options->notify_author_by_default;
    1368             }
    1369 
    1370             $checked = (bool)$checked ? 'checked="checked"' : '';
    1371 
    1372             echo '<input
     1242        }
     1243
     1244        /**
     1245         * Field to choose between auto select author for notifications.
     1246         */
     1247        public function settings_notify_author_by_default_option() {
     1248            $checked = '1';
     1249            if ( isset( $this->module->options->notify_author_by_default ) ) {
     1250                $checked = $this->module->options->notify_author_by_default;
     1251            }
     1252
     1253            $checked = (bool) $checked ? 'checked="checked"' : '';
     1254
     1255            echo '<input
    13731256                    id="' . $this->module->slug . '_notify_author_by_default"
    13741257                    type="checkbox"
    13751258                    name="' . $this->module->options_group_name . '[notify_author_by_default]"
    13761259                    value="1" ' . $checked . '/>';
    1377         }
    1378 
    1379         /**
    1380          * Field to choose between auto select current user for notifications.
    1381          */
    1382         public function settings_notify_current_user_by_default_option()
    1383         {
    1384             $checked = '1';
    1385             if (isset($this->module->options->notify_current_user_by_default))
    1386             {
    1387                 $checked = $this->module->options->notify_current_user_by_default;
    1388             }
    1389 
    1390             $checked = (bool)$checked ? 'checked="checked"' : '';
    1391 
    1392             echo '<input
     1260        }
     1261
     1262        /**
     1263         * Field to choose between auto select current user for notifications.
     1264         */
     1265        public function settings_notify_current_user_by_default_option() {
     1266            $checked = '1';
     1267            if ( isset( $this->module->options->notify_current_user_by_default ) ) {
     1268                $checked = $this->module->options->notify_current_user_by_default;
     1269            }
     1270
     1271            $checked = (bool) $checked ? 'checked="checked"' : '';
     1272
     1273            echo '<input
    13931274                    id="' . $this->module->slug . '_notify_current_user_by_default"
    13941275                    type="checkbox"
    13951276                    name="' . $this->module->options_group_name . '[notify_current_user_by_default]"
    13961277                    value="1" ' . $checked . '/>';
    1397         }
    1398 
    1399         /**
    1400          * Validate our user input as the settings are being saved
    1401          *
    1402          * @since 0.7
    1403          */
    1404         public function settings_validate($new_options)
    1405         {
    1406 
    1407             // Whitelist validation for the post type options
    1408             if (!isset($new_options['post_types']))
    1409             {
    1410                 $new_options['post_types'] = array();
    1411             }
    1412             $new_options['post_types'] = $this->clean_post_type_options($new_options['post_types'], $this->module->post_type_support);
    1413 
    1414             if (isset($new_options['email_from']))
    1415             {
    1416                 $new_options['email_from_name'] = filter_var($new_options['email_from_name'], FILTER_SANITIZE_STRING);
    1417                 $new_options['email_from']      = filter_var($new_options['email_from'], FILTER_SANITIZE_EMAIL);
    1418             }
    1419 
    1420 
    1421             if (isset($new_options['notify_author_by_default']))
    1422             {
    1423                 $new_options['notify_author_by_default'] = (bool)$new_options['notify_author_by_default'] ? '1' : '0';
    1424             } else
    1425             {
    1426                 $new_options['notify_author_by_default'] = '0';
    1427             }
    1428 
    1429 
    1430             if (isset($new_options['notify_current_user_by_default']))
    1431             {
    1432                 $new_options['notify_current_user_by_default'] = (bool)$new_options['notify_current_user_by_default'] ? '1' : '0';
    1433             } else
    1434             {
    1435                 $new_options['notify_current_user_by_default'] = '0';
    1436             }
    1437 
    1438             return $new_options;
    1439         }
    1440 
    1441         /**
    1442          * Settings page for notifications
    1443          *
    1444          * @since 0.7
    1445          */
    1446         public function print_configure_view()
    1447         {
    1448             settings_fields($this->module->options_group_name);
    1449             do_settings_sections($this->module->options_group_name);
    1450         }
    1451 
    1452         /**
    1453          * Gets a simple phrase containing the formatted date and time that the post is scheduled for.
    1454          *
    1455          * @since 0.8
    1456          *
    1457          * @param  obj $post Post object
    1458          * @return str    $scheduled_datetime The scheduled datetime in human-readable format
    1459          */
    1460         private function get_scheduled_datetime($post)
    1461         {
    1462             $scheduled_ts = strtotime($post->post_date);
    1463 
    1464             $date = date_i18n(get_option('date_format'), $scheduled_ts);
    1465             $time = date_i18n(get_option('time_format'), $scheduled_ts);
    1466 
    1467             return sprintf(__('%1$s at %2$s', 'publishpress'), $date, $time);
    1468         }
    1469 
    1470         public function send_notification_status_update($args)
    1471         {
    1472             $new_status = $args['new_status'];
    1473             $old_status = $args['old_status'];
    1474             $post       = $args['post'];
    1475 
    1476             // Get current user
    1477             $current_user = wp_get_current_user();
    1478 
    1479             $post_author = get_userdata($post->post_author);
    1480             //$duedate = $publishpress->post_metadata->get_post_meta( $post->ID, 'duedate', true );
    1481 
    1482             $blogname = get_option('blogname');
    1483 
    1484             $body = '';
    1485 
    1486             $post_id    = $post->ID;
    1487             $post_title = pp_draft_or_post_title($post_id);
    1488             $post_type  = get_post_type_object($post->post_type)->labels->singular_name;
    1489 
    1490             if (0 != $current_user->ID)
    1491             {
    1492                 $current_user_display_name = $current_user->display_name;
    1493                 $current_user_email        = sprintf('(%s )', $current_user->user_email);
    1494             } else
    1495             {
    1496                 $current_user_display_name = __('WordPress Scheduler', 'publishpress');
    1497                 $current_user_email        = '';
    1498             }
    1499 
    1500             // Email subject and first line of body
    1501             // Set message subjects according to what action is being taken on the Post
    1502             if ($old_status == 'new' || $old_status == 'auto-draft')
    1503             {
    1504                 /* translators: 1: site name, 2: post type, 3. post title */
    1505                 $subject = sprintf(__('[%1$s] New %2$s Created: "%3$s"', 'publishpress'), $blogname, $post_type, $post_title);
    1506                 /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
    1507                 $body .= sprintf(__('A new %1$s (#%2$s "%3$s" ) was created by %4$s %5$s', 'publishpress'), $post_type, $post_id, $post_title, $current_user->display_name, $current_user->user_email) . "\r\n";
    1508             } else if ($new_status == 'trash')
    1509             {
    1510                 /* translators: 1: site name, 2: post type, 3. post title */
    1511                 $subject = sprintf(__('[%1$s] %2$s Trashed: "%3$s"', 'publishpress'), $blogname, $post_type, $post_title);
    1512                 /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
    1513                 $body .= sprintf(__('%1$s #%2$s "%3$s" was moved to the trash by %4$s %5$s', 'publishpress'), $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email) . "\r\n";
    1514             } else if ($old_status == 'trash')
    1515             {
    1516                 /* translators: 1: site name, 2: post type, 3. post title */
    1517                 $subject = sprintf(__('[%1$s] %2$s Restored (from Trash ): "%3$s"', 'publishpress'), $blogname, $post_type, $post_title);
    1518                 /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
    1519                 $body .= sprintf(__('%1$s #%2$s "%3$s" was restored from trash by %4$s %5$s', 'publishpress'), $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email) . "\r\n";
    1520             } else if ($new_status == 'future')
    1521             {
    1522                 /* translators: 1: site name, 2: post type, 3. post title */
    1523                 $subject = sprintf(__('[%1$s] %2$s Scheduled: "%3$s"'), $blogname, $post_type, $post_title);
    1524                 /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email 6. scheduled date  */
    1525                 $body .= sprintf(__('%1$s #%2$s "%3$s" was scheduled by %4$s %5$s.  It will be published on %6$s'), $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email, $this->get_scheduled_datetime($post)) . "\r\n";
    1526             } else if ($new_status == 'publish')
    1527             {
    1528                 /* translators: 1: site name, 2: post type, 3. post title */
    1529                 $subject = sprintf(__('[%1$s] %2$s Published: "%3$s"', 'publishpress'), $blogname, $post_type, $post_title);
    1530                 /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
    1531                 $body .= sprintf(__('%1$s #%2$s "%3$s" was published by %4$s %5$s', 'publishpress'), $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email) . "\r\n";
    1532             } else if ($old_status == 'publish')
    1533             {
    1534                 /* translators: 1: site name, 2: post type, 3. post title */
    1535                 $subject = sprintf(__('[%1$s] %2$s Unpublished: "%3$s"', 'publishpress'), $blogname, $post_type, $post_title);
    1536                 /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
    1537                 $body .= sprintf(__('%1$s #%2$s "%3$s" was unpublished by %4$s %5$s', 'publishpress'), $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email) . "\r\n";
    1538             } else
    1539             {
    1540                 /* translators: 1: site name, 2: post type, 3. post title */
    1541                 $subject = sprintf(__('[%1$s] %2$s Status Changed for "%3$s"', 'publishpress'), $blogname, $post_type, $post_title);
    1542                 /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
    1543                 $body .= sprintf(__('Status was changed for %1$s #%2$s "%3$s" by %4$s %5$s', 'publishpress'), $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email) . "\r\n";
    1544             }
    1545 
    1546             /* translators: 1: date, 2: time, 3: timezone */
    1547             $body .= sprintf(__('This action was taken on %1$s at %2$s %3$s', 'publishpress'), date_i18n(get_option('date_format')), date_i18n(get_option('time_format')), get_option('timezone_string')) . "\r\n";
    1548 
    1549             $old_status_friendly_name = $this->get_post_status_friendly_name($old_status);
    1550             $new_status_friendly_name = $this->get_post_status_friendly_name($new_status);
    1551 
    1552             // Email body
    1553             $body .= "\r\n";
    1554             /* translators: 1: old status, 2: new status */
    1555             $body .= sprintf(__('%1$s => %2$s', 'publishpress'), $old_status_friendly_name, $new_status_friendly_name);
    1556             $body .= "\r\n\r\n";
    1557 
    1558             $body .= "--------------------\r\n\r\n";
    1559 
    1560             $body .= sprintf(__('== %s Details ==', 'publishpress'), $post_type) . "\r\n";
    1561             $body .= sprintf(__('Title: %s', 'publishpress'), $post_title) . "\r\n";
    1562             if (!empty($post_author))
    1563             {
    1564                 /* translators: 1: author name, 2: author email */
    1565                 $body .= sprintf(__('Author: %1$s (%2$s )', 'publishpress'), $post_author->display_name, $post_author->user_email) . "\r\n";
    1566             }
    1567 
    1568             $admin_path = 'post.php?post=' . $post_id . '&action=edit';
    1569             $edit_link  = htmlspecialchars_decode(admin_url($admin_path));
    1570             if ($new_status != 'publish')
    1571             {
    1572                 $view_link = add_query_arg(array('preview' => 'true'), wp_get_shortlink($post_id));
    1573             } else
    1574             {
    1575                 $view_link = htmlspecialchars_decode(get_permalink($post_id));
    1576             }
    1577             $body .= "\r\n";
    1578             $body .= __('== Actions ==', 'publishpress') . "\r\n";
    1579             $body .= sprintf(__('Add editorial comment: %s', 'publishpress'), $edit_link . '#editorialcomments/add') . "\r\n";
    1580             $body .= sprintf(__('Edit: %s', 'publishpress'), $edit_link) . "\r\n";
    1581             $body .= sprintf(__('View: %s', 'publishpress'), $view_link) . "\r\n";
    1582 
    1583             $body .= $this->get_notification_footer($post);
    1584 
    1585             $this->send_email('status-change', $post, $subject, $body);
    1586         }
    1587 
    1588         public function send_notification_comment($args)
    1589         {
    1590             /* translators: 1: blog name, 2: post title */
    1591             $subject = sprintf(__('[%1$s] New Editorial Comment: "%2$s"', 'publishpress'), $args['blogname'], $args['post_title']);
    1592 
    1593             /* translators: 1: post id, 2: post title, 3. post type */
    1594             $body = sprintf(__('A new editorial comment was added to %3$s #%1$s "%2$s"', 'publishpress'), $args['post_id'], $args['post_title'], $args['post_type']) . "\r\n\r\n";
    1595             /* translators: 1: comment author, 2: author email, 3: date, 4: time */
    1596             $body .= sprintf(__('%1$s (%2$s ) said on %3$s at %4$s:', 'publishpress'), $args['current_user']->display_name, $args['current_user']->user_email, mysql2date(get_option('date_format'), $args['comment']->comment_date), mysql2date(get_option('time_format'), $args['comment']->comment_date)) . "\r\n";
    1597             $body .= "\r\n" . $args['comment']->comment_content . "\r\n";
    1598 
    1599             // @TODO: mention if it was a reply
    1600             /*
    1601             if( $parent ) {
    1602 
    1603             }
    1604             */
    1605 
    1606             $body .= "\r\n--------------------\r\n";
    1607 
    1608             $admin_path = 'post.php?post=' . $args['post_id'] . '&action=edit';
    1609             $edit_link  = htmlspecialchars_decode(admin_url($admin_path));
    1610             $view_link = htmlspecialchars_decode(get_permalink($args['post_id']));
    1611 
    1612             $body .= "\r\n";
    1613             $body .= __('== Actions ==', 'publishpress') . "\r\n";
    1614             $body .= sprintf(__('Reply: %s', 'publishpress'), $edit_link . '#editorialcomments/reply/' . $args['comment']->comment_ID) . "\r\n";
    1615             $body .= sprintf(__('Add editorial comment: %s', 'publishpress'), $edit_link . '#editorialcomments/add') . "\r\n";
    1616             $body .= sprintf(__('Edit: %s', 'publishpress'), $edit_link) . "\r\n";
    1617             $body .= sprintf(__('View: %s', 'publishpress'), $view_link) . "\r\n";
    1618 
    1619             $body .= "\r\n" . sprintf(__('You can see all editorial comments on this %s here: ', 'publishpress'), $args['post_type']) . "\r\n";
    1620             $body .= $edit_link . "#editorialcomments" . "\r\n\r\n";
    1621 
    1622             $body .= $this->get_notification_footer($args['post']);
    1623 
    1624             $this->send_email('comment', $args['post'], $subject, $body);
    1625         }
    1626     }
     1278        }
     1279
     1280        /**
     1281         * Validate our user input as the settings are being saved
     1282         *
     1283         * @since 0.7
     1284         */
     1285        public function settings_validate( $new_options ) {
     1286
     1287            // Whitelist validation for the post type options
     1288            if ( ! isset( $new_options['post_types'] ) ) {
     1289                $new_options['post_types'] = [];
     1290            }
     1291            $new_options['post_types'] = $this->clean_post_type_options( $new_options['post_types'],
     1292                $this->module->post_type_support );
     1293
     1294            if ( isset( $new_options['email_from'] ) ) {
     1295                $new_options['email_from_name'] = filter_var( $new_options['email_from_name'], FILTER_SANITIZE_STRING );
     1296                $new_options['email_from']      = filter_var( $new_options['email_from'], FILTER_SANITIZE_EMAIL );
     1297            }
     1298
     1299
     1300            if ( isset( $new_options['notify_author_by_default'] ) ) {
     1301                $new_options['notify_author_by_default'] = (bool) $new_options['notify_author_by_default'] ? '1' : '0';
     1302            } else {
     1303                $new_options['notify_author_by_default'] = '0';
     1304            }
     1305
     1306
     1307            if ( isset( $new_options['notify_current_user_by_default'] ) ) {
     1308                $new_options['notify_current_user_by_default'] = (bool) $new_options['notify_current_user_by_default'] ? '1' : '0';
     1309            } else {
     1310                $new_options['notify_current_user_by_default'] = '0';
     1311            }
     1312
     1313            return $new_options;
     1314        }
     1315
     1316        /**
     1317         * Settings page for notifications
     1318         *
     1319         * @since 0.7
     1320         */
     1321        public function print_configure_view() {
     1322            settings_fields( $this->module->options_group_name );
     1323            do_settings_sections( $this->module->options_group_name );
     1324        }
     1325
     1326        /**
     1327         * Gets a simple phrase containing the formatted date and time that the post is scheduled for.
     1328         *
     1329         * @since 0.8
     1330         *
     1331         * @param  obj $post Post object
     1332         *
     1333         * @return str    $scheduled_datetime The scheduled datetime in human-readable format
     1334         */
     1335        private function get_scheduled_datetime( $post ) {
     1336            $scheduled_ts = strtotime( $post->post_date );
     1337
     1338            $date = date_i18n( get_option( 'date_format' ), $scheduled_ts );
     1339            $time = date_i18n( get_option( 'time_format' ), $scheduled_ts );
     1340
     1341            return sprintf( __( '%1$s at %2$s', 'publishpress' ), $date, $time );
     1342        }
     1343
     1344        public function send_notification_status_update( $args ) {
     1345            $new_status = $args['new_status'];
     1346            $old_status = $args['old_status'];
     1347            $post       = $args['post'];
     1348
     1349            // Get current user
     1350            $current_user = wp_get_current_user();
     1351
     1352            $post_author = get_userdata( $post->post_author );
     1353            //$duedate = $publishpress->post_metadata->get_post_meta( $post->ID, 'duedate', true );
     1354
     1355            $blogname = get_option( 'blogname' );
     1356
     1357            $body = '';
     1358
     1359            $post_id    = $post->ID;
     1360            $post_title = pp_draft_or_post_title( $post_id );
     1361            $post_type  = get_post_type_object( $post->post_type )->labels->singular_name;
     1362
     1363            if ( 0 != $current_user->ID ) {
     1364                $current_user_display_name = $current_user->display_name;
     1365                $current_user_email        = sprintf( '(%s )', $current_user->user_email );
     1366            } else {
     1367                $current_user_display_name = __( 'WordPress Scheduler', 'publishpress' );
     1368                $current_user_email        = '';
     1369            }
     1370
     1371            // Email subject and first line of body
     1372            // Set message subjects according to what action is being taken on the Post
     1373            if ( $old_status == 'new' || $old_status == 'auto-draft' ) {
     1374                /* translators: 1: site name, 2: post type, 3. post title */
     1375                $subject = sprintf( __( '[%1$s] New %2$s Created: "%3$s"', 'publishpress' ), $blogname, $post_type,
     1376                    $post_title );
     1377                /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
     1378                $body .= sprintf( __( 'A new %1$s (#%2$s "%3$s" ) was created by %4$s %5$s', 'publishpress' ),
     1379                        $post_type, $post_id, $post_title, $current_user->display_name,
     1380                        $current_user->user_email ) . "\r\n";
     1381            } elseif ( $new_status == 'trash' ) {
     1382                /* translators: 1: site name, 2: post type, 3. post title */
     1383                $subject = sprintf( __( '[%1$s] %2$s Trashed: "%3$s"', 'publishpress' ), $blogname, $post_type,
     1384                    $post_title );
     1385                /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
     1386                $body .= sprintf( __( '%1$s #%2$s "%3$s" was moved to the trash by %4$s %5$s', 'publishpress' ),
     1387                        $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email ) . "\r\n";
     1388            } elseif ( $old_status == 'trash' ) {
     1389                /* translators: 1: site name, 2: post type, 3. post title */
     1390                $subject = sprintf( __( '[%1$s] %2$s Restored (from Trash ): "%3$s"', 'publishpress' ), $blogname,
     1391                    $post_type, $post_title );
     1392                /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
     1393                $body .= sprintf( __( '%1$s #%2$s "%3$s" was restored from trash by %4$s %5$s', 'publishpress' ),
     1394                        $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email ) . "\r\n";
     1395            } elseif ( $new_status == 'future' ) {
     1396                /* translators: 1: site name, 2: post type, 3. post title */
     1397                $subject = sprintf( __( '[%1$s] %2$s Scheduled: "%3$s"' ), $blogname, $post_type, $post_title );
     1398                /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email 6. scheduled date  */
     1399                $body .= sprintf( __( '%1$s #%2$s "%3$s" was scheduled by %4$s %5$s.  It will be published on %6$s' ),
     1400                        $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email,
     1401                        $this->get_scheduled_datetime( $post ) ) . "\r\n";
     1402            } elseif ( $new_status == 'publish' ) {
     1403                /* translators: 1: site name, 2: post type, 3. post title */
     1404                $subject = sprintf( __( '[%1$s] %2$s Published: "%3$s"', 'publishpress' ), $blogname, $post_type,
     1405                    $post_title );
     1406                /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
     1407                $body .= sprintf( __( '%1$s #%2$s "%3$s" was published by %4$s %5$s', 'publishpress' ), $post_type,
     1408                        $post_id, $post_title, $current_user_display_name, $current_user_email ) . "\r\n";
     1409            } elseif ( $old_status == 'publish' ) {
     1410                /* translators: 1: site name, 2: post type, 3. post title */
     1411                $subject = sprintf( __( '[%1$s] %2$s Unpublished: "%3$s"', 'publishpress' ), $blogname, $post_type,
     1412                    $post_title );
     1413                /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
     1414                $body .= sprintf( __( '%1$s #%2$s "%3$s" was unpublished by %4$s %5$s', 'publishpress' ), $post_type,
     1415                        $post_id, $post_title, $current_user_display_name, $current_user_email ) . "\r\n";
     1416            } else {
     1417                /* translators: 1: site name, 2: post type, 3. post title */
     1418                $subject = sprintf( __( '[%1$s] %2$s Status Changed for "%3$s"', 'publishpress' ), $blogname,
     1419                    $post_type, $post_title );
     1420                /* translators: 1: post type, 2: post id, 3. post title, 4. user name, 5. user email */
     1421                $body .= sprintf( __( 'Status was changed for %1$s #%2$s "%3$s" by %4$s %5$s', 'publishpress' ),
     1422                        $post_type, $post_id, $post_title, $current_user_display_name, $current_user_email ) . "\r\n";
     1423            }
     1424
     1425            /* translators: 1: date, 2: time, 3: timezone */
     1426            $body .= sprintf( __( 'This action was taken on %1$s at %2$s %3$s', 'publishpress' ),
     1427                    date_i18n( get_option( 'date_format' ) ), date_i18n( get_option( 'time_format' ) ),
     1428                    get_option( 'timezone_string' ) ) . "\r\n";
     1429
     1430            $old_status_friendly_name = $this->get_post_status_friendly_name( $old_status );
     1431            $new_status_friendly_name = $this->get_post_status_friendly_name( $new_status );
     1432
     1433            // Email body
     1434            $body .= "\r\n";
     1435            /* translators: 1: old status, 2: new status */
     1436            $body .= sprintf( __( '%1$s => %2$s', 'publishpress' ), $old_status_friendly_name,
     1437                $new_status_friendly_name );
     1438            $body .= "\r\n\r\n";
     1439
     1440            $body .= "--------------------\r\n\r\n";
     1441
     1442            $body .= sprintf( __( '== %s Details ==', 'publishpress' ), $post_type ) . "\r\n";
     1443            $body .= sprintf( __( 'Title: %s', 'publishpress' ), $post_title ) . "\r\n";
     1444            if ( ! empty( $post_author ) ) {
     1445                /* translators: 1: author name, 2: author email */
     1446                $body .= sprintf( __( 'Author: %1$s (%2$s )', 'publishpress' ), $post_author->display_name,
     1447                        $post_author->user_email ) . "\r\n";
     1448            }
     1449
     1450            $admin_path = 'post.php?post=' . $post_id . '&action=edit';
     1451            $edit_link  = htmlspecialchars_decode( admin_url( $admin_path ) );
     1452            if ( $new_status != 'publish' ) {
     1453                $view_link = add_query_arg( [ 'preview' => 'true' ], wp_get_shortlink( $post_id ) );
     1454            } else {
     1455                $view_link = htmlspecialchars_decode( get_permalink( $post_id ) );
     1456            }
     1457            $body .= "\r\n";
     1458            $body .= __( '== Actions ==', 'publishpress' ) . "\r\n";
     1459            $body .= sprintf( __( 'Add editorial comment: %s', 'publishpress' ),
     1460                    $edit_link . '#editorialcomments/add' ) . "\r\n";
     1461            $body .= sprintf( __( 'Edit: %s', 'publishpress' ), $edit_link ) . "\r\n";
     1462            $body .= sprintf( __( 'View: %s', 'publishpress' ), $view_link ) . "\r\n";
     1463
     1464            $body .= $this->get_notification_footer( $post );
     1465
     1466            $this->send_email( 'status-change', $post, $subject, $body );
     1467        }
     1468
     1469        public function send_notification_comment( $args ) {
     1470            /* translators: 1: blog name, 2: post title */
     1471            $subject = sprintf( __( '[%1$s] New Editorial Comment: "%2$s"', 'publishpress' ), $args['blogname'],
     1472                $args['post_title'] );
     1473
     1474            /* translators: 1: post id, 2: post title, 3. post type */
     1475            $body = sprintf( __( 'A new editorial comment was added to %3$s #%1$s "%2$s"', 'publishpress' ),
     1476                    $args['post_id'], $args['post_title'], $args['post_type'] ) . "\r\n\r\n";
     1477            /* translators: 1: comment author, 2: author email, 3: date, 4: time */
     1478            $body .= sprintf( __( '%1$s (%2$s ) said on %3$s at %4$s:', 'publishpress' ),
     1479                    $args['current_user']->display_name, $args['current_user']->user_email,
     1480                    mysql2date( get_option( 'date_format' ), $args['comment']->comment_date ),
     1481                    mysql2date( get_option( 'time_format' ), $args['comment']->comment_date ) ) . "\r\n";
     1482            $body .= "\r\n" . $args['comment']->comment_content . "\r\n";
     1483
     1484            // @TODO: mention if it was a reply
     1485            /*
     1486            if( $parent ) {
     1487
     1488            }
     1489            */
     1490
     1491            $body .= "\r\n--------------------\r\n";
     1492
     1493            $admin_path = 'post.php?post=' . $args['post_id'] . '&action=edit';
     1494            $edit_link  = htmlspecialchars_decode( admin_url( $admin_path ) );
     1495            $view_link  = htmlspecialchars_decode( get_permalink( $args['post_id'] ) );
     1496
     1497            $body .= "\r\n";
     1498            $body .= __( '== Actions ==', 'publishpress' ) . "\r\n";
     1499            $body .= sprintf( __( 'Reply: %s', 'publishpress' ),
     1500                    $edit_link . '#editorialcomments/reply/' . $args['comment']->comment_ID ) . "\r\n";
     1501            $body .= sprintf( __( 'Add editorial comment: %s', 'publishpress' ),
     1502                    $edit_link . '#editorialcomments/add' ) . "\r\n";
     1503            $body .= sprintf( __( 'Edit: %s', 'publishpress' ), $edit_link ) . "\r\n";
     1504            $body .= sprintf( __( 'View: %s', 'publishpress' ), $view_link ) . "\r\n";
     1505
     1506            $body .= "\r\n" . sprintf( __( 'You can see all editorial comments on this %s here: ', 'publishpress' ),
     1507                    $args['post_type'] ) . "\r\n";
     1508            $body .= $edit_link . "#editorialcomments" . "\r\n\r\n";
     1509
     1510            $body .= $this->get_notification_footer( $args['post'] );
     1511
     1512            $this->send_email( 'comment', $args['post'], $subject, $body );
     1513        }
     1514    }
    16271515}
  • publishpress/trunk/modules/roles/roles.php

    r1860640 r1871614  
    150150
    151151            add_action('profile_update', [$this, 'action_profile_update'], 10, 2);
    152             add_action('user_register', [$this, 'action_profile_update'], 10);
     152            add_action('user_register', [$this, 'action_profile_update'], 9);
    153153
    154154            if ($this->wasPublishPressInstalledBefore()) {
  • publishpress/trunk/publishpress.php

    r1860640 r1871614  
    66 * Author: PublishPress
    77 * Author URI: https://publishpress.com
    8  * Version: 1.12.0
     8 * Version: 1.12.1
    99 * Text Domain: publishpress
    1010 * Domain Path: /languages
  • publishpress/trunk/readme.txt

    r1860640 r1871614  
    66Requires at least: 4.6
    77Requires PHP: 5.4
    8 Tested up to: 4.9.4
    9 Stable tag: 1.12.0
     8Tested up to: 4.9.5
     9Stable tag: 1.12.1
    1010License: GPLv2 or later
    1111License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    133133The format is based on [Keep a Changelog](http://keepachangelog.com/)
    134134and this project adheres to [Semantic Versioning](http://semver.org/).
     135
     136= [1.12.1] - 2018-05-09  =
     137
     138*Fixed:*
     139
     140* Fixed PHP strict warning about trait and a redefined property;
     141* Fixed duplicated notifications on some scenarios;
     142
     143*Changed:*
     144
     145* Increased the priority of the hook user_register to have the multiple roles loaded and available for add-ons;
    135146
    136147= [1.12.0] - 2018-04-18  =
Note: See TracChangeset for help on using the changeset viewer.