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 -294 0.30.7 View file →
@@ -1,307 +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.3
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->right_post->post_author );
106 - $the_title = get_the_title( $this->right_post->ID );
107 - $right_date = DateTime::createFromFormat( 'Y-m-d H:i:s', $this->right_post->post_modified_gmt, new DateTimeZone( 'UTC' ) );
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->left_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 - $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
180 - $title = wp_specialchars_decode( $the_title, ENT_QUOTES );
181 -
182 - add_action( 'phpmailer_init', array( &$this, 'phpmailer_init_once' ) );
183 -
184 - wp_mail(
185 - null, // see hack in ::phpmailer_init_once()
186 - sprintf( __( '[%s] %s changed: %s' ), $blogname, $post_type, $title ),
187 - $html_diff
188 - );
189 - }
190 -
191 - /* Email hook */
192 - function phpmailer_init_once( &$phpmailer ) {
193 - remove_action( 'phpmailer_init', array( &$this, 'phpmailer_init_once' ) );
194 - $phpmailer->AltBody = $this->text_diff;
195 -
196 - $phpmailer->to = array(); // Hack
197 -
198 - $options = $this->get_options();
199 - foreach ( $options['emails'] as $email )
200 - $phpmailer->AddBCC( $email );
201 -
202 - $phpmailer->AddReplyTo(
203 - get_the_author_meta( 'email', $this->right_post->post_author ),
204 - get_the_author_meta( 'display_name', $this->right_post->post_author )
205 - );
206 - }
207 -
208 - /* Admin */
209 - function admin_menu() {
210 - register_setting( self::OPTION_GROUP, self::OPTION, array( &$this, 'validate_options' ) );
211 -
212 - add_settings_section( self::ADMIN_PAGE, __( 'Email Post Changes' ), array( &$this, 'settings_section' ), self::ADMIN_PAGE );
213 - add_settings_field( self::ADMIN_PAGE . '_emails', __( 'Email Addresses' ), array( &$this, 'emails_setting' ), self::ADMIN_PAGE, self::ADMIN_PAGE );
214 - add_settings_field( self::ADMIN_PAGE . '_post_types', __( 'Post Types' ), array( &$this, 'post_types_setting' ), self::ADMIN_PAGE, self::ADMIN_PAGE );
215 -
216 - add_options_page( __( 'Email Post Changes' ), __( 'Email Post Changes' ), 'manage_options', self::ADMIN_PAGE, array( &$this, 'admin_page' ) );
217 -
218 - add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( &$this, 'plugin_action_links' ) );
219 - }
220 -
221 - function validate_options( $options ) {
222 - if ( !$options || !is_array( $options ) )
223 - return $this->defaults;
224 -
225 - $return = array();
226 -
227 - if ( empty( $options['emails'] ) ) {
228 - $return['emails'] = $this->defaults['emails'];
229 - } else {
230 - $_emails = array_unique( preg_split( '(\n|\r)', $options['emails'], -1, PREG_SPLIT_NO_EMPTY ) );
231 - $emails = array_filter( $_emails, 'is_email' );
232 - if ( $diff = array_diff( $_emails, $emails ) )
233 - $return['invalid_emails'] = $diff;
234 - $return['emails'] = $emails ? $emails : $this->defaults['emails'];
235 - }
236 -
237 - if ( empty( $options['post_types'] ) || !is_array( $options ) ) {
238 - $return['post_types'] = $this->defaults['post_types'];
239 - } else {
240 - $post_types = array_intersect( $options['post_types'], $this->get_post_types() );
241 - $return['post_types'] = $post_types ? $post_types : $this->defaults['post_types'];
242 - }
243 -
244 - return $return;
245 - }
246 -
247 - function admin_page() {
248 - $options = $this->get_options();
249 -?>
250 -
251 -<div class="wrap">
252 - <h2><?php _e( 'Email Post Changes' ); ?></h2>
253 -<?php if ( !empty( $options['invalid_emails'] ) ) : ?>
254 -
255 - <div class="error">
256 - <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>
257 - </div>
258 -<?php endif; ?>
259 -
260 - <form action="options.php" method="post">
261 - <?php settings_fields( self::OPTION_GROUP ); ?>
262 - <?php do_settings_sections( self::ADMIN_PAGE ); ?>
263 - <p class="submit">
264 - <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes' ); ?>" />
265 - </p>
266 - </form>
267 -</div>
268 -<?php
269 - }
270 -
271 - function settings_section() {} // stub
272 -
273 - function emails_setting() {
274 - $options = $this->get_options();
275 -?>
276 - <textarea rows="4" cols="40" style="width: 40em;" name="email_post_changes[emails]"><?php echo esc_html( join( "\n", $options['emails'] ) ); ?></textarea>
277 - <p class="description"><?php _e( 'Send emails to these addresses. One per line.' ); ?></p>
278 - <p class="description"><?php printf(
279 - __( "If blank, send emails to this site&#8217;s <a href='%s'>admin email address</a>." ),
280 - clean_url( get_bloginfo( 'wpurl' ) . '/wp-admin/options-general.php#admin_email' )
281 - ); ?></p>
282 -<?php
283 - }
284 -
285 - function post_types_setting() {
286 - $options = $this->get_options();
287 -?>
288 -
289 - <ul>
290 -<?php foreach ( $this->get_post_types() as $post_type ) : ?>
291 -
292 - <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>
293 -<?php endforeach; ?>
294 -
295 - </ul>
296 - <p class="description"><?php _e( 'Send emails when a post of these post types changes.' ); ?></p>
297 - <p class="description"><?php _e( 'If none are selected, &#8220;post&#8221; and &#8220;page&#8221; will be checked by default.' ); ?></p>
298 -<?php
299 - }
300 -
301 - function plugin_action_links( $links ) {
302 - array_unshift( $links, '<a href="options-general.php?page=' . self::ADMIN_PAGE . '">' . __( 'Settings' ) . "</a>" );
303 - return $links;
304 - }
305 -}
306 -
307 -add_action( 'init', array( 'Email_Post_Changes', 'init' ) );