PluginProbe
Email Post Changes / 0.7
Email Post Changes v0.7
trunk 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.7.1 1.7.2
← All changes | email-post-changes.php +9 -297 0.50.7 View file →
@@ -1,310 +1,22 @@
1 1 <?php
2 2
3 3 /*
4 4 Plugin Name: Email Post Changes
5 -Description: Whenever a change to a post or page is made, those changes are emailed to the blog's admin.
5 +Description: Whenever a change to a post or page is made, those changes are emailed to the email addresses you specify.
6 6 Plugin URI: http://wordpress.org/extend/plugins/email-post-changes/
7 -Version: 0.5
7 +Version: 0.7
8 8 Author: Michael D Adams
9 9 Author URI: http://blogwaffe.com/
10 10 */
11 11
12 -class Email_Post_Changes {
13 - var $defaults;
12 +require_once 'class.email-post-changes.php';
14 13
15 - var $left_post;
16 - var $right_post;
14 +function email_post_changes_action_links( $links ) {
15 + array_unshift( $links, '<a href="options-general.php?page=' . Email_Post_Changes::ADMIN_PAGE . '">' . __( 'Settings' ) . "</a>" );
16 + return $links;
17 +}
17 18
18 - var $text_diff;
19 +add_action( 'init', array( 'Email_Post_Changes', 'init' ) );
19 20
20 - const ADMIN_PAGE = 'email_post_changes';
21 - const OPTION_GROUP = 'email_post_changes';
22 - const OPTION = 'email_post_changes';
21 +add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'email_post_changes_action_links' );
23 22
24 - function &init() {
25 - static $instance = null;
26 -
27 - if ( $instance )
28 - return $instance;
29 -
30 - $class = __CLASS__;
31 - $instance = new $class;
32 - }
33 -
34 - function __construct() {
35 - $this->defaults = array(
36 - 'emails' => array( get_option( 'admin_email' ) ),
37 - 'post_types' => array( 'post', 'page' )
38 - );
39 -
40 - add_action( 'wp_insert_post', array( &$this, 'wp_insert_post' ), 10, 2 );
41 - add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
42 - }
43 -
44 - function get_post_types() {
45 - $post_types = get_post_types();
46 - if ( false !== $pos = array_search( 'revision', $post_types ) )
47 - unset( $post_types[$pos] );
48 - return $post_types;
49 - }
50 -
51 - function get_options( $just_defaults = false ) {
52 - if ( $just_defaults )
53 - return $this->defaults;
54 -
55 - return get_option( 'email_post_changes', $this->defaults );
56 - }
57 -
58 - // The meat of the plugin
59 - function wp_insert_post( $post_id, $post ) {
60 - $options = $this->get_options();
61 -
62 - if ( 'revision' == $post->post_type ) { // Revision is saved first
63 - if ( wp_is_post_autosave( $post ) )
64 - return;
65 - $this->left_post = $post;
66 - } elseif ( !empty( $this->left_post ) && $this->left_post->post_parent == $post->ID ) { // Then new post
67 - if ( !in_array( $post->post_type, $options['post_types'] ) )
68 - return;
69 - $this->right_post = $post;
70 - }
71 -
72 - if ( !$this->left_post || !$this->right_post )
73 - return;
74 -
75 - $html_diffs = array();
76 - $text_diffs = array();
77 - $identical = true;
78 - foreach ( _wp_post_revision_fields() as $field => $field_title ) {
79 - $left = apply_filters( "_wp_post_revision_field_$field", $this->left_post->$field, $field );
80 - $right = apply_filters( "_wp_post_revision_field_$field", $this->right_post->$field, $field );
81 -
82 - if ( !$diff = wp_text_diff( $left, $right ) )
83 - continue;
84 - $html_diffs[$field_title] = $diff;
85 -
86 - $left = normalize_whitespace( $left );
87 - $right = normalize_whitespace( $right );
88 -
89 - $left_lines = split( "\n", $left );
90 - $right_lines = split( "\n", $right );
91 -
92 - require_once( dirname( __FILE__ ) . '/unified.php' );
93 -
94 - $text_diff = new Text_Diff( $left_lines, $right_lines );
95 - $renderer = new Text_Diff_Renderer_unified();
96 - $text_diffs[$field_title] = $renderer->render($text_diff);
97 -
98 - $identical = false;
99 - }
100 -
101 - if ( $identical )
102 - return;
103 -
104 - // Grab the meta data
105 - $the_author = get_the_author_meta( 'display_name', $this->left_post->post_author ); // The revision
106 - $the_title = get_the_title( $this->right_post->ID ); // New title (may be same as old title)
107 - $right_date = new DateTime( $this->right_post->post_modified_gmt, new DateTimeZone( 'UTC' ) ); // Modified time
108 - $the_date = $right_date->format( 'j F, Y \a\t G:i \U\T\C' );
109 - $the_permalink = clean_url( get_permalink( $this->right_post->ID ) );
110 - $the_edit_link = clean_url( get_edit_post_link( $this->right_post->ID ) );
111 -
112 - $left_title = __( 'Revision' );
113 - $right_title = sprintf( __( 'Current %s' ), $post_type = ucfirst( $this->right_post->post_type ) );
114 -
115 - $head_sprintf = __( '%s made the following changes to the %s %s on %s' );
116 -
117 -
118 - // HTML
119 - $html_diff_head = '<h2>' . sprintf( __( '%s changed' ), $post_type ) . "</h2>\n";
120 - $html_diff_head .= '<p>' . sprintf( $head_sprintf,
121 - esc_html( $the_author ),
122 - sprintf( _x( '&#8220;%s&#8221; [%s]', '1 = link, 2 = "edit"' ),
123 - "<a href='$the_permalink'>" . esc_html( $the_title ) . '</a>',
124 - "<a href='$the_edit_link'>" . __( 'edit' ) . '</a>'
125 - ),
126 - $this->right_post->post_type,
127 - $the_date
128 - ) . "</p>\n\n";
129 -
130 - $html_diff_head .= "<table style='width: 100%; border-collapse: collapse; border: none;'><tr>\n";
131 - $html_diff_head .= "<td style='width: 50%; padding: 0; margin: 0;'>" . esc_html( $left_title ) . ' @ ' . esc_html( $this->left_post->post_date_gmt ) . "</td>\n";
132 - $html_diff_head .= "<td style='width: 50%; padding: 0; margin: 0;'>" . esc_html( $right_title ) . ' @ ' . esc_html( $this->right_post->post_modified_gmt ) . "</td>\n";
133 - $html_diff_head .= "</tr></table>\n\n";
134 -
135 - $html_diff = '';
136 - foreach ( $html_diffs as $field_title => $diff ) {
137 - $html_diff .= '<h3>' . esc_html( $field_title ) . "</h3>\n";
138 - $html_diff .= "$diff\n\n";
139 - }
140 -
141 - $html_diff = rtrim( $html_diff );
142 -
143 - // Replace classes with inline style
144 - $html_diff = str_replace( "class='diff'", 'style="width: 100%; border-collapse: collapse; border: none; white-space: pre-wrap; word-wrap: break-word; font-family: Consolas,Monaco,Courier,monospace;"', $html_diff );
145 - $html_diff = preg_replace( '#<col[^>]+/?>#i', '', $html_diff );
146 - $html_diff = str_replace( "class='diff-deletedline'", 'style="padding: 5px; width: 50%; background-color: #fdd;"', $html_diff );
147 - $html_diff = str_replace( "class='diff-addedline'", 'style="padding: 5px; width: 50%; background-color: #dfd;"', $html_diff );
148 - $html_diff = str_replace( "class='diff-context'", 'style="padding: 5px; width: 50%;"', $html_diff );
149 - $html_diff = str_replace( '<td>', '<td style="padding: 5px;">', $html_diff );
150 - $html_diff = str_replace( '<del>', '<del style="text-decoration: none; background-color: #f99;">', $html_diff );
151 - $html_diff = str_replace( '<ins>', '<ins style="text-decoration: none; background-color: #9f9;">', $html_diff );
152 - $html_diff = str_replace( array( '</td>', '</tr>', '</tbody>' ), array( "</td>\n", "</tr>\n", "</tbody>\n" ), $html_diff );
153 -
154 - $html_diff = $html_diff_head . $html_diff;
155 -
156 -
157 - // Refactor some of the meta data for TEXT
158 - $length = max( strlen( $left_title ), strlen( $right_title ) );
159 - $left_title = str_pad( $left_title, $length + 2 );
160 - $right_title = str_pad( $right_title, $length + 2 );
161 -
162 - // TEXT
163 - $text_diff = sprintf( $head_sprintf, $the_author, '"' . $the_title . '"', $this->right_post->post_type, $the_date ) . "\n";
164 - $text_diff .= "URL: $the_permalink\n";
165 - $text_diff .= "Edit: $the_edit_link\n\n";
166 -
167 - foreach ( $text_diffs as $field_title => $diff ) {
168 - $text_diff .= "$field_title\n";
169 - $text_diff .= "===================================================================\n";
170 - $text_diff .= "--- $left_title ({$this->left_post->post_date_gmt})\n";
171 - $text_diff .= "+++ $right_title ({$this->right_post->post_modified_gmt})\n";
172 - $text_diff .= "$diff\n\n";
173 - }
174 -
175 - $this->text_diff = $text_diff = rtrim( $text_diff );
176 -
177 -
178 - // Send email
179 - $charset = apply_filters( 'wp_mail_charset', get_option( 'blog_charset' ) );
180 - $blogname = html_entity_decode( get_option( 'blogname' ), ENT_QUOTES, $charset );
181 - $title = html_entity_decode( $the_title, ENT_QUOTES, $charset );
182 -
183 - add_action( 'phpmailer_init', array( &$this, 'phpmailer_init_once' ) );
184 -
185 - wp_mail(
186 - null, // see hack in ::phpmailer_init_once()
187 - sprintf( __( '[%s] %s changed: %s' ), $blogname, $post_type, $title ),
188 - $html_diff
189 - );
190 - }
191 -
192 - /* Email hook */
193 - function phpmailer_init_once( &$phpmailer ) {
194 - remove_action( 'phpmailer_init', array( &$this, 'phpmailer_init_once' ) );
195 - $phpmailer->AltBody = $this->text_diff;
196 -
197 - $phpmailer->to = array(); // Hack
198 -
199 - $options = $this->get_options();
200 - foreach ( $options['emails'] as $email )
201 - $phpmailer->AddBCC( $email );
202 -
203 - $phpmailer->AddReplyTo(
204 - get_the_author_meta( 'email', $this->right_post->post_author ),
205 - get_the_author_meta( 'display_name', $this->right_post->post_author )
206 - );
207 - }
208 -
209 - /* Admin */
210 - function admin_menu() {
211 - register_setting( self::OPTION_GROUP, self::OPTION, array( &$this, 'validate_options' ) );
212 -
213 - add_settings_section( self::ADMIN_PAGE, __( 'Email Post Changes' ), array( &$this, 'settings_section' ), self::ADMIN_PAGE );
214 - add_settings_field( self::ADMIN_PAGE . '_emails', __( 'Email Addresses' ), array( &$this, 'emails_setting' ), self::ADMIN_PAGE, self::ADMIN_PAGE );
215 - add_settings_field( self::ADMIN_PAGE . '_post_types', __( 'Post Types' ), array( &$this, 'post_types_setting' ), self::ADMIN_PAGE, self::ADMIN_PAGE );
216 -
217 - add_options_page( __( 'Email Post Changes' ), __( 'Email Post Changes' ), 'manage_options', self::ADMIN_PAGE, array( &$this, 'admin_page' ) );
218 -
219 - add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( &$this, 'plugin_action_links' ) );
220 - }
221 -
222 - function validate_options( $options ) {
223 - if ( !$options || !is_array( $options ) )
224 - return $this->defaults;
225 -
226 - $return = array();
227 -
228 - if ( empty( $options['emails'] ) ) {
229 - $return['emails'] = $this->defaults['emails'];
230 - } else {
231 - if ( is_string( $options['emails'] ) )
232 - $_emails = preg_split( '(\n|\r)', $options['emails'], -1, PREG_SPLIT_NO_EMPTY );
233 - $_emails = array_unique( (array) $_emails );
234 - $emails = array_filter( $_emails, 'is_email' );
235 - if ( $diff = array_diff( $_emails, $emails ) )
236 - $return['invalid_emails'] = $diff;
237 - $return['emails'] = $emails ? $emails : $this->defaults['emails'];
238 - }
239 -
240 - if ( empty( $options['post_types'] ) || !is_array( $options ) ) {
241 - $return['post_types'] = $this->defaults['post_types'];
242 - } else {
243 - $post_types = array_intersect( $options['post_types'], $this->get_post_types() );
244 - $return['post_types'] = $post_types ? $post_types : $this->defaults['post_types'];
245 - }
246 -
247 - return $return;
248 - }
249 -
250 - function admin_page() {
251 - $options = $this->get_options();
252 -?>
253 -
254 -<div class="wrap">
255 - <h2><?php _e( 'Email Post Changes' ); ?></h2>
256 -<?php if ( !empty( $options['invalid_emails'] ) ) : ?>
257 -
258 - <div class="error">
259 - <p><?php printf( _n( 'Invalid Email: %s', 'Invalid Emails: %s', count( $options['invalid_emails'] ) ), '<kbd>' . join( '</kbd>, <kbd>', array_map( 'esc_html', $options['invalid_emails'] ) ) ); ?></p>
260 - </div>
261 -<?php endif; ?>
262 -
263 - <form action="options.php" method="post">
264 - <?php settings_fields( self::OPTION_GROUP ); ?>
265 - <?php do_settings_sections( self::ADMIN_PAGE ); ?>
266 - <p class="submit">
267 - <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes' ); ?>" />
268 - </p>
269 - </form>
270 -</div>
271 -<?php
272 - }
273 -
274 - function settings_section() {} // stub
275 -
276 - function emails_setting() {
277 - $options = $this->get_options();
278 -?>
279 - <textarea rows="4" cols="40" style="width: 40em;" name="email_post_changes[emails]"><?php echo esc_html( join( "\n", $options['emails'] ) ); ?></textarea>
280 - <p class="description"><?php _e( 'Send emails to these addresses. One per line.' ); ?></p>
281 - <p class="description"><?php printf(
282 - __( "If blank, send emails to this site&#8217;s <a href='%s'>admin email address</a>." ),
283 - clean_url( get_bloginfo( 'wpurl' ) . '/wp-admin/options-general.php#admin_email' )
284 - ); ?></p>
285 -<?php
286 - }
287 -
288 - function post_types_setting() {
289 - $options = $this->get_options();
290 -?>
291 -
292 - <ul>
293 -<?php foreach ( $this->get_post_types() as $post_type ) : ?>
294 -
295 - <li><label><input type="checkbox" name="email_post_changes[post_types][]" value="<?php echo esc_attr( $post_type ); ?>"<?php checked( in_array( $post_type, $options['post_types'] ) ); ?> /> <?php echo esc_html( ucfirst( $post_type ) ); ?></label></li>
296 -<?php endforeach; ?>
297 -
298 - </ul>
299 - <p class="description"><?php _e( 'Send emails when a post of these post types changes.' ); ?></p>
300 - <p class="description"><?php _e( 'If none are selected, &#8220;post&#8221; and &#8220;page&#8221; will be checked by default.' ); ?></p>
301 -<?php
302 - }
303 -
304 - function plugin_action_links( $links ) {
305 - array_unshift( $links, '<a href="options-general.php?page=' . self::ADMIN_PAGE . '">' . __( 'Settings' ) . "</a>" );
306 - return $links;
307 - }
308 -}
309 -
310 -add_action( 'init', array( 'Email_Post_Changes', 'init' ) );