Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 814 lines (673 sloc) 24.817 kb
8ff4206 @mjangda v1
mjangda authored
1 <?php
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
2
8ff4206 @mjangda v1
mjangda authored
3 /**
4 * Plugin Name: Liveblog
1fc681a @nb Add metadata URLs
nb authored
5 * Plugin URI: http://wordpress.org/extend/plugins/liveblog/
8ff4206 @mjangda v1
mjangda authored
6 * Description: Blogging: at the speed of live.
1c424e2 @mjangda Bump version to 1.1
mjangda authored
7 * Version: 1.1
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
8 * Author: WordPress.com VIP, Automattic
1fc681a @nb Add metadata URLs
nb authored
9 * Author URI: http://vip.wordpress.com/
10 * Text Domain: liveblog
8ff4206 @mjangda v1
mjangda authored
11 */
12
13 if ( ! class_exists( 'WPCOM_Liveblog' ) ) :
14
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
15 /**
16 * The main Liveblog class used to setup everything this plugin needs.
17 *
18 * Liveblog currently uses a custom comment-type to circumvent post cache
19 * issues frequently experienced by other live-blog implimentations. It comes
20 * with a simple and effective templating mechanism, complete with all of the
21 * CSS, JS, and AJAX needed to make this a turn-key installation.
22 *
23 * This class is a big container for a bunch of static methods, similar to a
24 * factory but without object inheritance or instantiation.
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
25 *
5ad84ba @nb Fix typo
nb authored
26 * Things yet to be implemented:
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
27 *
28 * -- Change "Read More" to "View Liveblog"
29 * -- Manual refresh button
30 * -- Allow marking of liveblog as ended
31 * -- Allow comment modifications; need to store modified date as comment_meta
32 */
33 final class WPCOM_Liveblog {
34
35 /** Constants *************************************************************/
8ff4206 @mjangda v1
mjangda authored
36
1c424e2 @mjangda Bump version to 1.1
mjangda authored
37 const version = '1.1';
1d5d7f9 @nb Flush the rewrite rules on rules update
nb authored
38 const rewrites_version = 1;
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
39 const key = 'liveblog';
40 const url_endpoint = 'liveblog';
41 const edit_cap = 'publish_posts';
42 const nonce_key = 'liveblog_nonce';
8ff4206 @mjangda v1
mjangda authored
43
ed1991c @nb Shut the auto-update only on consecutive failures
nb authored
44 const refresh_interval = 3; // how often should we refresh
45 const max_consecutive_retries = 100; // max number of failed tries before polling is disabled
46 const delay_threshold = 5; // how many failed tries after which we should increase the refresh interval
47 const delay_multiplier = 2; // by how much should we inscrease the refresh interval
8ff4206 @mjangda v1
mjangda authored
48
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
49 /** Variables *************************************************************/
50
51 private static $post_id = null;
52 private static $entry_query = null;
53 private static $do_not_cache_response = false;
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
54
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
55 /** Load Methods **********************************************************/
56
57 /**
58 * @uses add_action() to hook methods into WordPress actions
59 * @uses add_filter() to hook methods into WordPress filters
60 */
61 public static function load() {
e5351e5 @mjangda load_plugin_textdomain so the plugin can be translated.
mjangda authored
62 load_plugin_textdomain( 'liveblog', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
63
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
64 self::includes();
65 self::add_actions();
66 self::add_filters();
67 self::add_admin_actions();
68 }
69
70 /**
71 * Include the necessary files
72 */
73 private static function includes() {
74 require( dirname( __FILE__ ) . '/classes/class-wpcom-liveblog-entry.php' );
75 require( dirname( __FILE__ ) . '/classes/class-wpcom-liveblog-entry-query.php' );
e691fe3 @johnjamesjacoby Include ms.php theme-side for its filesize and available space functi…
johnjamesjacoby authored
76
77 // Manually include ms.php theme-side in multisite environments because
78 // we need its filesize and available space functions.
79 if ( ! is_admin() && is_multisite() ) {
8f5fb3c @johnjamesjacoby Remove preceding slash. ABSPATH is already slashed for us.
johnjamesjacoby authored
80 require_once( ABSPATH . 'wp-admin/includes/ms.php' );
e691fe3 @johnjamesjacoby Include ms.php theme-side for its filesize and available space functi…
johnjamesjacoby authored
81 }
02b5fdb @nb Add convertor from extend read me to github readme
nb authored
82
83 if ( defined( 'WP_CLI' ) && WP_CLI ) {
84 require( dirname( __FILE__ ) . '/classes/class-wpcom-liveblog-wp-cli.php' );
85 }
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
86 }
8ff4206 @mjangda v1
mjangda authored
87
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
88 /**
89 * Hook actions in that run on every page-load
90 *
91 * @uses add_action()
92 */
93 private static function add_actions() {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
94 add_action( 'init', array( __CLASS__, 'init' ) );
7994c3e @nb Re-add the rewrite rules on permalink change
nb authored
95 add_action( 'init', array( __CLASS__, 'add_rewrite_rules' ) );
96 add_action( 'permalink_structure_changed', array( __CLASS__, 'add_rewrite_rules' ) );
4221823 @nb Flush the rewrite rules later
nb authored
97 // flush the rewrite rules a lot later so that we don't interfere with other plugins using rewrite rules
98 add_action( 'init', array( __CLASS__, 'flush_rewrite_rules' ), 1000 );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
99 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
8ff4206 @mjangda v1
mjangda authored
100 add_action( 'wp_ajax_liveblog_insert_entry', array( __CLASS__, 'ajax_insert_entry' ) );
5aee585 @nb Add ajax endpoint for preview
nb authored
101 add_action( 'wp_ajax_liveblog_preview_entry', array( __CLASS__, 'ajax_preview_entry' ) );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
102 }
8ff4206 @mjangda v1
mjangda authored
103
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
104 /**
105 * Hook filters in that run on every page-load
106 *
107 * @uses add_filter()
108 */
109 private static function add_filters() {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
110 add_filter( 'template_redirect', array( __CLASS__, 'handle_request' ) );
111 add_filter( 'comment_class', array( __CLASS__, 'add_comment_class' ) );
8ff4206 @mjangda v1
mjangda authored
112 }
113
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
114 /**
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
115 * Hook actions in that run on every admin page-load
116 *
117 * @uses add_action()
118 * @uses is_admin()
119 */
120 private static function add_admin_actions() {
121
122 // Bail if not in admin area
123 if ( ! is_admin() )
124 return;
125
126 add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_box' ) );
127 add_action( 'save_post', array( __CLASS__, 'save_meta_box' ) );
128 }
129
130 /** Public Methods ********************************************************/
131
132 /**
133 * Liveblog initialization functions.
134 *
135 * This is where Liveblog sets up any additional things it needs to run
136 * inside of WordPress. Where some plugins would register post types or
137 * taxonomies, we modify endpoints and add post type support for Liveblog.
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
138 */
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
139 public static function init() {
140 /**
141 * Add liveblog support to the 'post' post type. This is done here so
142 * we can possibly introduce this to other post types later.
143 */
8ff4206 @mjangda v1
mjangda authored
144 add_post_type_support( 'post', self::key );
145 }
146
7994c3e @nb Re-add the rewrite rules on permalink change
nb authored
147 public function add_rewrite_rules() {
1d5d7f9 @nb Flush the rewrite rules on rules update
nb authored
148 add_rewrite_endpoint( self::url_endpoint, EP_PERMALINK );
7994c3e @nb Re-add the rewrite rules on permalink change
nb authored
149 }
1d5d7f9 @nb Flush the rewrite rules on rules update
nb authored
150
7994c3e @nb Re-add the rewrite rules on permalink change
nb authored
151 public static function flush_rewrite_rules() {
1d5d7f9 @nb Flush the rewrite rules on rules update
nb authored
152 if ( get_option( 'liveblog_rewrites_version' ) != self::rewrites_version ) {
153 flush_rewrite_rules();
154 update_option( 'liveblog_rewrites_version', self::rewrites_version );
155 }
156 }
157
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
158 /**
159 * This is where a majority of the magic happens.
160 *
161 * Hooked to template_redirect, this method tries to add anything it can to
162 * the current post output. If nothing needs to be added, we redirect back
163 * to the permalink.
164 *
165 * @return If request has been handled
166 */
167 public static function handle_request() {
168
8ff4206 @mjangda v1
mjangda authored
169 if ( ! self::is_viewing_liveblog_post() )
170 return;
171
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
172 self::$post_id = get_the_ID();
b28b38d @nb Rename the query class to match WP conventions
nb authored
173 self::$entry_query = new WPCOM_Liveblog_Entry_Query( self::$post_id, self::key );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
174
4872b2a @nb Use front-end AJAX URLs for same-origin requests
nb authored
175 if ( self::is_initial_page_request() )
8ff4206 @mjangda v1
mjangda authored
176 add_filter( 'the_content', array( __CLASS__, 'add_liveblog_to_content' ) );
4872b2a @nb Use front-end AJAX URLs for same-origin requests
nb authored
177 else
178 self::handle_ajax_request();
179 }
180
181 private static function handle_ajax_request() {
182
183 $endpoint_suffix = get_query_var( self::url_endpoint );
184
185 if ( !$endpoint_suffix ) {
186 // we redirect, because if somebody accessed <permalink>/liveblog
187 // they probably did that in the URL bar, not via AJAX
188 wp_safe_redirect( get_permalink() );
189 exit();
8ff4206 @mjangda v1
mjangda authored
190 }
2b0244c @nb Remove trailing whitespace
nb authored
191 wp_cache_delete( self::key . '_entries_asc_' . self::$post_id, 'liveblog' );
8ff4206 @mjangda v1
mjangda authored
192
4872b2a @nb Use front-end AJAX URLs for same-origin requests
nb authored
193 $suffix_to_method = array(
194 '\d+/\d+' => 'ajax_entries_between',
195 'insert' => 'ajax_insert_entry',
196 'preview' => 'ajax_preview_entry',
197 );
198
199 $response_method = 'ajax_unknown';
200
201 foreach( $suffix_to_method as $suffix_re => $method ) {
202 if ( preg_match( "%^$suffix_re/?%", $endpoint_suffix ) ) {
203 $response_method = $method;
204 break;
205 }
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
206 }
207
4872b2a @nb Use front-end AJAX URLs for same-origin requests
nb authored
208 self::$response_method();
209
8ff4206 @mjangda v1
mjangda authored
210 }
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
211
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
212 /**
213 * Look for any new Liveblog entries, and return them via JSON
214 */
215 public static function ajax_entries_between() {
216
217 // Set some defaults
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
218 $latest_timestamp = 0;
219 $entries_for_json = array();
558008c @nb Use the same current timestamp at all places
nb authored
220
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
221 // Look for entry boundaries
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
222 list( $start_timestamp, $end_timestamp ) = self::get_timestamps_from_query();
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
223
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
224 // Bail if there is no end timestamp
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
225 if ( empty( $end_timestamp ) ) {
70b347a @mjangda Add missing textdomain to translated strings
mjangda authored
226 self::send_user_error( __( 'A timestamp is missing. Correct URL: <permalink>/liveblog/<from>/</to>/', 'liveblog' ) );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
227 }
228
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
229 // Do not cache if it's too soon
bd6c841 @nb Use the Date header to get server-side date
nb authored
230 if ( $end_timestamp > time() )
6c66757 @nb Do not let the client cache future requests
nb authored
231 self::$do_not_cache_response = true;
232
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
233 // Get liveblog entries within the start and end boundaries
b28b38d @nb Rename the query class to match WP conventions
nb authored
234 $entries = self::$entry_query->get_between_timestamps( $start_timestamp, $end_timestamp );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
235 if ( empty( $entries ) ) {
236 self::json_return( array(
237 'entries' => array(),
238 'latest_timestamp' => null
239 ) );
240 }
d79a82d @nb Gather common entry functionality in a new class
nb authored
241
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
242 /**
243 * Loop through each liveblog entry, set the most recent timestamp, and
244 * put the JSON data for each entry into a neat little array.
245 */
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
246 foreach( $entries as $entry ) {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
247 $latest_timestamp = max( $latest_timestamp, $entry->get_timestamp() );
d79a82d @nb Gather common entry functionality in a new class
nb authored
248 $entries_for_json[] = $entry->for_json();
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
249 }
250
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
251 // Setup our data to return via JSON
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
252 $result_for_json = array(
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
253 'entries' => $entries_for_json,
254 'latest_timestamp' => $latest_timestamp,
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
255 );
256
e977561 @nb Get rid of extra json_return() arguments
nb authored
257 self::json_return( $result_for_json );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
258 }
259
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
260 /** Private _is_ Methods **************************************************/
261
262 /**
263 * Are we viewing a liveblog post?
264 *
265 * @uses is_single()
266 * @uses is_liveblog_post()
267 * @return bool
268 */
269 private static function is_viewing_liveblog_post() {
270 return (bool) ( is_single() && self::is_liveblog_post() );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
271 }
272
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
273 /**
274 * Is this the initial page request?
275 *
276 * Note that we do not use get_query_var() - it returns '' for all requests,
277 * which is valid for /post-name/liveblog/
278 *
279 * @global WP_Query $wp_query
280 * @return bool
281 */
282 private static function is_initial_page_request() {
8ff4206 @mjangda v1
mjangda authored
283 global $wp_query;
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
284
285 return (bool) ! isset( $wp_query->query_vars[self::key] );
8ff4206 @mjangda v1
mjangda authored
286 }
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
287
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
288 /**
289 * Is this an ajax request for the entries?
290 *
291 * @uses get_query_var() to check for the url_endpoint
292 * @return bool
293 */
294 private static function is_entries_ajax_request() {
295 return (bool) get_query_var( self::url_endpoint );
296 }
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
297
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
298 /**
299 * Is a given post_id a liveblog enabled post?
300 *
301 * @global WP_Post $post
302 * @param int $post_id
303 * @return bool
304 */
305 private static function is_liveblog_post( $post_id = null ) {
306 if ( empty( $post_id ) ) {
307 global $post;
308 $post_id = $post->ID;
309 }
310
311 return (bool) get_post_meta( $post_id, self::key, true );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
312 }
313
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
314 /**
315 * Get timestamps from the current WP_Query
316 *
317 * Ensures that two timestamps exist, and returns a properly formatted empty
318 * array if not.
319 *
320 * @return array
321 */
322 private static function get_timestamps_from_query() {
323
324 // Look for timestamps and bail if none
25be635 @mjangda Support for non-pretty permalinks
mjangda authored
325 $stamps = rtrim( get_query_var( self::url_endpoint ), '/' );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
326 if ( empty( $stamps ) )
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
327 return array( false, false );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
328
329 // Get timestamps from the query variable
330 $timestamps = explode( '/', $stamps );
331
332 // Bail if there are not 2 timestamps
333 if ( 2 !== count( $timestamps ) )
334 return array( false, false );
335
336 // Return integer timestamps in an array
337 return array_map( 'intval', $timestamps );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
338 }
339
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
340 /**
341 * Inserts, updates, or deletes a liveblog entry
342 */
343 public static function ajax_insert_entry() {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
344
345 // Capability and Intention Checks
b58c3a0 @nb Remove leading underscores from function names
nb authored
346 self::ajax_current_user_can_edit_liveblog();
347 self::ajax_check_nonce();
8ff4206 @mjangda v1
mjangda authored
348
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
349 // Check POST data
ec017c4 @nb Kses posts content closer to the place we use it
nb authored
350 $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
351 $replaces_comment_id = isset( $_POST['replaces'] ) ? intval( $_POST['replaces'] ) : 0;
352 $entry_content = isset( $_POST['entry_content'] ) ? $_POST['entry_content'] : '';
8ff4206 @mjangda v1
mjangda authored
353
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
354 if ( empty( $post_id ) )
69f9cbb @nb Add more specific HTTP error codes
nb authored
355 self::send_user_error( __( 'Sorry, that post is not accepting Liveblog entries.', 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
356
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
357 // Get the current user
8ff4206 @mjangda v1
mjangda authored
358 $user = wp_get_current_user();
359
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
360 // Insert new comment
361 $new_comment_id = wp_insert_comment( array(
362 'comment_post_ID' => $post_id,
ec017c4 @nb Kses posts content closer to the place we use it
nb authored
363 'comment_content' => wp_filter_post_kses( $entry_content ),
f157181 @johnjamesjacoby Comment Status:
johnjamesjacoby authored
364 'comment_approved' => self::key,
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
365 'comment_type' => self::key,
366 'user_id' => $user->ID,
8ff4206 @mjangda v1
mjangda authored
367
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
368 'comment_author' => $user->display_name,
8ff4206 @mjangda v1
mjangda authored
369 'comment_author_email' => $user->user_email,
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
370 'comment_author_url' => $user->user_url,
371
8ff4206 @mjangda v1
mjangda authored
372 // Borrowed from core as wp_insert_comment does not generate them
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
373 'comment_author_IP' => preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] ),
374 'comment_agent' => substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ),
375 ) );
2b0244c @nb Remove trailing whitespace
nb authored
376 wp_cache_delete( self::key . '_entries_asc_' . $post_id, 'liveblog' );
8ff4206 @mjangda v1
mjangda authored
377
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
378 // Bail if comment could not be saved
379 if ( empty( $new_comment_id ) || is_wp_error( $new_comment_id ) )
69f9cbb @nb Add more specific HTTP error codes
nb authored
380 self::send_server_error( __( 'Error posting entry', 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
381
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
382 // Are we replacing an existing comment?
383 if ( !empty( $replaces_comment_id ) ) {
a2f3ce4 @nb Show inserted entry immediately
nb authored
384
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
385 //
a2723d4 @nb Commit entry modifications
nb authored
386 add_comment_meta( $new_comment_id, WPCOM_Liveblog_Entry::replaces_meta_key, $replaces_comment_id );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
387
388 // Update an existing comment
389 if ( !empty( $entry_content ) ) {
390 wp_update_comment( array(
391 'comment_ID' => $replaces_comment_id,
ec017c4 @nb Kses posts content closer to the place we use it
nb authored
392 'comment_content' => wp_filter_post_kses( $entry_content ),
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
393 ) );
394
395 // Delete this comment
396 } else {
a2723d4 @nb Commit entry modifications
nb authored
397 wp_delete_comment( $replaces_comment_id );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
398 }
a2723d4 @nb Commit entry modifications
nb authored
399 }
400
a2f3ce4 @nb Show inserted entry immediately
nb authored
401 $entry = WPCOM_Liveblog_Entry::from_comment( get_comment( $new_comment_id ) );
402
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
403 // Do not send latest_timestamp. If we send it the client won't get
404 // older entries. Since we send only the new one, we don't know if there
405 // weren't any entries in between.
406 self::json_return( array(
407 'entries' => array( $entry->for_json() ),
408 'latest_timestamp' => null
409 ) );
8ff4206 @mjangda v1
mjangda authored
410 }
411
5aee585 @nb Add ajax endpoint for preview
nb authored
412 function ajax_preview_entry() {
413 self::ajax_current_user_can_edit_liveblog();
414 self::ajax_check_nonce();
415 $entry_content = isset( $_REQUEST['entry_content'] ) ? $_REQUEST['entry_content'] : '';
416 $entry_content = wp_filter_post_kses( $entry_content );
417 $entry_content = WPCOM_Liveblog_Entry::render_content( $entry_content );
418 self::json_return( array( 'html' => $entry_content ) );
419 }
420
4872b2a @nb Use front-end AJAX URLs for same-origin requests
nb authored
421 public function ajax_unknown() {
422 self::send_user_error( __( 'Unknown liveblog action', 'liveblog' ) );
423 }
424
425
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
426 /** Comment Methods *******************************************************/
8ff4206 @mjangda v1
mjangda authored
427
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
428 /**
429 * Add a liveblog class to each comment, so they can be styled
430 *
431 * @param array $classes
432 * @return string
433 */
434 public static function add_comment_class( $classes ) {
8ff4206 @mjangda v1
mjangda authored
435 $classes[] = 'liveblog-entry';
436 return $classes;
437 }
438
f157181 @johnjamesjacoby Comment Status:
johnjamesjacoby authored
439
440 /**
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
441 * Enqueue the necessary CSS and JS that liveblog needs to function.
442 *
443 * @return If not a liveblog post
444 */
445 public static function enqueue_scripts() {
446
8ff4206 @mjangda v1
mjangda authored
447 if ( ! self::is_viewing_liveblog_post() )
448 return;
449
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
450 wp_enqueue_style( self::key, plugins_url( 'css/liveblog.css', __FILE__ ) );
db742c8 @nb Highlight new posts
nb authored
451 wp_enqueue_script( self::key, plugins_url( 'js/liveblog.js', __FILE__ ), array( 'jquery', 'jquery-color' ), self::version, true );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
452
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
453 if ( self::current_user_can_edit_liveblog() ) {
a456b55 @nb Add Preview interface
nb authored
454 wp_enqueue_script( 'liveblog-publisher', plugins_url( 'js/liveblog-publisher.js', __FILE__ ), array( self::key, 'jquery-ui-tabs' ), self::version, true );
212e64d @zbtirrell Hookable Uploader
zbtirrell authored
455 wp_enqueue_script( 'liveblog-plupload', plugins_url( 'js/plupload.js', __FILE__ ), array( self::key, 'wp-plupload', 'jquery' ) );
c65e58f @nb Make the function name a verb
nb authored
456 self::add_default_plupload_settings();
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
457 }
8ff4206 @mjangda v1
mjangda authored
458
c0c3085 @nb Add spinner for inserting an entry
nb authored
459 if ( wp_script_is( 'jquery.spin', 'registered' ) ) {
460 wp_enqueue_script( 'jquery.spin' );
461 } else {
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
462 wp_enqueue_script( 'spin', plugins_url( 'js/spin.js', __FILE__ ), false, '1.2.4' );
463 wp_enqueue_script( 'jquery.spin', plugins_url( 'js/jquery.spin.js', __FILE__ ), array( 'jquery', 'spin' ) );
c0c3085 @nb Add spinner for inserting an entry
nb authored
464 }
465
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
466 wp_localize_script( self::key, 'liveblog_settings',
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
467 apply_filters( 'liveblog_settings', array(
468 'permalink' => get_permalink(),
469 'post_id' => get_the_ID(),
8ff4206 @mjangda v1
mjangda authored
470
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
471 'key' => self::key,
472 'nonce_key' => self::nonce_key,
473 'latest_entry_timestamp' => self::$entry_query->get_latest_timestamp(),
8ff4206 @mjangda v1
mjangda authored
474
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
475 'refresh_interval' => self::refresh_interval,
ed1991c @nb Shut the auto-update only on consecutive failures
nb authored
476 'max_consecutive_retries'=> self::max_consecutive_retries,
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
477 'delay_threshold' => self::delay_threshold,
478 'delay_multiplier' => self::delay_multiplier,
8ff4206 @mjangda v1
mjangda authored
479
358dc85 @nb Rename entriesurl to endpoint_url
nb authored
480 'endpoint_url' => self::get_entries_endpoint_url(),
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
481
482 // i18n
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
483 'update_nag_singular' => __( '%d new update', 'liveblog' ),
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
484 'update_nag_plural' => __( '%d new updates', 'liveblog' ),
28802ff @nb Delete entry functionality
nb authored
485 'delete_confirmation' => __( 'Do you really want do delete this entry? There is no way back.', 'liveblog' ),
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
486 ) )
487 );
8ff4206 @mjangda v1
mjangda authored
488 }
489
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
490 /**
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
491 * Sets up some default Plupload settings so we can upload meda theme-side
492 *
493 * @global type $wp_scripts
494 */
c65e58f @nb Make the function name a verb
nb authored
495 private static function add_default_plupload_settings() {
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
496 global $wp_scripts;
497
498 $defaults = array(
499 'runtimes' => 'html5,silverlight,flash,html4',
500 'file_data_name' => 'async-upload',
501 'multiple_queues' => true,
502 'max_file_size' => self::max_upload_size() . 'b',
503 'url' => admin_url( 'admin-ajax.php', 'relative' ),
504 'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
505 'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
70b347a @mjangda Add missing textdomain to translated strings
mjangda authored
506 'filters' => array( array( 'title' => __( 'Allowed Files', 'liveblog' ), 'extensions' => '*') ),
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
507 'multipart' => true,
508 'urlstream_upload' => true,
509 'multipart_params' => array(
510 'action' => 'upload-attachment',
511 '_wpnonce' => wp_create_nonce( 'media-form' )
512 )
513 );
514
515 $settings = array(
516 'defaults' => $defaults,
517 'browser' => array(
518 'mobile' => wp_is_mobile(),
519 'supported' => _device_can_upload(),
520 )
521 );
522
523 $script = 'var _wpPluploadSettings = ' . json_encode( $settings ) . ';';
524 $data = $wp_scripts->get_data( 'wp-plupload', 'data' );
525
526 if ( ! empty( $data ) )
527 $script = "$data\n$script";
528
529 $wp_scripts->add_data( 'wp-plupload', 'data', $script );
530 }
531
532 /**
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
533 * Get the URL of a specific liveblog entry.
534 *
535 * @return string
536 */
537 private static function get_entries_endpoint_url() {
0dccc81 @nb Add correct endpoing to draft URLs with query args
nb authored
538 $post_permalink = get_permalink( self::$post_id );
539 if ( false !== strpos( $post_permalink, '?p=' ) )
540 $url = add_query_arg( self::url_endpoint, '', $post_permalink ) . '='; // returns something like ?p=1&liveblog=
25be635 @mjangda Support for non-pretty permalinks
mjangda authored
541 else
0dccc81 @nb Add correct endpoing to draft URLs with query args
nb authored
542 $url = trailingslashit( trailingslashit( $post_permalink ) . self::url_endpoint ); // returns something like /2012/01/01/post/liveblog/
7330fcb @nb Allow the endpoint URL to be filtered
nb authored
543 $url = apply_filters( 'liveblog_endpoint_url', $url, self::$post_id );
25be635 @mjangda Support for non-pretty permalinks
mjangda authored
544 return $url;
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
545 }
cb778e4 @mjangda Load initial entries server-side rather than via AJAX for SEO benefit
mjangda authored
546
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
547 /** Display Methods *******************************************************/
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
548
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
549 /**
550 * Filter the_content and add the liveblog theme-side UI above the normal
551 * content area.
552 *
553 * @param string $content
554 * @return string
555 */
556 public static function add_liveblog_to_content( $content ) {
cb778e4 @mjangda Load initial entries server-side rather than via AJAX for SEO benefit
mjangda authored
557
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
558 $liveblog_output = '<div id="liveblog-container" class="'. self::$post_id .'">';
559 $liveblog_output .= self::get_editor_output();
560 $liveblog_output .= '<div id="liveblog-update-spinner"></div>';
561 $liveblog_output .= self::get_all_entry_output();
ba2c2ae @mjangda Switch around ids with classes just to be future-safe. Add a new wrap…
mjangda authored
562 $liveblog_output .= '</div>';
8ff4206 @mjangda v1
mjangda authored
563
7205206 @nb Put the post contents before the liveblog
nb authored
564 return $content . $liveblog_output;
8ff4206 @mjangda v1
mjangda authored
565 }
566
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
567 /**
568 * Return the posting area for the end-user to liveblog from
569 *
570 * @return string
571 */
572 private static function get_editor_output() {
b58c3a0 @nb Remove leading underscores from function names
nb authored
573 if ( ! self::current_user_can_edit_liveblog() )
8ff4206 @mjangda v1
mjangda authored
574 return;
575
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
576 // Get the template part
577 return self::get_template_part( 'liveblog-form.php' );
8ff4206 @mjangda v1
mjangda authored
578 }
579
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
580 /**
581 * Get all the liveblog entries for this post
582 */
583 private static function get_all_entry_output() {
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
584
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
585 // Get liveblog entries
9c2b7c3 @nb Order entries reverse-chronologically on initial load
nb authored
586 $entries = (array) self::$entry_query->get_all();
8ff4206 @mjangda v1
mjangda authored
587
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
588 // Get the template part
589 return self::get_template_part( 'liveblog-loop.php', compact( 'entries' ) );
590 }
591
592 /**
593 * Get the template part in an output buffer and return it
594 *
595 * @param string $template_name
596 * @param array $template_variables
597 */
598 public static function get_template_part( $template_name, $template_variables = array() ) {
599 ob_start();
600 extract( $template_variables );
601 include( dirname( __FILE__ ) . '/templates/' . $template_name );
602 return ob_get_clean();
8ff4206 @mjangda v1
mjangda authored
603 }
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
604
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
605 /** Admin Methods *********************************************************/
606
607 /**
608 * Register the metabox with the supporting post-type
609 *
610 * @param string $post_type
611 */
612 public static function add_meta_box( $post_type ) {
613
614 // Bail if not supported
615 if ( ! post_type_supports( $post_type, self::key ) )
616 return;
8ff4206 @mjangda v1
mjangda authored
617
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
618 add_meta_box( self::key, __( 'Liveblog', 'liveblog' ), array( __CLASS__, 'display_meta_box' ) );
8ff4206 @mjangda v1
mjangda authored
619 }
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
620
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
621 /**
622 * Output the metabox
623 *
624 * @param WP_Post $post
625 */
626 public static function display_meta_box( $post ) {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
627 ?>
628
8ff4206 @mjangda v1
mjangda authored
629 <label>
630 <input type="checkbox" name="is-liveblog" id="is-liveblog" value="1" <?php checked( self::is_liveblog_post( $post->ID ) ); ?> />
631 <?php esc_html_e( 'This is a liveblog', 'liveblog' ); ?>
632 </label>
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
633
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
634 <?php
635 wp_nonce_field( self::nonce_key, self::nonce_key, false );
8ff4206 @mjangda v1
mjangda authored
636 }
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
637
638 /**
639 * Save the metabox when the post is saved
640 *
641 * @param type $post_id
642 * @return type
643 */
644 public function save_meta_box( $post_id ) {
645
646 // Bail if no liveblog nonce
647 if ( empty( $_POST[self::nonce_key] ) || ! wp_verify_nonce( $_POST[self::nonce_key], self::nonce_key ) )
8ff4206 @mjangda v1
mjangda authored
648 return;
649
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
650 // Update liveblog beta
651 if ( ! empty( $_POST['is-liveblog'] ) )
8ff4206 @mjangda v1
mjangda authored
652 update_post_meta( $post_id, self::key, 1 );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
653
654 // Delete liveblog meta
8ff4206 @mjangda v1
mjangda authored
655 else
656 delete_post_meta( $post_id, self::key );
657 }
2ba7f86 @nb Remove trailing whitespace
nb authored
658
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
659 /** Error Methods *********************************************************/
660
661 /**
662 * Can the current user edit liveblog data (non-ajax)
663 *
664 * @return bool
665 */
666 public static function current_user_can_edit_liveblog() {
667 return (bool) current_user_can( apply_filters( 'liveblog_edit_cap', self::edit_cap ) );
8ff4206 @mjangda v1
mjangda authored
668 }
669
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
670 /**
671 * Can the current user edit liveblog data (ajax)
672 *
673 * Sends an error if not
674 */
675 public static function ajax_current_user_can_edit_liveblog() {
b58c3a0 @nb Remove leading underscores from function names
nb authored
676 if ( ! self::current_user_can_edit_liveblog() ) {
69f9cbb @nb Add more specific HTTP error codes
nb authored
677 self::send_forbidden_error( __( "Cheatin', uh?", 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
678 }
679 }
680
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
681 /**
682 * Check for valid intention, and send an error if there is none
683 *
684 * @param string $action
685 */
686 public static function ajax_check_nonce( $action = self::nonce_key ) {
8ff4206 @mjangda v1
mjangda authored
687 if ( ! isset( $_REQUEST[ self::nonce_key ] ) || ! wp_verify_nonce( $_REQUEST[ self::nonce_key ], $action ) ) {
69f9cbb @nb Add more specific HTTP error codes
nb authored
688 self::send_forbidden_error( __( 'Sorry, we could not authenticate you.', 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
689 }
690 }
691
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
692 /** Feedback **************************************************************/
693
694 /**
695 * Send an error message
696 * @param type $message
697 */
69f9cbb @nb Add more specific HTTP error codes
nb authored
698 private static function send_server_error( $message ) {
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
699 self::status_header_with_message( 500, $message );
700 exit();
701 }
702
69f9cbb @nb Add more specific HTTP error codes
nb authored
703 private static function send_user_error( $message ) {
704 self::status_header_with_message( 406, $message );
705 exit();
706 }
707
708 private static function send_forbidden_error( $message ) {
709 self::status_header_with_message( 403, $message );
710 exit();
711 }
712
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
713 /**
714 * Encode some data and echo it (possibly without cached headers)
715 *
716 * @param array $data
717 */
718 private static function json_return( $data ) {
20c5b02 @nb Get rid of the intermediate layer completely
nb authored
719 $json_data = json_encode( $data );
8ff4206 @mjangda v1
mjangda authored
720
f2908df @nb Get rid if return functionality in json_return()
nb authored
721 header( 'Content-Type: application/json' );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
722 if ( self::$do_not_cache_response )
6c66757 @nb Do not let the client cache future requests
nb authored
723 nocache_headers();
20c5b02 @nb Get rid of the intermediate layer completely
nb authored
724
725 echo $json_data;
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
726 exit();
d81e042 @nb Extract sending errors in its own method
nb authored
727 }
728
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
729 /**
730 * Modify the header and description in the global array
731 *
732 * @global array $wp_header_to_desc
733 * @param int $status
734 * @param string $message
735 */
736 private static function status_header_with_message( $status, $message ) {
2532397 @nb Send HTTP errors instead of the success flag
nb authored
737 global $wp_header_to_desc;
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
738
739 $status = absint( $status );
740 $official_message = isset( $wp_header_to_desc[$status] ) ? $wp_header_to_desc[$status] : '';
2532397 @nb Send HTTP errors instead of the success flag
nb authored
741 $wp_header_to_desc[$status] = $message;
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
742
2532397 @nb Send HTTP errors instead of the success flag
nb authored
743 status_header( $status );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
744
2532397 @nb Send HTTP errors instead of the success flag
nb authored
745 $wp_header_to_desc[$status] = $official_message;
746 }
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
747
748 /** Plupload Helpers ******************************************************/
749
750 /**
751 * Convert hours to bytes
752 *
753 * @param unknown_type $size
754 * @return unknown
755 */
756 private static function convert_hr_to_bytes( $size ) {
757 $size = strtolower( $size );
758 $bytes = (int) $size;
759
760 if ( strpos( $size, 'k' ) !== false )
761 $bytes = intval( $size ) * 1024;
762 elseif ( strpos( $size, 'm' ) !== false )
763 $bytes = intval( $size ) * 1024 * 1024;
764 elseif ( strpos( $size, 'g' ) !== false )
765 $bytes = intval( $size ) * 1024 * 1024 * 1024;
766
767 return $bytes;
768 }
769
770 /**
771 * Convert bytes to hour
772 *
773 * @param string $bytes
774 * @return string
775 */
776 private static function convert_bytes_to_hr( $bytes ) {
777 $units = array( 0 => 'B', 1 => 'kB', 2 => 'MB', 3 => 'GB' );
778 $log = log( $bytes, 1024 );
779 $power = (int) $log;
780 $size = pow( 1024, $log - $power );
781
782 return $size . $units[$power];
783 }
784
785 /**
786 * Get the maximum upload file size
787 *
788 * @see wp_max_upload_size()
789 * @return string
790 */
791 private static function max_upload_size() {
792 $u_bytes = self::convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
793 $p_bytes = self::convert_hr_to_bytes( ini_get( 'post_max_size' ) );
794 $bytes = apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
795
796 return $bytes;
a6429c8 @nb Remove trailing whitespace
nb authored
797 }
8ff4206 @mjangda v1
mjangda authored
798 }
799
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
800 /**
801 * Load the one true WPCOM_Liveblog instance
802 *
803 * Loaded late on the 'plugins_loaded' hook to allow any other plugin to sneak
804 * in ahead of it, to add actions, filters, etc...
805 *
806 * @uses WPCOM_Liveblog::load()
807 */
808 function wpcom_liveblog_load() {
809 WPCOM_Liveblog::load();
810 }
811 add_action( 'plugins_loaded', 'wpcom_liveblog_load', 999 );
812
8ff4206 @mjangda v1
mjangda authored
813 endif;
Something went wrong with that request. Please try again.