Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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