Making WordPress.org

Ticket #212: 212.2.diff

File 212.2.diff, 15.6 KB (added by iandunn, 12 years ago)
  • sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-organizer-reminders/bootstrap.php

     
     1<?php
     2
     3/*
     4 * Plugin Name: WordCamp Organizer Reminders
     5 * Description: Automatically e-mail WordCamp organizers with various reminders at specified intervals.
     6 * Version:     0.1
     7 * Author:      Ian Dunn
     8 */
     9
     10require_once( __DIR__ . '/wcor-mailer.php' );
     11$GLOBALS['WCOR_Mailer'] = new WCOR_Mailer();
     12register_activation_hook(   __FILE__, array( $GLOBALS['WCOR_Mailer'], 'activate' ) );
     13register_deactivation_hook( __FILE__, array( $GLOBALS['WCOR_Mailer'], 'deactivate' ) );
     14
     15require_once( __DIR__ . '/wcor-reminder.php' );
     16$GLOBALS['WCOR_Reminder'] = new WCOR_Reminder();
     17 No newline at end of file
  • sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-organizer-reminders/wcor-mailer.php

     
     1<?php
     2
     3/**
     4 * Sends e-mails at time-based intervals and triggers
     5 * @package WordCampOrganizerReminders
     6 */
     7class WCOR_Mailer {
     8       
     9        /**
     10         * Constructor
     11         */
     12        public function __construct() {
     13                add_action( 'wcor_send_timed_emails', array( $this, 'send_timed_emails' ) );
     14                add_action( 'post_updated',           array( $this, 'send_trigger_added_to_schedule' ), 10, 2 );
     15        }
     16
     17        /**
     18         * Schedule cron job when plugin is activated 
     19         */
     20        public function activate() {
     21                if ( wp_next_scheduled( 'wcor_send_timed_emails' ) === false ) {
     22                        wp_schedule_event(
     23                                current_time( 'timestamp' ),
     24                                'daily',
     25                                'wcor_send_timed_emails'
     26                        );
     27                }
     28        }
     29       
     30        /**
     31         * Clear cron job when plugin is deactivated
     32         */
     33        public function deactivate() {
     34                wp_clear_scheduled_hook( 'wcor_send_timed_emails' );
     35        }
     36
     37        /**
     38         * Wrapper for wp_mail() that adds our headers
     39         *
     40         * We want to make sure that replies go to support@wordcamp.org, rather than the fake address that WordPress sends from, but
     41         * we don't want to be flagged as spam for forging the From header, so we set the Sender header.
     42         * @see http://stackoverflow.com/q/4728393/450127
     43         *
     44         * @param string $to
     45         * @param string $subject
     46         * @param string $body
     47         * @return bool
     48         */
     49        protected function mail( $to, $subject, $body ) {
     50                $headers = array(
     51                        'From: WordCamp Central <support@wordcamp.org>',
     52                        'Sender: wordpress@' . strtolower( $_SERVER['SERVER_NAME'] )
     53                );
     54
     55                // todo replace %%organizer_name%% with their name, etc?
     56                        // maybe use shortcodes so it happens automatically?
     57                        // maybe move other universal stuff here, like the checks for if the email has been sent or not
     58               
     59                // maybe move the subject prefix here, but then we'd have to know what the camp name is. but will need that for the shortcodes above too?
     60               
     61                return wp_mail( $to, $subject, $body, $headers );
     62        }
     63
     64        /**
     65         * Send e-mails that are scheduled to go out at a specific time (e.g., 3 days before the camp)
     66         */
     67        public function send_timed_emails() {
     68                $recent_or_upcoming_wordcamps = get_posts( array(
     69                        'posts_per_page'  => -1,
     70                        'post_type'       => 'wordcamp',
     71                        'meta_query'      => array(
     72                                array(
     73                                        'key'     => 'Start Date (YYYY-mm-dd)',
     74                                        'value'   => strtotime( 'now - 3 months' ),
     75                                        'compare' => '>=',
     76                                )
     77                        )
     78                ) );
     79               
     80                $reminder_emails = get_posts( array(
     81                        'posts_per_page' => -1,
     82                        'post_type'      => WCOR_Reminder::POST_TYPE_SLUG
     83                ) );
     84               
     85                foreach ( $recent_or_upcoming_wordcamps as $wordcamp ) {
     86                        $organizers_email = get_post_meta( $wordcamp->ID, 'E-mail Address', true );
     87                        $sent_email_ids   = (array) get_post_meta( $wordcamp->ID, 'wcor_sent_email_ids', true );
     88
     89                        if ( ! is_email( $organizers_email ) ) {
     90                                continue;
     91                        }
     92                       
     93                        foreach ( $reminder_emails as $email ) {
     94
     95                                echo '<br>'. $wordcamp->post_title .' - '. $email->post_title .': ';
     96                               
     97                                if ( $this->timed_email_is_ready_to_send( $wordcamp, $email, $sent_email_ids ) ) {
     98                                        /*$this->mail(
     99                                                $organizers_email,
     100                                                $wordcamp->post_title .' Reminder: ' . $email->post_title,              // todo apply filters?
     101                                                $email->post_content    // todo apply filters?
     102                                        );
     103                                       
     104                                        $sent_email_ids[] = $email->ID;
     105                                        update_post_meta( $wordcamp->ID, 'wcor_sent_email_ids', $sent_email_ids );
     106                                        sleep( 1 ); // don't send e-mails too fast, or it might increase the risk of being flagged as spam
     107                                        */
     108                                       
     109                                        echo 'yes';
     110                                }
     111                               
     112                                else echo 'no';
     113                        }
     114                }
     115        }
     116
     117        /**
     118         * Determines if a time-based e-mail is ready to be sent to a WordCamp
     119         *
     120         * E-mails should be sent if the current date matches the date that the e-mail is scheduled to be sent (e.g., 3 days before the camp starts).
     121         *
     122         * One exception to that is if a camp is added later than expected (e.g., we start sending e-mails 4 months before the start date, but a camp
     123         * isn't scheduled until 2 months before the start). When that happens, we want to send all the e-mails that they've missed.
     124         *
     125         * An exception to that exception is that we don't want to send e-mails to camps that have already been sent those e-mails manually, before we
     126         * started sending them automatically.
     127         * @todo this exception will no longer be relevant in a few months, and can be removed at that time. Approximately January 15th, 2014.
     128         *       
     129         * @param WP_Post $wordcamp
     130         * @param WP_Post $email
     131         * @param array   $sent_email_ids The IDs of emails that have already been sent to the $wordcamp post
     132         * @return bool
     133         */
     134        protected function timed_email_is_ready_to_send( $wordcamp, $email, $sent_email_ids ) {
     135                $ready      = false;
     136                $send_when  = get_post_meta( $email->ID, 'wcor_send_when', true );
     137                $start_date = get_post_meta( $wordcamp->ID, 'Start Date (YYYY-mm-dd)', true );
     138                $end_date   = get_post_meta( $wordcamp->ID, 'End Date (YYYY-mm-dd)', true );
     139               
     140                if ( ! $end_date ) {
     141                        $end_date = $start_date;
     142                }
     143               
     144                if ( ! in_array( $email->ID, $sent_email_ids ) ) {
     145                        if ( 'wcor_send_before' == $send_when ) {
     146                                $days_before = absint( get_post_meta( $email->ID, 'wcor_send_days_before', true ) );
     147                               
     148                                if ( $days_before ) {
     149                                        $send_date = $start_date - ( $days_before * DAY_IN_SECONDS );
     150                                       
     151                                        if ( $send_date <= current_time( 'timestamp' ) ) {
     152                                                $ready = true;
     153                                        }
     154                                }
     155                        } elseif ( 'wcor_send_after' == $send_when ) {
     156                                $days_after = absint( get_post_meta( $email->ID, 'wcor_send_days_after', true ) );
     157
     158                                if ( $days_after ) {
     159                                        $send_date = $end_date + ( $days_after * DAY_IN_SECONDS );
     160                                       
     161                                        if ( $send_date <= current_time( 'timestamp' ) ) {
     162                                                $ready = true;
     163                                        }
     164                                }
     165                        }
     166
     167                        if ( $send_date <= strtotime( 'October 15th, 2013' ) ) {        // todo update to the day before you deploy the code
     168                                // Assume it was already sent manually before this plugin was activated
     169                                $ready = false;
     170                        }
     171                }
     172               
     173                // todo write unit tests for this function?
     174                        // hard to do b/c have to mock get_post_meta and current_time()
     175               
     176                return $ready;
     177        }
     178
     179        /**
     180         * Sends e-mails hooked to the wcor_added_to_schedule trigger.
     181         *
     182         * This fires when a WordCamp is added to the schedule (i.e., when they set the start date in their `wordcamp` post).
     183         *
     184         * Since Core doesn't support revisions on post meta, we're not actually checking to see if the start date was added during
     185         * the current post update, but just that it has a start data. By itself, that would lead to the e-mail being sent every time
     186         * the post is updated, but to avoid that we're checking the `wcor_sent_email_id` post meta for the `wordcamp` post to see if
     187         * we've already sent this particular e-mail in the past.
     188         *
     189         * @param int $post_id
     190         * @param WP_Post $post
     191         */
     192        public function send_trigger_added_to_schedule( $post_id, $post ) {
     193
     194                /* @todo Update time-based code to ignore trigger-based e-mails in multiple places.              */
     195               
     196               
     197               
     198                if ( 'wordcamp' == $post->post_type && 'publish' == $post->post_status ) {
     199                        $start_date       = get_post_meta( $post_id, 'Start Date (YYYY-mm-dd)', true );
     200                        $organizers_email = get_post_meta( $post_id, 'E-mail Address', true );
     201                        $sent_email_ids   = (array) get_post_meta( $post_id, 'wcor_sent_email_ids', true );
     202               
     203                        if ( $start_date && is_email( $organizers_email ) ) {
     204                                $emails = get_posts( array(
     205                                        'posts_per_page' => -1,
     206                                        'post_type'      => WCOR_Reminder::POST_TYPE_SLUG,
     207                                        'meta_query'     => array(
     208                                                array(
     209                                                        'key'    => 'wcor_which_trigger',
     210                                                        'value'  => 'wcor_added_to_schedule',
     211                                                )
     212                                        )
     213                                ) );
     214                               
     215                                foreach( $emails as $email ) {
     216                                        if ( ! in_array( $email->ID, $sent_email_ids ) ) {
     217                                                $this->mail(
     218                                                        $organizers_email,
     219                                                        $post->post_title . ' Reminder: ' . $email->post_title,
     220                                                        $email->post_body
     221                                                );
     222       
     223                                                $sent_email_ids[] = $email->ID;
     224                                                // todo update_post_meta( $post_id, 'wcor_sent_email_ids', $sent_email_ids );
     225                                        }
     226                                }
     227                        }
     228                }
     229        }
     230}
     231 No newline at end of file
  • sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-organizer-reminders/wcor-reminder.php

     
     1<?php
     2
     3/**
     4 * A Custom post type to store the body of the reminder e-mails
     5 * @package WordCampOrganizerReminders
     6 */
     7
     8class WCOR_Reminder {
     9        const POST_TYPE_SLUG = 'organizer-reminder';
     10
     11        /**
     12         * Constructor
     13         */
     14        public function __construct() {
     15                add_action( 'init',                              array( $this, 'register_post_type' ) );
     16                add_action( 'admin_init',                        array( $this, 'add_meta_boxes' ) );
     17                add_action( 'save_post_' . self::POST_TYPE_SLUG, array( $this, 'save_post' ), 10, 2 );
     18        }
     19
     20        /**
     21         * Registers the Reminder post type
     22         */
     23        public function register_post_type() {
     24                $labels = array(
     25                        'name'               => 'Organizer Reminders',
     26                        'singular_name'      => 'Organizer Reminder',
     27                        'add_new'            => 'Add New',
     28                        'add_new_item'       => 'Add New Reminder',
     29                        'edit'               => 'Edit',
     30                        'edit_item'          => 'Edit Reminder',
     31                        'new_item'           => 'New Reminder',
     32                        'view'               => 'View Reminders',
     33                        'view_item'          => 'View Reminder',
     34                        'search_items'       => 'Search Reminders',
     35                        'not_found'          => 'No reminders',
     36                        'not_found_in_trash' => 'No reminders',
     37                        'parent'             => 'Parent Reminder',
     38                );
     39
     40                $params = array(
     41                        'labels'              => $labels,
     42                        'singular_label'      => 'Reminder',
     43                        'public'              => true,
     44                        'exclude_from_search' => true,
     45                        'publicly_queryable'  => false,
     46                        'show_ui'             => true,
     47                        'show_in_nav_menus'   => false,
     48                        'hierarchical'        => false,
     49                        'capability_type'     => 'post',
     50                        'has_archive'         => false,
     51                        'rewrite'             => false,
     52                        'query_var'           => false,
     53                        'supports'            => array( 'title', 'editor', 'author', 'revisions' ),
     54                );
     55               
     56                register_post_type( self::POST_TYPE_SLUG, $params );
     57        }
     58
     59        /**
     60         * Adds meta boxes for the custom post type
     61         */
     62        public function add_meta_boxes() {
     63                add_meta_box(
     64                        'wcor_reminder_details',
     65                        'Reminder Details',
     66                        array( $this, 'markup_reminder_details' ),
     67                        self::POST_TYPE_SLUG,
     68                        'side',
     69                        'default'
     70                );
     71        }
     72
     73        /**
     74         * Builds the markup for the Reminder Details metabox
     75         *
     76         * @param object $post
     77         */
     78        public static function markup_reminder_details( $post ) {
     79                $send_when        = get_post_meta( $post->ID, 'wcor_send_when', true );
     80                $send_days_before = get_post_meta( $post->ID, 'wcor_send_days_before', true );
     81                $send_days_after  = get_post_meta( $post->ID, 'wcor_send_days_after', true );
     82                $which_trigger    = get_post_meta( $post->ID, 'wcor_which_trigger', true );
     83               
     84                ?>
     85               
     86                <p>When should this e-mail be sent?</p>
     87
     88                <table>
     89                        <tbody>
     90                                <tr>
     91                                        <th><input id="wcor_send_before" name="wcor_send_when" type="radio" value="wcor_send_before" <?php checked( $send_when, 'wcor_send_before' ); ?>></th>
     92                                        <td><label for="wcor_send_before">before the camp starts: </label></td>
     93                                        <td>
     94                                                <input id="wcor_send_days_before" name="wcor_send_days_before" type="text" class="small-text" value="<?php echo esc_attr( $send_days_before ); ?>" />
     95                                                <label for="wcor_send_days_before">days</label>
     96                                        </td>
     97                                </tr>
     98
     99                                <tr>
     100                                        <th><input id="wcor_send_after" name="wcor_send_when" type="radio" value="wcor_send_after" <?php checked( $send_when, 'wcor_send_after' ); ?>></th>
     101                                        <td><label for="wcor_send_after">after the camp ends: </label></td>
     102                                        <td>
     103                                                <input id="wcor_send_days_after" name="wcor_send_days_after" type="text" class="small-text" value="<?php echo esc_attr( $send_days_after ); ?>" />
     104                                                <label for="wcor_send_days_after">days</label>
     105                                        </td>
     106                                </tr>
     107
     108                                <tr>
     109                                        <th><input id="wcor_send_trigger" name="wcor_send_when" type="radio" value="wcor_send_trigger" <?php checked( $send_when, 'wcor_send_trigger' ); ?>></th>
     110                                        <td><label for="wcor_send_trigger">on trigger: </label></td>
     111                                        <td>
     112                                                <select name="wcor_which_trigger">
     113                                                        <option value="null" <?php selected( $which_trigger, false ); ?>></option>
     114                                                        <option value="wcor_added_to_schedule" <?php selected( $which_trigger, 'wcor_added_to_schedule' ); ?>>Added to schedule</option>
     115                                                               
     116                                                                <!-- todo maybe make this auto build from array in WCOR_MAILER -->
     117                                                </select>
     118                                        </td>
     119                                </tr>
     120                        </tbody>
     121                </table>
     122
     123                <?php
     124        }
     125
     126        /**
     127         * Checks to make sure the conditions for saving post meta are met
     128         *
     129         * @param int $post_id
     130         * @param object $post
     131         */
     132        public function save_post( $post_id, $post ) {
     133                $ignored_actions = array( 'trash', 'untrash', 'restore' );
     134
     135                if ( isset( $_GET['action'] ) && in_array( $_GET['action'], $ignored_actions ) ) {
     136                        return;
     137                }
     138
     139                if ( ! current_user_can( 'edit_posts', $post_id ) ) {
     140                        return;
     141                }
     142
     143                if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) {
     144                        return;
     145                }
     146               
     147                $this->save_post_meta( $post, $_POST );
     148        }
     149
     150        /**
     151         * Saves the meta data for the reminder post
     152         *
     153         * @param WP_Post $post
     154         * @param array $new_meta
     155         */
     156        protected function save_post_meta( $post, $new_meta ) {
     157                if ( isset( $new_meta['wcor_send_when'] ) ) {
     158                        if ( in_array( $new_meta['wcor_send_when'], array( 'wcor_send_before', 'wcor_send_after', 'wcor_send_trigger' ) ) ) {
     159                                update_post_meta( $post->ID, 'wcor_send_when', $new_meta['wcor_send_when'] );
     160                        }
     161                }
     162
     163                if ( isset( $new_meta['wcor_send_days_before'] ) ) {
     164                        update_post_meta( $post->ID, 'wcor_send_days_before', absint( $new_meta['wcor_send_days_before'] ) );
     165                }
     166
     167                if ( isset( $new_meta['wcor_send_days_after'] ) ) {
     168                        update_post_meta( $post->ID, 'wcor_send_days_after', absint( $new_meta['wcor_send_days_after'] ) );
     169                }
     170
     171                if ( isset( $new_meta['wcor_which_trigger'] ) ) {
     172                        if ( in_array( $new_meta['wcor_which_trigger'], array( 'null', 'wcor_added_to_schedule' ) ) ) { // todo maybe build array dynamically from wcor_mailer
     173                                update_post_meta( $post->ID, 'wcor_which_trigger', $new_meta['wcor_which_trigger'] );
     174                        }
     175                }
     176        }
     177}
     178 No newline at end of file