Exemple #1
0
 /**
  * Main AJAX callback
  *
  * @param object The post fragment object
  */
 function callback($post_data)
 {
     if (!property_exists($post_data, 'postID') || !property_exists($post_data, 'isSticky')) {
         self::die_failure('invalid_message', __('Insufficient information provided.', 'o2'));
     }
     $post = get_post(absint($post_data->postID));
     if (!$post) {
         self::die_failure('post_not_found', __('Post not found.', 'o2'));
     }
     if (!current_user_can('edit_post', $post->ID)) {
         self::die_failure('cannot_edit_post_sticky', __('You are not allowed to edit this post sticky.', 'o2'));
     }
     if ($post_data->isSticky) {
         stick_post($post->ID);
     } else {
         unstick_post($post->ID);
     }
     // Bump the post to make it update in polling
     o2_Fragment::bump_post($post->ID);
     $retval = array('isSticky' => is_sticky($post->ID));
     self::die_success($retval);
 }
Exemple #2
0
 public static function poll()
 {
     // This is a super lightweight API to get posts and comments from WP
     // It's intended for use with o2
     // @todo Allow requesting a specific post or comment, and a post with all comments
     // Need to sort things because they're queried separately
     function o2_date_sort($a, $b)
     {
         if ($a->unixtime == $b->unixtime) {
             return 0;
         }
         return $a->unixtime > $b->unixtime ? -1 : 1;
     }
     $ok_to_serve_data = true;
     $ok_to_serve_data = apply_filters('o2_read_api_ok_to_serve_data', $ok_to_serve_data);
     $data = array();
     if ($ok_to_serve_data) {
         $posts = self::get_posts();
         $comments = self::get_comments();
         // Clean up posts and comments
         $data = array();
         if (count($posts)) {
             foreach ($posts as $post) {
                 $data[] = o2_Fragment::get_fragment($post);
             }
         }
         if (count($comments)) {
             foreach ($comments as $comment) {
                 $data[] = o2_Fragment::get_fragment($comment);
             }
         }
         // Shuffle up and deal
         usort($data, 'o2_date_sort');
     }
     // Let the client know if the user is logged in or not
     $is_logged_in = is_user_logged_in();
     // Generate an updated nonce (they expire after all, and our "app" may be open for a long time)
     $new_nonce = wp_create_nonce('o2_nonce');
     if ($is_logged_in) {
         // @todo change to another way, and one that is less costly - see also below
         // $current_user_id = get_current_user_id();
         // update_user_meta( $current_user_id, 'o2_last_poll_gmt', time() );
     }
     $response = array("data" => $data, "newNonce" => $new_nonce, "loggedIn" => $is_logged_in);
     // Check for unloaded scripts and styles if there are polled posts
     if (!empty($data)) {
         // Attach scripts
         if (isset($_REQUEST['scripts'])) {
             // Parse and sanitize the script handles already output
             if (!is_array($_REQUEST['scripts'])) {
                 $_REQUEST['scripts'] = explode(',', $_REQUEST['scripts']);
             }
             $initial_scripts = is_array($_REQUEST['scripts']) ? array_map('sanitize_text_field', $_REQUEST['scripts']) : null;
             if (is_array($initial_scripts)) {
                 global $wp_scripts;
                 if (!$wp_scripts instanceof WP_Scripts) {
                     $wp_scripts = new WP_Scripts();
                 }
                 // Identify new scripts needed by the polled posts
                 $polled_scripts = array_diff($wp_scripts->done, $initial_scripts);
                 // If new scripts are needed, extract relevant data from $wp_scripts
                 if (!empty($polled_scripts)) {
                     $response['scripts'] = array();
                     foreach ($polled_scripts as $handle) {
                         // Abort if the handle doesn't match a registered script
                         if (!isset($wp_scripts->registered[$handle])) {
                             continue;
                         }
                         // Provide basic script data
                         $script_data = array('handle' => $handle, 'footer' => is_array($wp_scripts->in_footer) && in_array($handle, $wp_scripts->in_footer), 'extra_data' => $wp_scripts->print_extra_script($handle, false));
                         // Base source
                         $src = $wp_scripts->registered[$handle]->src;
                         // Take base_url into account
                         if (strpos($src, '//') === 0) {
                             $src = is_ssl() ? 'https:' . $src : 'http:' . $src;
                         }
                         // Deal with root-relative URLs
                         if (strpos($src, '/') === 0) {
                             $src = $wp_scripts->base_url . $src;
                         }
                         if (strpos($src, 'http') !== 0) {
                             $src = $wp_scripts->base_url . $src;
                         }
                         // Version and additional arguments
                         if (null === $wp_scripts->registered[$handle]->ver) {
                             $ver = '';
                         } else {
                             $ver = $wp_scripts->registered[$handle]->ver ? $wp_scripts->registered[$handle]->ver : $wp_scripts->default_version;
                         }
                         if (isset($wp_scripts->args[$handle])) {
                             $ver = $ver ? $ver . '&' . $wp_scripts->args[$handle] : $wp_scripts->args[$handle];
                         }
                         // Full script source with version info
                         $script_data['src'] = add_query_arg('ver', $ver, $src);
                         // Add script to data that will be returned to o2
                         array_push($response['scripts'], $script_data);
                     }
                 }
             }
         }
         // Attach styles
         if (isset($_REQUEST['styles'])) {
             // Parse and sanitize the script handles already output
             if (!is_array($_REQUEST['styles'])) {
                 $_REQUEST['styles'] = explode(',', $_REQUEST['styles']);
             }
             // Parse and sanitize the style handles already output
             $initial_styles = is_array($_REQUEST['styles']) ? array_map('sanitize_text_field', $_REQUEST['styles']) : null;
             if (is_array($initial_styles)) {
                 global $wp_styles;
                 // Identify new styles needed by the polled posts
                 $polled_styles = array_diff($wp_styles->done, $initial_styles);
                 // If new styles are needed, extract relevant data from $wp_styles
                 if (!empty($polled_styles)) {
                     $response['styles'] = array();
                     foreach ($polled_styles as $handle) {
                         // Abort if the handle doesn't match a registered stylesheet
                         if (!isset($wp_styles->registered[$handle])) {
                             continue;
                         }
                         // Provide basic style data
                         $styles_data = array('handle' => $handle, 'media' => 'all');
                         // Base source
                         $src = $wp_styles->registered[$handle]->src;
                         // Take base_url into account
                         if (strpos($src, 'http') !== 0) {
                             $src = $wp_styles->base_url . $src;
                         }
                         // Version and additional arguments
                         if (null === $wp_styles->registered[$handle]->ver) {
                             $ver = '';
                         } else {
                             $ver = $wp_styles->registered[$handle]->ver ? $wp_styles->registered[$handle]->ver : $wp_styles->default_version;
                         }
                         if (isset($wp_styles->args[$handle])) {
                             $ver = $ver ? $ver . '&' . $wp_styles->args[$handle] : $wp_styles->args[$handle];
                         }
                         // Full script source with version info
                         $script_data['src'] = add_query_arg('ver', $ver, $src);
                         // @todo Handle parsing conditional comments
                         // Parse requested media context for stylesheet
                         if (isset($wp_styles->registered[$handle]->args)) {
                             $style_data['media'] = esc_attr($wp_styles->registered[$handle]->args);
                         }
                         // Add script to data that will be returned to o2
                         array_push($response['styles'], $style_data);
                     }
                 }
             }
         }
     }
     wp_send_json_success($response);
 }
Exemple #3
0
 function update_object_content($object_type, $object_ID, $updated_content)
 {
     $updated_object = false;
     if ('post' == $object_type) {
         o2_Fragment::bump_post($object_ID, $updated_content);
         $updated_object = get_post($object_ID);
     } else {
         $comment_data = array('comment_ID' => $object_ID, 'comment_content' => $updated_content);
         // purposefully throw away the comment global otherwise get_comment will return
         // the pre-updated copy from $GLOBALS
         if (isset($GLOBALS['comment'])) {
             unset($GLOBALS['comment']);
         }
         wp_update_comment($comment_data);
         update_comment_meta($object_ID, 'o2_comment_gmt_modified', time());
         $updated_object = get_comment($object_ID);
         // update the global
         $GLOBALS['comment'] = $updated_object;
     }
     return $updated_object;
 }
Exemple #4
0
function o2_live_comments_widget_footer_bootstrap()
{
    // embed in the footer the most recent N comments and M posts based
    // on the widget settings
    $comment_count = 0;
    $post_count = 0;
    $settings_array = get_option('widget_o2-live-comments-widget');
    if (is_array($settings_array)) {
        foreach ((array) $settings_array as $settings) {
            if (is_array($settings)) {
                if (isset($settings['kind']) && isset($settings['number'])) {
                    $kind = $settings['kind'];
                    $count = intval($settings['number']);
                    if (0 > $count) {
                        $count = 0;
                    }
                    if ("both" == $kind) {
                        $comment_count = max($comment_count, $count);
                        $post_count = max($post_count, $count);
                    } else {
                        if ("comment" == $kind) {
                            $comment_count = max($comment_count, $count);
                        } else {
                            if ("post" == $kind) {
                                $post_count = max($post_count, $count);
                            }
                        }
                    }
                }
            }
        }
    }
    $live_bootstrap = array();
    // Bootstrap comments, as needed based on widget settings
    if (0 < $comment_count) {
        $comments = get_comments(array('status' => 'approve', 'number' => $comment_count));
        // instead of using get_fragment, which is terribly verbose, we use lighterweight emitters here
        foreach ((array) $comments as $comment) {
            $comment_ID = $comment->comment_ID;
            $comment_post_ID = $comment->comment_post_ID;
            $title = html_entity_decode(get_the_title($comment->comment_post_ID));
            $comment_bootstrap = array('unixtime' => strtotime($comment->comment_date_gmt), 'title' => $title, 'domRef' => "#comment-" . $comment_ID, 'permalink' => get_permalink($comment_post_ID) . '#comment-' . $comment_ID, 'type' => 'comment', 'externalID' => $comment_ID, 'postID' => $comment->comment_post_ID);
            $commentor = o2_Fragment::get_comment_author_properties($comment);
            $live_bootstrap[] = array_merge($comment_bootstrap, $commentor);
        }
    }
    // Bootstrap posts, as needed based on widget settings
    if (0 < $post_count) {
        $posts = get_posts(array('post_status' => 'publish', 'number' => $post_count));
        foreach ((array) $posts as $post) {
            $post_ID = $post->ID;
            $title = html_entity_decode($post->post_title);
            $post_bootstrap = array('unixtime' => strtotime($post->post_date_gmt), 'title' => $title, 'domRef' => "#post-" . $post_ID, 'permalink' => get_permalink($post_ID), 'type' => 'post', 'externalID' => $post_ID);
            $poster = o2_Fragment::get_post_user_properties($post);
            $live_bootstrap[] = array_merge($post_bootstrap, $poster);
        }
    }
    echo "<script class='o2-live-widget-bootstrap-data' type='application/json' style='display:none'>";
    echo json_encode($live_bootstrap);
    echo "</script>\n";
    // split this and the widgets init out into a separate class.  maybe rename the containing directory to simply live-comments
}
Exemple #5
0
 /**
  * Main AJAX callback
  *
  * Determine if a post's next state is valid, set it, and return the audit log fragment as success, or
  * an error message as failure
  *
  * @param object The post fragment object
  */
 function callback($post_data)
 {
     if (!property_exists($post_data, 'postID') || !property_exists($post_data, 'nextState')) {
         self::die_failure('invalid_message', __('Insufficient information provided.', 'o2'));
     }
     $post = get_post(absint($post_data->postID));
     if (!$post) {
         self::die_failure('post_not_found', __('Post not found.', 'o2'));
     }
     if (!current_user_can('edit_post', $post->ID)) {
         self::die_failure('cannot_edit_post_resolution', __('You are not allowed to edit this post resolution', 'o2'));
     }
     if (in_array($post_data->nextState, self::get_state_slugs())) {
         $next_state = sanitize_key($post_data->nextState);
     } else {
         self::die_failure('invalid_post_resolution', __('Invalid post resolution.', 'o2'));
     }
     $success = self::change_post_state($post->ID, $next_state);
     if (is_wp_error($success)) {
         self::die_failure('cannot_set_post_resolution', __('Unable to set post resolution.', 'o2'));
     } else {
         $audit_log = self::get_audit_log_fragment($success);
     }
     $post_terms = o2_Fragment::get_post_terms($post->ID);
     $retval = array('currentState' => $next_state, 'auditLog' => $audit_log);
     self::die_success($retval);
 }
Exemple #6
0
 /**
  * Called from the end of the core commenting process. If we get here
  * then the comment was posted successfully, so just output it and die.
  */
 public static function comment_success($comment)
 {
     do_action('o2_writeapi_comment_created', $comment->comment_ID);
     self::die_success(o2_Fragment::get_fragment($comment));
 }
Exemple #7
0
 /**
  * Called from the end of the core commenting process. If we get here
  * then the comment was posted successfully, so just output it and die.
  */
 public static function comment_success($comment)
 {
     self::die_success(o2_Fragment::get_fragment($comment));
 }
Exemple #8
0
 public function ajax_get_o2_userdata()
 {
     // returns the o2 userdata for the given userLogin, or an error if a bad userLogin was given
     // note:  both priv and nopriv hit this, since o2s can be read by nopriv users
     $ok_to_serve_data = apply_filters('o2_read_api_ok_to_serve_data', true);
     if (!$ok_to_serve_data) {
         wp_send_json_error(array('errorText' => 'Unauthorized'));
     }
     if (isset($_GET['userlogin'])) {
         // V1 userlogin (singular)
         // it will be OK to remove this case after the new V2 has been deployed
         // for a day or two, so as to not disrupt V1 clients that are still active
         $user_login = $_GET['userlogin'];
         $user = get_user_by('login', $user_login);
         if (false === $user) {
             wp_send_json_error(array('errorText' => 'Invalid request'));
         }
         // Otherwise, create and send the model
         $user_data = get_userdata($user->ID);
         $user_model = o2_Fragment::get_model_from_userdata($user_data);
         wp_send_json_success($user_model);
     } else {
         // V2 userlogins (array of 1 or more)
         $user_logins = $_GET['userlogins'];
         $user_models = array();
         foreach ((array) $user_logins as $user_login) {
             $user = get_user_by('login', $user_login);
             if (false != $user) {
                 $user_data = get_userdata($user->ID);
                 $user_models[] = o2_Fragment::get_model_from_userdata($user_data);
             }
         }
         if (0 == count($user_models)) {
             wp_send_json_error(array('errorText' => 'Invalid request'));
         }
         wp_send_json_success($user_models);
     }
 }
Exemple #9
0
 public static function get_fragment_from_comment($my_comment)
 {
     add_filter('home_url', array('o2_Fragment', 'home_url'), 10, 4);
     // Update the global comment variable for methods like get_comment_ID used by comment_like_current_user_likes
     global $comment;
     if (isset($comment)) {
         $old_comment = $comment;
     }
     $comment = $my_comment;
     // Update the global post variable for methods like $wp_embed->autoembed that need it
     global $post;
     if (isset($post)) {
         $old_post = $post;
     }
     $post = get_post($my_comment->comment_post_ID);
     $comment_ID = $my_comment->comment_ID;
     $permalink = get_permalink($my_comment->comment_post_ID) . '#comment-' . $comment_ID;
     $permalink = apply_filters('o2_comment_permalink', $permalink, $comment_ID);
     $approved = '1' == $my_comment->comment_approved;
     $is_trashed = 'trash' == $my_comment->comment_approved;
     $previously_deleted = get_comment_meta($comment_ID, 'o2_comment_prev_deleted', true);
     // Update the $comment_depth global with our findings so that get_comment_class will
     // work correctly
     global $comment_depth;
     $comment_depth = o2_Fragment::get_depth_for_comment($comment);
     // These calls with empty args will rely on global $comment
     $edit_comment_link = get_edit_comment_link();
     $comment_class_array = get_comment_class();
     $comment_class = !empty($comment_class_array);
     if ($comment_class) {
         // Let's add trashed and deleted classes to the comment for styling.
         if ($is_trashed) {
             $comment_class_array[] = 'o2-trashed';
         }
         if ($previously_deleted) {
             $comment_class_array[] = 'o2-deleted';
         }
         $comment_class = join(' ', $comment_class_array);
     }
     $comment_created = get_comment_meta($comment_ID, 'o2_comment_created', true);
     if (empty($comment_created)) {
         $comment_created = strtotime($comment->comment_date_gmt);
     }
     // Convert HTML entities in the comment_content back to their actual characters
     // So that the JSON encoded value is the same thing the user edited in their
     // comment in the first place.
     // In this way, if/when they edit the comment, they don't get things like &lt;p&gt;
     // in the editor, but get <p> instead
     $raw_content = htmlspecialchars_decode($my_comment->comment_content, ENT_QUOTES);
     $raw_post_title = html_entity_decode(get_the_title($my_comment->comment_post_ID));
     // Mentions
     list($mentions, $mention_context) = self::get_mention_data('comment', $comment_ID, $raw_content);
     $fragment = array('type' => 'comment', 'id' => $comment_ID, 'postID' => $my_comment->comment_post_ID, 'postTitleRaw' => $raw_post_title, 'cssClasses' => $comment_class, 'parentID' => $my_comment->comment_parent, 'contentRaw' => $raw_content, 'contentFiltered' => apply_filters('comment_text', $my_comment->comment_content, $my_comment, array()), 'permalink' => $permalink, 'unixtime' => strtotime($my_comment->comment_date_gmt), 'loginRedirectURL' => wp_login_url($permalink), 'approved' => $approved, 'isTrashed' => $is_trashed, 'prevDeleted' => $previously_deleted, 'editURL' => $edit_comment_link, 'depth' => $comment_depth, 'commentDropdownActions' => o2_get_comment_actions('dropdown', $comment, $comment_depth), 'commentFooterActions' => o2_get_comment_actions('footer', $comment, $comment_depth), 'commentTrashedActions' => o2_get_comment_actions('trashed_dropdown', $comment, $comment_depth), 'mentions' => $mentions, 'mentionContext' => $mention_context, 'commentCreated' => $comment_created, 'hasChildren' => (bool) get_comment_meta($comment_ID, 'o2_comment_has_children', true));
     // Get author properties (and bootstrap the rest of the model)
     // e.g. userLogin or noprivUserName, noprivUserHash and noprivUserURL for nopriv commentor
     $comment_author_properties = self::get_comment_author_properties($my_comment);
     $fragment = array_merge($fragment, $comment_author_properties);
     // Put the original globals back
     if (isset($old_comment)) {
         $comment = $old_comment;
     }
     if (isset($old_post)) {
         $post = $old_post;
     }
     remove_filter('home_url', array('o2_Fragment', 'home_url'), 10, 4);
     $fragment = apply_filters('o2_comment_fragment', $fragment, $comment_ID);
     // Force UTF8 to avoid JSON encode issues
     $fragment = self::to_utf8($fragment);
     return $fragment;
 }