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