diff -r c7c0fbc09788 -r 5e8dcbe22c24 web/wp-content/plugins/social/social.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/wp-content/plugins/social/social.php Tue Dec 04 18:43:10 2012 -0800 @@ -0,0 +1,2253 @@ +MailChimp. +Version: 2.6 +Author: Crowd Favorite +Author URI: http://crowdfavorite.com/ +*/ + +if (!class_exists('Social')) { // try to avoid double-loading... + +/** + * Social Core + * + * @package Social + */ +final class Social { + + /** + * @var string URL of the API + */ + public static $api_url = 'https://sopresto.mailchimp.com/'; + + /** + * @var string version number + */ + public static $version = '2.6'; + + /** + * @var string CRON lock directory. + */ + public static $cron_lock_dir = null; + + /** + * @var string plugins URL + */ + public static $plugins_url = ''; + + /** + * @var string plugins file path + */ + public static $plugins_path = ''; + + /** + * @var bool loaded by theme? + */ + public static $loaded_by_theme = false; + + /** + * @var string duplicate comment message + */ + public static $duplicate_comment_message = 'duplicate comment'; + + /** + * @var Social_Log logger + */ + private static $log = null; + + /** + * @var array default options + */ + protected static $options = array( + 'debug' => false, + 'install_date' => 0, + 'installed_version' => 0, + 'broadcast_format' => '{title}: {content} {url}', + 'comment_broadcast_format' => '{content} {url}', + 'system_cron_api_key' => null, + 'fetch_comments' => '1', + 'broadcast_by_default' => '0', + 'use_standard_comments' => '0', + ); + + /** + * @var Social instance of Social + */ + public static $instance = null; + + /** + * Loads the instance of Social. + * + * @static + * @return Social + */ + public static function instance() { + if (self::$instance === null) { + self::$instance = new self; + } + + return self::$instance; + } + + /** + * Handles the auto loading of classes. + * + * @static + * + * @param string $class + * + * @return bool + */ + public static function auto_load($class) { + if (substr($class, 0, 7) == 'Social_' or substr($class, 0, 7) == 'Kohana_') { + try { + $file = Social::$plugins_path.'lib/'.str_replace('_', '/', strtolower($class)).'.php'; + $file = apply_filters('social_auto_load_file', $file, $class); + if (file_exists($file)) { + require $file; + + return true; + } + + return false; + } + catch (Exception $e) { + Social::log(sprintf(__('Failed to auto load class %s.', 'social'), $class)); + } + } + + return true; + } + + /** + * Returns the broadcast format tokens. + * + * Format: + * + * {key} => __('Description', 'social') + * + * @static + * @return array + */ + public static function broadcast_tokens() { + $query = new WP_Query(array( + 'posts_per_page' => 1 + )); + if (count($query->posts) and $post = $query->posts[0]) { + $url = wp_get_shortlink($post->ID); + $date = get_date_from_gmt($post->post_date_gmt); + } + else { + $url = home_url('?p=123'); + $date = get_date_from_gmt(current_time('mysql', true)); + } + + $defaults = array( + '{url}' => sprintf(__('Example: %s', 'social'), $url), + '{title}' => '', + '{content}' => '', + '{date}' => sprintf(__('Example: %s', 'social'), $date), + '{author}' => '', + ); + + return apply_filters('social_broadcast_tokens', $defaults); + } + + /** + * Returns the comment broadcast format tokens. + * + * Format: + * + * {key} => __('Description', 'social') + * + * @static + * @return mixed + */ + public static function comment_broadcast_tokens() { + $defaults = array( + '{content}' => '', + '{url}' => '', + ); + return apply_filters('social_comment_broadcast_tokens', $defaults); + } + + /** + * Sets or gets an option based on the key defined. + * + * Get Format: + * + * Running Social::option('option_name') will load "social_option_name" using get_option() + * + * Set Format: + * + * Running Social::option('option_name', 'new_value') will update "social_option_name" to "new_value" + * using update_option(). + * + * @static + * @param string $key option key + * @param mixed $value option value + * @return bool|mixed + * @uses get_option() + * @uses update_option() + */ + public static function option($key, $value = null) { + if ($value === null) { + $default = null; + if (isset(Social::$options[$key])) { + $default = Social::$options[$key]; + } + + return get_option('social_'.$key, $default); + } + + update_option('social_'.$key, $value); + return false; + } + + /** + * Add a message to the log. + * + * @static + * @param string $message message to add to the log + * @param array $args arguments to pass to the writer + * @param string $context context of the log message + * @param bool $backtrace show the backtrace + * @return void + */ + public static function log($message, array $args = null, $context = null, $backtrace = false) { + Social::$log->write($message, $args, $context, $backtrace); + } + + /** + * Sets the loaded by theme. + * + * @static + * @return void + */ + public static function social_loaded_by_theme() { + self::$loaded_by_theme = true; + } + + /** + * Sets the customer die handler. + * + * @static + * @param string $handler + * @return array + */ + public static function wp_die_handler($handler) { + return array('Social', 'wp_comment_die_handler'); + } + + /** + * Don't actually die for aggregation runs. + * + * @static + * @param string $message + * @param string $title + * @param array $args + * @return mixed + */ + public static function wp_comment_die_handler($message, $title, $args) { + if ($message == __('Duplicate comment detected; it looks as though you’ve already said that!')) { + // Keep going + throw new Exception(Social::$duplicate_comment_message); + } + } + + /** + * @var bool is Social enabled? + */ + private $_enabled = null; + + /** + * Returns an array of all of the services. + * + * Format of the data returned: + * + * $services = array( + * 'twitter' => Social_Service_Twitter, + * 'facebook' => Social_Service_Facebook, + * // ... any other services registered + * ) + * + * @return array + */ + public function services() { + return $this->load_services(); + } + + /** + * Returns a service by access key. + * + * Loading a service: + * + * $twitter = Social::instance()->service('twitter'); + * + * @param string $key service key + * @return mixed Social_Service|Social_Service_Twitter|Social_Service_Facebook|false + */ + public function service($key) { + $services = $this->load_services(); + if (!isset($services[$key])) { + return false; + } + return $services[$key]; + } + + /** + * Returns a service by comment type. + * + * Loading a service: + * + * $twitter = Social::instance()->service_for_comment_type('social-twitter-rt'); + * + * @param string $key service key + * @return mixed Social_Service|Social_Service_Twitter|Social_Service_Facebook|false + */ + public function service_for_comment_type($comment_type) { + $services = $this->load_services(); + foreach ($services as $service) { + if (in_array($comment_type, $service->comment_types())) { + return $service; + } + } + return false; + } + + /** + * Initializes Social. + * + * @wp-action init + * @return void + */ + public function init() { + // Load the language translations + if (Social::$loaded_by_theme) { + $path = trailingslashit(Social::$plugins_path).'lang'; + load_theme_textdomain('social', $path); + } + else { + $plugin_dir = basename(dirname(SOCIAL_FILE)).'/lang'; + load_plugin_textdomain('social', false, $plugin_dir); + } + + if (version_compare(PHP_VERSION, '5.2.4', '<')) { + deactivate_plugins(basename(__FILE__)); // Deactivate ourself + wp_die(__("Sorry, Social requires PHP 5.2.4 or higher. Ask your host how to enable PHP 5 as the default on your servers.", 'social')); + } + + // Just activated? + if (!Social::option('install_date')) { + Social::option('install_date', current_time('timestamp', 1)); + Social::option('system_cron_api_key', wp_generate_password(16, false)); + } + + // Plugins URL + $url = plugins_url('', SOCIAL_FILE); + Social::$plugins_url = trailingslashit(apply_filters('social_plugins_url', $url)); + + Social::$plugins_path = trailingslashit(apply_filters('social_plugins_path', SOCIAL_PATH)); + + // Set the logger + Social::$log = Social_Log::factory(); + + // Require Facebook and Twitter by default. + require Social::$plugins_path.'social-twitter.php'; + require Social::$plugins_path.'social-facebook.php'; + } + + /** + * Auth Cookie expiration for API users. + * + * @return int + */ + public function auth_cookie_expiration() { + return 31536000; // 1 Year + } + + /** + * Enqueues the assets for Social. + * + * @wp-action wp_enqueue_scripts + * @wp-action load-post-new.php + * @wp-action load-post.php + * @wp-action load-profile.php + * @wp-action load-settings_page_social + * @return void + */ + public function enqueue_assets() { + if (Social::option('use_standard_comments') == '1') { + return; + } + // JS/CSS + if (!defined('SOCIAL_COMMENTS_JS')) { + define('SOCIAL_COMMENTS_JS', Social::$plugins_url.'assets/social.js'); + } + if (SOCIAL_COMMENTS_JS !== false) { + wp_enqueue_script('jquery'); + wp_enqueue_script('social_js', SOCIAL_COMMENTS_JS, array('jquery'), Social::$version, true); + wp_localize_script('social_js', 'Sociali18n', array( + 'commentReplyTitle' => __('Post a Reply', 'social'), + )); + } + + if (!is_admin()) { + if (!defined('SOCIAL_COMMENTS_CSS')) { + define('SOCIAL_COMMENTS_CSS', Social::$plugins_url.'assets/comments.css'); + } + if (SOCIAL_COMMENTS_CSS !== false) { + wp_enqueue_style('social_comments', SOCIAL_COMMENTS_CSS, array(), Social::$version, 'screen'); + } + } + + } + + /** + * Enqueues the assets for Social. + * + * @wp-action admin_enqueue_scripts + * @return void + */ + public function admin_enqueue_assets() { + if (!defined('SOCIAL_ADMIN_JS')) { + define('SOCIAL_ADMIN_JS', Social::$plugins_url.'assets/admin.js'); + } + + if (!defined('SOCIAL_ADMIN_CSS')) { + define('SOCIAL_ADMIN_CSS', Social::$plugins_url.'assets/admin.css'); + } + + if (SOCIAL_ADMIN_CSS !== false) { + wp_enqueue_style('social_admin', SOCIAL_ADMIN_CSS, array(), Social::$version, 'screen'); + } + + if (SOCIAL_ADMIN_JS !== false) { + wp_enqueue_script('social_admin', SOCIAL_ADMIN_JS, array(), Social::$version, true); + $data = apply_filters('social_admin_js_strings', array( + 'protectedTweet' => __('Protected Tweet', 'social'), + 'invalidUrl' => __('Invalid URL', 'social'), + )); + wp_localize_script('social_admin', 'socialAdminL10n', $data); + } + } + + /** + * Loads the services on every page if the user is an admin. + * + * @wp-action admin_init + * @return void + */ + public function admin_init() { + if (current_user_can('manage_options') or current_user_can('publish_posts')) { + // Trigger upgrade? + if (isset($_GET['page']) and $_GET['page'] == basename(SOCIAL_FILE)) { + global $wpdb; + + // First check for the semaphore options, they need to be added before the upgrade starts. + $results = $wpdb->get_results(" + SELECT option_id + FROM $wpdb->options + WHERE option_name IN ('social_locked', 'social_unlocked') + "); + if (!count($results)) { + update_option('social_unlocked', '1'); + update_option('social_last_lock_time', current_time('mysql', 1)); + update_option('social_semaphore', '0'); + } + + if (version_compare(Social::option('installed_version'), Social::$version, '<')) { + $this->_enabled = false; + $this->upgrade(); + } + } + + if ($this->_enabled === null) { + $this->load_services(); + } + } + + // Redirect to the home_url() if the user is a commenter. + if (!current_user_can('publish_posts')) { + $commenter = get_user_meta(get_current_user_id(), 'social_commenter', true); + if (!empty($commenter) and $commenter == 'true') { + wp_redirect(trailingslashit(home_url())); + } + } + } + + /** + * Checks to see if system crons are disabled. + * + * @wp-action load-settings_page_social + * @return void + */ + public function check_system_cron() { + Social::log('Checking system CRON'); + // Schedule CRONs + if (Social::option('fetch_comments') == '1') { + if (wp_next_scheduled('social_cron_15_init') === false) { + Social::log('Adding Social 15 CRON schedule'); + wp_schedule_event(time() + 900, 'every15min', 'social_cron_15_init'); + } + wp_remote_get( + admin_url('options_general.php?'.http_build_query(array( + 'social_controller' => 'cron', + 'social_action' => 'check_crons', + 'social_api_key' => Social::option('system_cron_api_key') + ), null, '&')), + array( + 'timeout' => 0.01, + 'blocking' => false, + 'sslverify' => apply_filters('https_local_ssl_verify', true), + ) + ); + } + } + + /** + * Handlers requests. + * + * @wp-action init + * @return void + */ + public function request_handler() { + if (isset($_GET['social_controller'])) { + Social_Request::factory()->execute(); + } + } + + /** + * Adds a link to the "Settings" menu in WP-Admin. + * + * @wp-action admin_menu + * @return void + */ + public function admin_menu() { + add_options_page( + __('Social Options', 'social'), + __('Social', 'social'), + 'manage_options', + basename(SOCIAL_FILE), + array( + $this, + 'admin_options_form' + ) + ); + } + + /** + * Add Settings link to plugins - code from GD Star Ratings + * + * @wp-filter plugin_action_links + * @param array $links + * @param string $file + * @return array + */ + public function add_settings_link($links, $file) { + static $this_plugin; + if (!$this_plugin) { + $this_plugin = plugin_basename(__FILE__); + } + + if ($file == $this_plugin) { + $settings_link = ''.__('Settings', 'social').''; + array_unshift($links, $settings_link); + } + return $links; + } + + /** + * Handles the display of different messages for admin notices. + * + * @wp-action admin_notices + * @action admin_notices + */ + public function admin_notices() { + if (current_user_can('manage_options') or current_user_can('publish_posts')) { + // Upgrade notice + if (version_compare(Social::option('installed_version'), Social::$version, '<')) { + $message = sprintf(__('Social is shiny and new! Please verify and save your settings to complete the upgrade.', 'social'), esc_url(Social::settings_url())); + echo '

'.$message.'

'; + } + + $suppress_no_accounts_notice = get_user_meta(get_current_user_id(), 'social_suppress_no_accounts_notice', true); + if (!$this->_enabled and (!isset($_GET['page']) or $_GET['page'] != basename(SOCIAL_FILE)) and empty($suppress_no_accounts_notice)) { + $dismiss = sprintf(__('[Dismiss]', 'social'), esc_url(admin_url('options-general.php?social_controller=settings&social_action=suppress_no_accounts_notice'))); + $message = sprintf(__('To start using Social, please add an account.', 'social'), esc_url(Social::settings_url())); + echo '

'.$message.' '.$dismiss.'

'; + } + + if (isset($_GET['page']) and $_GET['page'] == basename(SOCIAL_FILE)) { + // CRON Lock + if (Social::option('cron_lock_error') !== null) { + $upload_dir = wp_upload_dir(); + if (is_writeable(Social::$plugins_path) or (isset($upload_dir['basedir']) and is_writeable($upload_dir['basedir']))) { + delete_option('social_cron_lock_error'); + } + else { + if (isset($upload_dir['basedir'])) { + $message = sprintf(__('Social requires that either %s or %s be writable for CRON jobs.', 'social'), esc_html(Social::$plugins_path), esc_html($upload_dir['basedir'])); + } + else { + $message = sprintf(__('Social requires that %s is writable for CRON jobs.', 'social'), esc_html(Social::$plugins_path)); + } + + echo '

'.esc_html($message).'

'; + } + } + + // Enable notice? + $suppress_enable_notice = get_user_meta(get_current_user_id(), 'social_suppress_enable_notice', true); + if (empty($suppress_enable_notice)) { + $message = __('When you enable Social, users will be created when they log in with Facebook or Twitter to comment. These users are created without a role and will be prevented from accessing the admin side of WordPress until an administrator edits the user to give them a role.', 'social'); + $dismiss = sprintf(__('[Dismiss]', 'social'), esc_url(admin_url('options-general.php?social_controller=settings&social_action=suppress_enable_notice'))); + echo '

'.$message.' '.$dismiss.'

'; + } + } + + // Log write error + $error = Social::option('log_write_error'); + if ($error == '1') { + echo '

'. + sprintf(__('%s needs to be writable for Social\'s logging. ', 'social'), esc_html(Social::$plugins_path), esc_url(admin_url('options-general.php?social_controller=settings&social_action=clear_log_write_error'))). + '

'; + } + } + + // Deauthed accounts + $deauthed = Social::option('deauthed'); + if (!empty($deauthed)) { + foreach ($deauthed as $service => $data) { + foreach ($data as $id => $message) { + $dismiss = sprintf(__('[Dismiss]', 'social'), esc_url(admin_url('options-general.php?social_controller=settings&social_action=clear_deauth&id='.$id.'&service='.$service)), 'social_dismiss'); + echo '

'.esc_html($message).' '.$dismiss.'

'; + } + } + } + + // Errored broadcasting? + global $post; + if (isset($post->ID)) { + $error_accounts = get_post_meta($post->ID, '_social_broadcast_error', true); + if (!empty($error_accounts)) { + $message = Social_View::factory('wp-admin/post/broadcast/error/notice', array( + 'social' => $this, + 'accounts' => $error_accounts, + 'post' => $post, + )); + echo '
'.$message.'
'; + + delete_post_meta($post->ID, '_social_broadcast_error'); + } + } + + // 2.0 Upgrade? + $upgrade_2_0 = get_user_meta(get_current_user_id(), 'social_2.0_upgrade', true); + if (!empty($upgrade_2_0)) { + if (current_user_can('manage_options')) { + $output = __('Social needs to re-authorize your Facebook account(s). Please re-connect your global and personal accounts.', 'social'); + $output = sprintf($output, esc_url(Social::settings_url()), esc_url(admin_url('profile.php#social-accounts'))); + } + else { + $output = __('Social needs to re-authorize your Facebook account(s).. Please re-connect your personal accounts.', 'social'); + $output = sprintf($output, esc_url(admin_url('profile.php#social-networks'))); + } + + $dismiss = sprintf(__('[Dismiss]', 'social'), esc_url(admin_url('options-general.php?social_controller=settings&social_action=clear_2_0_upgrade')), 'social_dismiss'); + echo '

'.$output.' '.$dismiss.'

'; + } + } + + /** + * Displays the admin options form. + * + * @return void + */ + public function admin_options_form() { + Social_Request::factory('settings/index')->execute(); + } + + /** + * Shows the user's social network accounts. + * + * @wp-action show_user_profile + * @param object $profileuser + * @return void + */ + public function show_user_profile($profileuser) { + $default_accounts = get_user_meta($profileuser->ID, 'social_default_accounts', true); + if (empty($default_accounts)) { + $default_accounts = array(); + } + $accounts = array(); + foreach ($this->services() as $key => $service) { + if (!isset($accounts[$key])) { + $accounts[$key] = array(); + } + foreach ($service->accounts() as $account) { + if ($account->personal()) { + $accounts[$key][] = $account->id(); + } + } + } + echo Social_View::factory('wp-admin/profile', array( + 'defaults' => $default_accounts, + 'services' => $this->services(), + 'accounts' => $accounts, + )); + } + + /** + * Saves the default accounts for the user. + * + * @wp-action personal_options_update + * @param int $user_id + * @return void + */ + public function personal_options_update($user_id) { + // Store the default accounts + $accounts = array(); + if (isset($_POST['social_default_accounts']) and is_array($_POST['social_default_accounts'])) { + foreach ($_POST['social_default_accounts'] as $account) { + $account = explode('|', $account); + $accounts[$account[0]][] = $account[1]; + } + } + + // TODO abstract this to the facebook plugin + if (isset($_POST['social_default_pages']) and is_array($_POST['social_default_pages'])) { + if (!isset($accounts['facebook'])) { + $accounts['facebook'] = array( + 'pages' => array() + ); + } + $accounts['facebook']['pages'] = $_POST['social_default_pages']; + } + + if (count($accounts)) { + update_user_meta($user_id, 'social_default_accounts', $accounts); + } + else { + delete_user_meta($user_id, 'social_default_accounts'); + } + + // Save Enabled child accounts + $is_profile = true; + $enabled_child_accounts = is_array($_POST['social_enabled_child_accounts']) ? $_POST['social_enabled_child_accounts'] : array(); + foreach ($this->services() as $service_key => $service) { + $updated_accounts = array(); + foreach ($service->accounts() as $account) { + //default service to empty array in case it is not set + $enabled_child_accounts[$service_key] = isset($enabled_child_accounts[$service_key]) ? $enabled_child_accounts[$service_key] : array(); + + $account->update_enabled_child_accounts($enabled_child_accounts[$service_key]); + $updated_accounts[$account->id()] = $account->as_object(); + } + $service->accounts($updated_accounts)->save($is_profile); + } + } + + /** + * Return array of enabled social broadcasting post types + * + * @static + * @return array + */ + public static function broadcasting_enabled_post_types() { + return apply_filters('social_broadcasting_enabled_post_types', get_post_types(array( + 'public' => true, + 'hierarchical' => false + ))); + } + + /** + * Check if a post type has broadcasting enabled + * + * @static + * @param string $post_type post type to check for + * @return bool + */ + public static function broadcasting_enabled_for_post_type($post_type = null) { + return (bool) in_array($post_type, self::broadcasting_enabled_post_types()); + } + + /** + * Add Meta Boxes + * + * @wp-action do_meta_boxes + * @return void + */ + public function do_meta_boxes() { + global $post; + + if ($post !== null && Social::option('disable_broadcasting') != 1) { + foreach (self::broadcasting_enabled_post_types() as $post_type) { + add_meta_box('social_meta_broadcast', __('Social Broadcasting', 'social'), array( + $this, + 'add_meta_box_broadcast' + ), $post_type, 'side', 'high'); + + $fetch = Social::option('fetch_comments'); + if ($this->_enabled and !empty($fetch)) { + if ($post->post_status == 'publish') { + add_meta_box('social_meta_aggregation_log', __('Social Comments', 'social'), array( + $this, + 'add_meta_box_log' + ), $post_type, 'normal', 'core'); + } + } + } + } + } + + /** + * Adds the broadcasting meta box. + * + * @return void + */ + public function add_meta_box_broadcast() { + global $post; + + $broadcasted = ''; + $broadcasted_ids = get_post_meta($post->ID, '_social_broadcasted_ids', true); + if (!empty($broadcasted_ids)) { + $broadcasted = Social_View::factory('wp-admin/post/meta/broadcast/parts/broadcasted', array( + 'services' => $this->services(), + 'ids' => $broadcasted_ids, + 'post' => $post, + )); + } + + $show_broadcast = false; + foreach ($this->services() as $service) { + if (count($service->accounts())) { + $show_broadcast = true; + break; + } + } + + // Content + $button = ''; + $content = ''; + if ($show_broadcast) { + if ($post->post_status != 'private') { + switch ($post->post_status) { + case 'pending': + $button = 'Edit'; + $accounts = get_post_meta($post->ID, '_social_broadcast_accounts', true); + $content = Social_View::factory('wp-admin/post/meta/broadcast/pending', array( + 'accounts' => $accounts, + 'services' => $this->services(), + )); + break; + case 'future': + $button = 'Edit'; + $accounts = get_post_meta($post->ID, '_social_broadcast_accounts', true); + $content = Social_View::factory('wp-admin/post/meta/broadcast/scheduled', array( + 'services' => $this->services(), + 'accounts' => $accounts, + )); + break; + case 'publish': + $button = 'Broadcast'; + break; + default: + if ($post->post_status == 'draft' and !empty($broadcasted_ids)) { + $content = ''; + } + else { + $notify = false; + if (get_post_meta($post->ID, '_social_notify', true) == '1') { + $notify = true; + } + else if (Social::option('broadcast_by_default') == '1') { + $notify = true; + } + + $content = Social_View::factory('wp-admin/post/meta/broadcast/default', array( + 'post' => $post, + 'notify' => $notify, + )); + } + break; + } + } + else { + $content = Social_View::factory('wp-admin/post/meta/broadcast/private'); + } + + // Button + if (!empty($button)) { + $button = Social_View::factory('wp-admin/post/meta/broadcast/parts/button', array( + 'broadcasted' => $broadcasted, + 'button_text' => $button, + )); + } + } + + echo Social_View::factory('wp-admin/post/meta/broadcast/shell', array( + 'post' => $post, + 'content' => $content, + 'broadcasted' => $broadcasted, + 'button' => $button + )); + } + + /** + * Adds the aggregation log meta box. + * + * @return void + */ + public function add_meta_box_log() { + global $post; + + $next_run = get_post_meta($post->ID, '_social_aggregation_next_run', true); + if (empty($next_run)) { + $next_run = __('Not Scheduled', 'social'); + } + else { + $next_run = Social_Aggregation_Queue::next_run($next_run); + } + + echo Social_View::factory('wp-admin/post/meta/log/shell', array( + 'post' => $post, + 'next_run' => $next_run, + )); + } + + /** + * Show the broadcast options if publishing. + * + * @wp-filter redirect_post_location + * @param string $location default post-publish location + * @param int $post_id post ID + * @return string|void + */ + public function redirect_post_location($location, $post_id) { + if ((isset($_POST['social_notify']) and $_POST['social_notify'] == '1') and + (isset($_POST['visibility']) and $_POST['visibility'] !== 'private') + ) { + update_post_meta($post_id, '_social_notify', '1'); + if (isset($_POST['publish']) or isset($_POST['social_broadcast'])) { + Social_Request::factory('broadcast/options')->post(array( + 'post_ID' => $post_id, + 'location' => $location, + ))->execute(); + } + } + else { + delete_post_meta($post_id, '_social_notify'); + } + return $location; + } + + /** + * Removes post meta if the post is going to private. + * + * @wp-action transition_post_status + * @param string $new + * @param string $old + * @param object $post + * @return void + */ + public function transition_post_status($new, $old, $post) { + if ($new == 'private') { + delete_post_meta($post->ID, '_social_notify'); + delete_post_meta($post->ID, '_social_broadcast_accounts'); + + foreach ($this->services() as $key => $service) { + delete_post_meta($post->ID, '_social_'.$key.'_content'); + } + } + else { + $xmlrpc = false; + if ($new == 'publish') { + if ( ( defined('XMLRPC_REQUEST') or defined('SOCIAL_MAIL_PUBLISH') ) and $old != 'publish') { + $xmlrpc = true; + $this->xmlrpc_publish_post($post); + } + if (self::broadcasting_enabled_for_post_type($post->post_type)) { + Social_Aggregation_Queue::factory()->add($post->ID)->save(); + } + } + + // Sends previously saved broadcast information + if ($xmlrpc or ($old == 'future' and !in_array($new, array('future', 'draft')))) { + Social_Request::factory('broadcast/run')->query(array( + 'post_ID' => $post->ID + ))->execute(); + } + } + } + + /** + * Broadcasts the post on XML RPC requests. + * + * @param object $post + * @return void + */ + public function xmlrpc_publish_post($post) { + if ($post and Social::option('broadcast_by_default') == '1') { + Social::log('Broadcasting triggered by XML-RPC.'); + + $broadcast_accounts = array(); + $broadcast_content = array(); + $broadcast_meta = array(); + + foreach ($this->default_accounts($post) as $service_key => $accounts) { + $service = $this->service($service_key); + if ($service !== false) { + $broadcast_content[$service_key] = array(); + $broadcast_meta[$service_key] = array(); + foreach ($accounts as $key => $id) { + // TODO abstract this to the Facebook plugin + if ($service_key == 'facebook' and $key === 'pages') { + foreach ($id as $account_id => $pages) { + $account = $service->account($account_id); + + // TODO This could use some DRY love + $universal_pages = $account->pages(); + $personal_pages = $account->pages(null, true); + + foreach ($pages as $page_id) { + if (!isset($broadcast_accounts[$service_key])) { + $broadcast_accounts[$service_key] = array(); + } + + if (!isset($broadcast_accounts[$service_key][$page_id])) { + if (isset($universal_pages[$page_id])) { + $broadcast_accounts[$service_key][$page_id] = (object) array( + 'id' => $page_id, + 'name' => $universal_pages[$page_id]->name, + 'universal' => true, + 'page' => true, + ); + } + else if (isset($personal_pages[$page_id])) { + $broadcast_accounts[$service_key][$page_id] = (object) array( + 'id' => $page_id, + 'name' => $personal_pages[$page_id]->name, + 'universal' => false, + 'page' => true, + ); + } + } + $broadcast_content[$service_key][$page_id] = $service->format_content($post, Social::option('broadcast_format')); + $broadcast_meta[$service_key][$page_id] = $service->get_broadcast_extras($page_id, $post); + } + } + } + else { + $account = $service->account($id); + if ($account !== false) { + if (!isset($broadcast_accounts[$service_key])) { + $broadcast_accounts[$service_key] = array(); + } + + $broadcast_accounts[$service_key][$account->id()] = (object) array( + 'id' => $account->id(), + 'universal' => $account->universal() + ); + + $broadcast_content[$service_key][$account->id()] = $service->format_content($post, Social::option('broadcast_format')); + $broadcast_meta[$service_key][$account->id()] = $service->get_broadcast_extras($account->id(), $post); + } + } + } + } + } + + update_post_meta($post->ID, '_social_broadcast_content', addslashes_deep($broadcast_content)); + update_post_meta($post->ID, '_social_broadcast_meta', addslashes_deep($broadcast_meta)); + + if (count($broadcast_accounts)) { + Social::log('There are default accounts, running broadcast'); + update_post_meta($post->ID, '_social_broadcast_accounts', addslashes_deep($broadcast_accounts)); + } + } + } + + /** + * Loads the default accounts for the post. + * + * @param object $post + * @return array + */ + public function default_accounts($post) { + $default_accounts = Social::option('default_accounts'); + $author_default_accounts = get_user_meta($post->post_author, 'social_default_accounts', true); + if (is_array($author_default_accounts)) { + foreach ($author_default_accounts as $service_key => $accounts) { + if (!isset($default_accounts[$service_key])) { + $default_accounts[$service_key] = $accounts; + } + else { + foreach ($accounts as $key => $account) { + if ($key === 'pages') { + if (!isset($default_accounts[$key]['pages'])) { + $default_accounts[$key]['pages'] = $account; + } + else { + foreach ($account as $page_id) { + if (!in_array($page_id, $default_accounts[$key]['pages'])) { + $default_accounts[$key]['pages'][] = $page_id; + } + } + } + } + else { + $default_accounts[$service_key][] = $account; + } + } + } + } + } + + return apply_filters('social_default_accounts', $default_accounts, $post); + } + + /** + * Sets the broadcasted IDs for the post. + * + * @param int $post_id post id + * @param string $service service key + * @param string $broadcasted_id broadcasted id + * @param string $message broadcasted message + * @param Social_Service_Account $account account + * @param Social_Response $response response object + * @return void + */ + public function add_broadcasted_id($post_id, $service, $broadcasted_id, $message, $account, Social_Response $response = null) { + $broadcasted_ids = get_post_meta($post_id, '_social_broadcasted_ids', true); + if (empty($broadcasted_ids)) { + $broadcasted_ids = array(); + } + + if (!isset($broadcasted_ids[$service])) { + $broadcasted_ids[$service] = array(); + } + + if (!isset($broadcasted_ids[$service][$account->id()])) { + $broadcasted_ids[$service][$account->id()] = array(); + } + + if (!isset($broadcasted_ids[$service][$account->id()][$broadcasted_id])) { + $urls = array( + get_permalink($post_id) + ); + + $shortlink = wp_get_shortlink($post_id); + if (!in_array($shortlink, $urls)) { + $urls[] = $shortlink; + } + + $home_url = home_url('?p='.$post_id); + if (!in_array($home_url, $urls)) { + $urls[] = $home_url; + } + + $data = array( + 'message' => $message, + 'urls' => $urls + ); + $data = apply_filters('social_save_broadcasted_ids_data', $data, $account, $service, $post_id, $response); + $broadcasted_ids[$service][$account->id()][$broadcasted_id] = $data; + update_post_meta($post_id, '_social_broadcasted_ids', $broadcasted_ids); + } + } + + /** + * Adds the 15 minute interval. + * + * @wp-filter cron_schedules + * @param array $schedules + * @return array + */ + public function cron_schedules($schedules) { + $schedules['every15min'] = array( + 'interval' => 900, + 'display' => 'Every 15 minutes' + ); + return $schedules; + } + + /** + * Sends a request to initialize CRON 15. + * + * @wp-action social_cron_15_init + * @return void + */ + public function cron_15_init() { + Social::log('Running cron_15_init'); + Social_Request::factory('cron/cron_15')->query('api_key', Social::option('system_cron_api_key'))->execute(); + } + + /** + * Runs the aggregation loop. + * + * @wp-action social_cron_15 + * @return void + */ + public function run_aggregation() { + $semaphore = Social_Semaphore::factory(); + $queue = Social_Aggregation_Queue::factory(); + + foreach ($queue->runnable() as $timestamp => $posts) { + foreach ($posts as $id => $interval) { + $post = get_post($id); + if ($post !== null) { + $queue->add($id, $interval)->save(); + $semaphore->increment(); + $this->request(home_url('index.php?social_controller=aggregation&social_action=run&post_id='.$id), 'run'); + } + else { + $queue->remove($id, $timestamp)->save(); + } + } + } + } + + /** + * Removes the post from the aggregation queue. + * + * @wp-action delete_post + * @param int $post_id + * @return void + */ + public function delete_post($post_id) { + Social_Aggregation_Queue::factory()->remove($post_id); + } + + /** + * Hides the Site Admin link for social-based users. + * + * @wp-filter register + * @param string $link + * @return string + */ + public function register($link) { + if (is_user_logged_in()) { + $commenter = get_user_meta(get_current_user_id(), 'social_commenter', true); + if (!empty($commenter)) { + return ''; + } + } + + return $link; + } + + /** + * Sets the user role. + * + * @wp-action set_user_role + * @param int $user_id + * @param string $role + */ + public function set_user_role($user_id, $role) { + if (!empty($role)) { + delete_user_meta($user_id, 'social_commenter'); + } + } + + /** + * Show the disconnect link for social-based users. + * + * @wp-filter loginout + * @param string $link + * @return string + */ + public function loginout($link) { + if (is_user_logged_in()) { + $commenter = get_user_meta(get_current_user_id(), 'social_commenter', true); + if (!empty($commenter)) { + foreach ($this->services() as $key => $service) { + $account = reset($service->accounts()); + if ($account) { + return $service->disconnect_link($account); + } + } + } + } + else { + $link = explode('>'.__('Log in'), $link); + $link = $link[0].' id="social_login">'.__('Log in').$link[1]; + } + + return $link; + } + + /** + * Increments the service comment counter. + * + * @static + * @param array $items + * @param array $groups + */ + public static function add_social_items_count($items, &$groups) { + foreach ($items as $group => $_items) { + if ($group == 'parent') { + self::add_social_items_count($_items, $groups); + } + else { + if (!isset($groups['social-'.$group])) { + $groups['social-'.$group] = 0; + } + + $groups['social-'.$group] = $groups['social-'.$group] + count($_items); + } + } + } + + /** + * Overrides the default WordPress comments_template function. + * + * @wp-filter comments_template + * @return string + */ + public function comments_template($path) { + global $post; + + if (!( + is_singular() and + (have_comments() or $post->comment_status == 'open') and + Social::option('use_standard_comments') != '1' + )) { + return $path; + } + + if (!defined('SOCIAL_COMMENTS_FILE')) { + define('SOCIAL_COMMENTS_FILE', trailingslashit(dirname(SOCIAL_FILE)).'views/comments.php'); + } + + return SOCIAL_COMMENTS_FILE; + } + + /** + * Returns an array of comment types that display avatars. + * + * @wp-filter get_avatar_comment_types + * @param array $types default WordPress types + * @return array + */ + public function get_avatar_comment_types($types) { + $types[] = 'wordpress'; + return $types; + } + + /** + * Gets the avatar based on the comment type. + * + * @wp-filter get_avatar + * @param string $avatar + * @param object $comment + * @param int $size + * @param string $default + * @param string $alt + * @return string + */ + public function get_avatar($avatar, $comment, $size, $default, $alt) { + $image = null; + if (is_object($comment)) { + $image = get_comment_meta($comment->comment_ID, 'social_profile_image_url', true); + if (empty($image)) { + $image = null; + } + } + else { + // Commenter? + $social_avatar = get_user_meta($comment, 'social_avatar', true); + if (!empty($social_avatar)) { + $image = $social_avatar; + } + } + + if ($image !== null) { + $image = esc_url($image); + $size = esc_attr($size); + $type = ''; + if (is_object($comment)) { + $type = esc_attr($comment->comment_type); + } + + $image = esc_url($image); + $image_format = apply_filters('social_get_avatar_image_format', '%1$s'); + return sprintf($image_format, $alt, $image, $size, $type); + } + + return $avatar; + } + + /** + * Sets the comment type upon being saved. + * + * @wp-action comment_post + * @param int $comment_ID + */ + public function comment_post($comment_ID) { + global $wpdb; + + $comment = get_comment($comment_ID); + $services = $this->services(); + if (!empty($services)) { + $account_id = $_POST['social_post_account']; + foreach ($services as $key => $service) { + $output = $service->format_comment_content($comment, Social::option('comment_broadcast_format')); + foreach ($service->accounts() as $account) { + if ($account_id == $account->id()) { + if (isset($_POST['post_to_service'])) { + $in_reply_to_status_id = get_comment_meta($_POST['comment_parent'], 'social_status_id', true); + if ($comment->comment_approved == '0') { + update_comment_meta($comment_ID, 'social_to_broadcast', $_POST['social_post_account']); + if (!empty($in_reply_to_status_id)) { + update_comment_meta($comment_ID, 'social_in_reply_to_status_id', addslashes_deep($in_reply_to_status_id)); + } + } + else { + $args = array(); + if (!empty($in_reply_to_status_id)) { + $args['in_reply_to_status_id'] = $in_reply_to_status_id; + delete_comment_meta($comment_ID, 'social_in_reply_to_status_id'); + } + Social::log(sprintf(__('Broadcasting comment #%s to %s using account #%s.', 'social'), $comment_ID, $service->title(), $account->id())); + $response = $service->broadcast($account, $output, $args, null, $comment_ID); + if ($response === false or $response->id() === '0') { + wp_delete_comment($comment_ID); + Social::log(sprintf(__('Error: Broadcast comment #%s to %s using account #%s, please go back and try again.', 'social'), $comment_ID, esc_html($service->title()), esc_html($account->id()))); + wp_die(sprintf(__('Error: Your comment could not be sent to %s, please go back and try again.', 'social'), esc_html($service->title()))); + } + + $wpdb->query($wpdb->prepare(" + UPDATE $wpdb->comments + SET comment_type = %s + WHERE comment_ID = %s + ", 'social-'.$service->key(), $comment_ID)); + + $this->set_comment_aggregated_id($comment_ID, $service->key(), $response->id()); + update_comment_meta($comment_ID, 'social_status_id', addslashes_deep($response->id())); + update_comment_meta($comment_ID, 'social_raw_data', addslashes_deep(base64_encode(json_encode($response->body()->response)))); + Social::log(sprintf(__('Broadcasting comment #%s to %s using account #%s COMPLETE.', 'social'), $comment_ID, $service->title(), $account->id())); + } + } + + update_comment_meta($comment_ID, 'social_account_id', addslashes_deep($account_id)); + update_comment_meta($comment_ID, 'social_profile_image_url', addslashes_deep($account->avatar())); + update_comment_meta($comment_ID, 'social_comment_type', addslashes_deep('social-'.$service->key())); + + if ($comment->user_id != '0') { + $comment->comment_author = $account->name(); + $comment->comment_author_url = $account->url(); + wp_update_comment(get_object_vars($comment)); + } + Social::log(sprintf(__('Comment #%s saved.', 'social'), $comment_ID)); + break; + } + } + } + } + } + + /** + * Sets the comment to be approved. + * + * @wp-action wp_set_comment_status + * @param int $comment_id + * @param string $comment_status + * @return void + */ + public function wp_set_comment_status($comment_id, $comment_status) { + if ($comment_status == 'approve') { + global $wpdb; + $results = $wpdb->get_results($wpdb->prepare(" + SELECT user_id, m.meta_value + FROM $wpdb->commentmeta AS m + JOIN $wpdb->comments AS c + ON m.comment_id = c.comment_ID + WHERE m.meta_key = %s + AND m.comment_id = %s + ", 'social_to_broadcast', $comment_id)); + if (!empty($results)) { + $result = reset($results); + $accounts = get_user_meta($result->user_id, 'social_accounts', true); + if (!empty($accounts)) { + foreach ($accounts as $service => $accounts) { + $service = $this->service($service); + if ($service !== false) { + $account = null; + if (!$service->account_exists($result->meta_value)) { + foreach ($accounts as $id => $account) { + if ($id == $result->meta_value) { + $class = 'Social_Service_'.$service->key().'_Account'; + $account = new $class($account); + break; + } + } + } + else { + $account = $service->account($result->meta_value); + } + + if ($account !== null) { + Social::log(sprintf(__('Broadcasting comment #%s to %s using account #%s.', 'social'), $comment_id, $service->title(), $account->id())); + $comment = get_comment($comment_id); + + $in_reply_to_status_id = get_comment_meta($comment_id, 'social_in_reply_to_status_id', true); + $args = array(); + if (!empty($in_reply_to_status_id)) { + $args['in_reply_to_status_id'] = $in_reply_to_status_id; + delete_comment_meta($comment_id, 'social_in_reply_to_status_id'); + } + + $output = $service->format_comment_content($comment, Social::option('comment_broadcast_format')); + $response = $service->broadcast($account, $output, $args, null, $comment_id); + if ($response === false or $response->id() === false) { + wp_delete_comment($comment_id); + Social::log(sprintf(__('Error: Broadcast comment #%s to %s using account #%s, please go back and try again.', 'social'), $comment_id, $service->title(), $account->id())); + } + + $wpdb->query($wpdb->prepare(" + UPDATE $wpdb->comments + SET comment_type = %s + WHERE comment_ID = %s + ", 'social-'.$service->key(), $comment_id)); + + $this->set_comment_aggregated_id($comment_id, $service->key(), $response->id()); + update_comment_meta($comment_id, 'social_status_id', addslashes_deep($response->id())); + update_comment_meta($comment_id, 'social_raw_data', addslashes_deep(base64_encode(json_encode($response->body()->response)))); + Social::log(sprintf(__('Broadcasting comment #%s to %s using account #%s COMPLETE.', 'social'), $comment_id, $service->title(), $account->id())); + } + } + } + } + + delete_comment_meta($comment_id, 'social_to_broadcast'); + } + } + } + + /** + * Sets the comment aggregation ID. + * + * Format of the stored data (serialized): + * + * array( + * 'twitter' => array( + * 1234567890, + * 0987654321, + * // ... Other aggregated IDs + * ), + * 'facebook' => array( + * 1234567890_1234567890, + * 0987654321_0987654321, + * // ... Other aggregated IDs + * ) + * ) + * + * @param int $comment_id + * @param string $service + * @param int $broadcasted_id + * @return void + */ + private function set_comment_aggregated_id($comment_id, $service, $broadcasted_id) { + $comment = get_comment($comment_id); + if (is_object($comment)) { + $aggregated_ids = get_post_meta($comment->comment_post_ID, '_social_aggregated_ids', true); + if (empty($aggregated_ids)) { + $aggregated_ids = array(); + } + + if (!isset($aggregated_ids[$service])) { + $aggregated_ids[$service] = array(); + } + + if (!in_array($broadcasted_id, $aggregated_ids[$service])) { + $aggregated_ids[$service][] = $broadcasted_id; + } + + update_post_meta($comment->comment_post_ID, '_social_aggregated_ids', $aggregated_ids); + } + } + + /** + * Counts the different types of comments. + * + * @wp-filter social_comments_array + * @static + * @param array $comments + * @param int $post_id + * @return array + */ + public function comments_array(array $comments, $post_id) { + $groups = array(); + if (isset($comments['social_groups'])) { + $groups = $comments['social_groups']; + } + + // count the comment types for output in tab headers + foreach ($comments as $comment) { + if (is_object($comment)) { + if (empty($comment->comment_type)) { + $comment->comment_type = 'wordpress'; + } + + if (!isset($groups[$comment->comment_type])) { + $groups[$comment->comment_type] = 1; + } + else { + ++$groups[$comment->comment_type]; + } + if (isset($comment->social_items) and is_array($comment->social_items)) { + $groups[$comment->comment_type] += count($comment->social_items); + } + } + } + + $comments['social_groups'] = apply_filters('social_comments_array_groups', $groups, $comments); + + return $comments; + } + + /** + * Displays a comment. + * + * @param object $comment comment object + * @param array $args + * @param int $depth + */ + public function comment($comment, array $args = array(), $depth = 0) { + $GLOBALS['comment'] = $comment; + + $social_items = ''; + $status_url = null; + $comment_type = $comment->comment_type; + $ignored_types = apply_filters('social_ignored_comment_types', array( + 'wordpress', + 'pingback' + )); + // set the comment type to WordPress if we can't load the Social service (perhaps it was deactivated) + // and the type isn't an ignored type + if (!($service = $this->service_for_comment_type($comment->comment_type)) && !in_array($comment->comment_type, $ignored_types)) { + $comment_type = 'wordpress'; + } + // set Social Items for Social comments + if (!in_array($comment->comment_type, $ignored_types)) { + $status_id = get_comment_meta($comment->comment_ID, 'social_status_id', true); + if (!empty($status_id)) { + $status_url = $service->status_url(get_comment_author(), $status_id); + } + // Social items? + if (!empty($comment->social_items)) { + if (is_object($service) && method_exists($service, 'key')) { + $avatar_size = apply_filters('social_items_comment_avatar_size', array( + 'width' => 18, + 'height' => 18, + )); + $social_items = Social_View::factory('comment/social_item', array( + 'items' => $comment->social_items, + 'service' => $service, + 'avatar_size' => $avatar_size + )); + } + else { + Social::log('service not set for: '.print_r($comment, true)); + ob_start(); + var_dump($service); + Social::log('$service: '.ob_get_clean()); + } + } + } + + echo Social_View::factory('comment/comment', array( + 'comment_type' => $comment_type, + 'comment' => $comment, + 'service' => $service, + 'status_url' => $status_url, + 'depth' => $depth, + 'args' => $args, + 'social_items' => $social_items, + )); + } + + /** + * Adds the Aggregate Comments link to the post row actions. + * + * @param array $actions + * @param WP_Post $post + * @return array + */ + public function post_row_actions(array $actions, $post) { + if ($post->post_status == 'publish' && in_array(Social::option('fetch_comments'), array('1', '2'))) { + $actions['social_aggregation'] = sprintf(__('Social Comments', 'social'), esc_url(wp_nonce_url(admin_url('options-general.php?social_controller=aggregation&social_action=run&post_id='.$post->ID), 'run')), $post->ID). + ''; + } + return $actions; + } + + /** + * Adds the aggregation functionality to the admin bar. + * + * @return void + */ + public function admin_bar_menu() { + global $wp_admin_bar; + + $current_object = get_queried_object(); + + if (empty($current_object)) { + return; + } + + if (!empty($current_object->post_type) + and ($post_type_object = get_post_type_object($current_object->post_type)) + and current_user_can($post_type_object->cap->edit_post, $current_object->ID) + and ($post_type_object->show_ui or 'attachment' == $current_object->post_type) + and (in_array(Social::option('fetch_comments'), array('1', '2'))) + ) { + $wp_admin_bar->add_menu(array( + 'parent' => 'comments', + 'id' => 'social-find-comments', + 'title' => __('Find Social Comments', 'social') + .'', + 'href' => esc_url(wp_nonce_url(admin_url('options-general.php?social_controller=aggregation&social_action=run&post_id='.$current_object->ID), 'run')), + )); + $wp_admin_bar->add_menu(array( + 'parent' => 'comments', + 'id' => 'social-add-tweet-by-url', + 'title' => __('Add Tweet by URL', 'social') + .'', + 'href' => esc_url(get_edit_post_link($current_object->ID)), + )); + } + } + + function admin_bar_footer_css() { +?> + + + +services() as $service) { + if (count($service->accounts())) { + return true; + } + } + + return false; + } + + /** + * Removes an account from the default broadcast accounts. + * + * @param string $service + * @param int $id + * @return void + */ + public function remove_from_default_accounts($service, $id) { + Social::log('Removing from default accounts #:id', array('id' => $id)); + if (defined('IS_PROFILE_PAGE')) { + $defaults = get_user_meta(get_current_user_id(), 'social_default_accounts', true); + } + else { + $defaults = Social::option('default_accounts'); + } + + if (!empty($defaults) and isset($defaults[$service])) { + Social::log('Old default accounts: :accounts', array('accounts' => print_r($defaults, true))); + + $_ids = array(); + foreach ($defaults[$service] as $key => $_id) { + if ($_id != $id) { + $_ids[$key] = $_id; + } + } + + // TODO abstract this to the Facebook plugin + if ($service == 'facebook' and isset($_ids['pages'])) { + $pages = $_ids['pages']; + unset($_ids['pages']); + sort($_ids); + foreach ($pages as $account_id => $account_pages) { + if ($account_id != $id) { + $_ids['pages'][$account_id] = $account_pages; + } + } + } + + $defaults[$service] = $_ids; + if (!count($defaults[$service])) { + unset($defaults[$service]); + } + Social::log('New default accounts: :accounts', array('accounts' => print_r($defaults, true))); + if (defined('IS_PROFILE_PAGE')) { + update_user_meta(get_current_user_id(), 'social_default_accounts', $defaults); + } + else { + Social::option('default_accounts', $defaults); + } + } + } + + /** + * Recursively applies wp_kses() to an array/stdClass. + * + * @param mixed $object + * @return mixed + */ + public function kses($object) { + if (is_object($object)) { + $_object = new stdClass; + } + else { + $_object = array(); + } + + foreach ($object as $key => $val) { + if (is_object($val) or is_array($val)) { + if (is_object($_object)) { + $_object->$key = $this->kses($val); + } + else if (is_array($_object)) { + $_object[$key] = $this->kses($val); + } + } + else { + if (is_object($_object)) { + $_object->$key = wp_kses($val, array()); + } + else { + $_object[$key] = wp_kses($val, array()); + } + } + } + + return $_object; + } + + /** + * Handles the remote timeout requests for Social. + * + * @param string $url url to request + * @param string $nonce_key key to use when generating the nonce + * @param bool $post set to true to do a wp_remote_post + * @return void + */ + private function request($url, $nonce_key = null, $post = false) { + if ($nonce_key !== null) { + $url = str_replace('&', '&', wp_nonce_url($url, $nonce_key)); + } + + $data = array( + 'timeout' => 0.01, + 'blocking' => false, + 'sslverify' => apply_filters('https_local_ssl_verify', true), + ); + + if ($post) { + Social::log('POST request to: :url', array( + 'url' => $url + )); + wp_remote_post($url, $data); + } + else { + Social::log('GET request to: :url', array( + 'url' => $url + )); + wp_remote_get($url, $data); + } + } + + /** + * Loads the services. + * + * @return array + */ + private function load_services() { + if ((isset($_GET['page']) and $_GET['page'] == basename(SOCIAL_FILE)) or defined('IS_PROFILE_PAGE')) { + $services = false; + } + else { + $services = wp_cache_get('services', 'social'); + } + + if ($services === false) { + $services = array(); + // Register services + $registered_services = apply_filters('social_register_service', array()); + if (is_array($registered_services) and count($registered_services)) { + $accounts = Social::option('accounts'); + foreach ($registered_services as $service) { + if (!isset($services[$service])) { + $service_accounts = array(); + + if (isset($accounts[$service]) and count($accounts[$service])) { + // Flag social as enabled, we have at least one account. + if ($this->_enabled === null) { + $this->_enabled = true; + } + + foreach ($accounts[$service] as $account_id => $account) { + // TODO Shouldn't have to do this. Fix later. + $account->personal = '0'; + $service_accounts[$account_id] = $account; + } + } + + $class = 'Social_Service_'.$service; + $services[$service] = new $class($service_accounts); + } + } + wp_cache_set('services', $services, 'social'); + } + } + else if ($this->_enabled === null and is_array($services)) { + foreach ($services as $service) { + if (count($service->accounts())) { + $this->_enabled = true; + break; + } + } + } + +// don't return global services for commenters + $commenter = get_user_meta(get_current_user_id(), 'social_commenter', true); + if ($commenter == 'true' && !current_user_can('publish_posts')) { + foreach ($services as $key => $accounts) { + $services[$key]->clear_accounts(); + } + } + + $personal_accounts = get_user_meta(get_current_user_id(), 'social_accounts', true); + if (is_array($personal_accounts)) { + foreach ($personal_accounts as $key => $_accounts) { + if (count($_accounts) and isset($services[$key])) { + $class = 'Social_Service_'.$key.'_Account'; + foreach ($_accounts as $account_id => $account) { + // TODO Shouldn't have to do this. Fix later. + $account->universal = '0'; + if ($services[$key]->account_exists($account_id) and !defined('IS_PROFILE_PAGE')) { + $account = $this->merge_accounts($services[$key]->account($account_id)->as_object(), $account, $key); + } + $account = new $class((object) $account); + $services[$key]->account($account); + // Flag social as enabled, we have at least one account. + if ($this->_enabled === null) { + $this->_enabled = true; + } + } + } + } + } + + return $services; + } + + /** + * Merges universal with personal account. + * + * @param array $arr1 + * @param array $arr2 + * @param string $service_key + * @return object + */ + private function merge_accounts($arr1, $arr2, $service_key) { + $arr1->personal = true; + return apply_filters('social_merge_accounts', $arr1, $arr2, $service_key); + } + + /** + * Checks to see if the array is an associative array. + * + * @param array $arr + * @return bool + */ + private function is_assoc($arr) { + $keys = array_keys($arr); + return array_keys($keys) !== $keys; + } + + /** + * Builds the settings URL for the plugin. + * + * @param array $params + * @param bool $personal + * @return string + */ + public static function settings_url(array $params = null, $personal = false) { + if ($params !== null) { + foreach ($params as $key => $value) { + $params[$key] = urlencode($value); + } + } + + if (!current_user_can('manage_options') or $personal) { + $file = 'profile.php'; + } + else { + $file = 'options-general.php'; + $params['page'] = basename(SOCIAL_FILE); + } + + $url = add_query_arg($params, admin_url($file)); + + if (!current_user_can('manage_options') or $personal) { + $url .= '#social-networks'; + } + + return $url; + } + + /** + * Filter the where clause for pulling comments for feeds (to exclude meta comments). + * + * @param string $where + * @return string + */ + public static function comments_feed_exclusions($where) { + global $wpdb; + $meta_types = array(); +// get services + $services = Social::instance()->services(); +// ask each service for it's "meta" comment types + foreach ($services as $service) { + $meta_types = array_merge($meta_types, $service->comment_types_meta()); + } + $meta_types = array_unique($meta_types); + if (count($meta_types)) { + $where .= " AND comment_type NOT IN ('".implode("', '", array_map('social_wpdb_escape', $meta_types))."') "; + } + return $where; + } + + /** + * Filter the image tag to implement lazy loading support for meta comments. + * + * @param string $image_format + * @return string + */ + public static function social_item_output_image_format($image_format) { + if (class_exists('LazyLoad_Images')) { + // would be great if the plugin provided an API for this, until then we'll copy the code + $placeholder_image = apply_filters( 'lazyload_images_placeholder_image', LazyLoad_Images::get_url( 'images/1x1.trans.gif' ) ); + $image_format = '%4$s'; + } + return $image_format; + } + + /** + * Filter the image tag to implement lazy loading support for avatars. + * + * @param string $image_format + * @return string + */ + public static function social_get_avatar_image_format($image_format) { + if (class_exists('LazyLoad_Images')) { + // would be great if the plugin provided an API for this, until then we'll copy the code + $placeholder_image = apply_filters( 'lazyload_images_placeholder_image', LazyLoad_Images::get_url( 'images/1x1.trans.gif' ) ); + $image_format = '%1$s'; + } + return $image_format; + } + +} // End Social + +if (!function_exists('addslashes_deep')) { +/** + * Navigates through an array and adds slashes to the values. + * + * If an array is passed, the array_map() function causes a callback to pass the + * value back to the function. Slashes will be added to this value. + * + * @since 3.4.0? + * + * @param array|string $value The array or string to be slashed. + * @return array|string Slashed array (or string in the callback). + */ +function addslashes_deep($value) { + if ( is_array($value) ) { + $value = array_map('addslashes_deep', $value); + } elseif ( is_object($value) ) { + $vars = get_object_vars( $value ); + foreach ($vars as $key=>$data) { + $value->{$key} = addslashes_deep( $data ); + } + } else { + $value = addslashes($value); + } + + return $value; +} +} + +function social_wpdb_escape($str) { + global $wpdb; + return $wpdb->escape($str); +} + +function social_wp_mail_indicator() { + define('SOCIAL_MAIL_PUBLISH', true); +} + +$social_file = __FILE__; +if (isset($plugin)) { + $social_file = $plugin; +} +else if (isset($mu_plugin)) { + $social_file = $mu_plugin; +} +else if (isset($network_plugin)) { + $social_file = $network_plugin; +} + +define('SOCIAL_FILE', $social_file); +define('SOCIAL_PATH', WP_PLUGIN_DIR.'/'.basename(dirname($social_file)).'/'); + +// Register Social's autoloading +spl_autoload_register(array('Social', 'auto_load')); + +$social = Social::instance(); + +// General Actions +add_action('init', array($social, 'init'), 1); +add_action('init', array($social, 'request_handler'), 2); +add_action('admin_init', array($social, 'admin_init'), 1); +add_action('load-settings_page_social', array($social, 'check_system_cron')); +add_action('load-social.php', array($social, 'check_system_cron')); +add_action('comment_post', array($social, 'comment_post')); +add_action('wp_set_comment_status', array($social, 'wp_set_comment_status'), 10, 3); +add_action('admin_notices', array($social, 'admin_notices')); +add_action('transition_post_status', array($social, 'transition_post_status'), 10, 3); +add_action('show_user_profile', array($social, 'show_user_profile')); +add_action('do_meta_boxes', array($social, 'do_meta_boxes')); +add_action('delete_post', array($social, 'delete_post')); +add_action('wp_enqueue_scripts', array($social, 'enqueue_assets')); +add_action('load-post-new.php', array($social, 'enqueue_assets')); +add_action('load-post.php', array($social, 'enqueue_assets')); +add_action('load-profile.php', array($social, 'enqueue_assets')); +add_action('load-settings_page_social', array($social, 'enqueue_assets')); +add_action('admin_enqueue_scripts', array($social, 'admin_enqueue_assets')); +add_action('admin_bar_menu', array($social, 'admin_bar_menu'), 95); +add_action('wp_after_admin_bar_render', array($social, 'admin_bar_footer_css')); +add_action('wp_after_admin_bar_render', array($social, 'admin_bar_footer_js')); +add_action('set_user_role', array($social, 'set_user_role'), 10, 2); +add_action('wp-mail.php', 'social_wp_mail_indicator'); +add_action('social_settings_save', array('Social_Service_Facebook', 'social_settings_save')); + +// CRON Actions +add_action('social_cron_15_init', array($social, 'cron_15_init')); +add_action('social_cron_15', array($social, 'run_aggregation')); + +// Admin Actions +add_action('admin_menu', array($social, 'admin_menu')); +add_action('personal_options_update', array($social, 'personal_options_update')); + +// Filters +add_filter('cron_schedules', array($social,'cron_schedules')); +add_filter('plugin_action_links', array($social, 'add_settings_link'), 10, 2); +add_filter('redirect_post_location', array($social, 'redirect_post_location'), 10, 2); +add_filter('comments_template', array($social, 'comments_template')); +add_filter('get_avatar_comment_types', array($social, 'get_avatar_comment_types')); +add_filter('get_avatar', array($social, 'get_avatar'), 10, 5); +add_filter('register', array($social, 'register')); +add_filter('loginout', array($social, 'loginout')); +add_filter('post_row_actions', array($social, 'post_row_actions'), 10, 2); +add_filter('social_comments_array', array($social, 'comments_array'), 100, 2); +add_filter('comment_feed_where', array($social, 'comments_feed_exclusions')); +add_filter('social_settings_default_accounts', array('Social_Service_Facebook', 'social_settings_default_accounts'), 10, 2); +add_filter('social_item_output_image_format', array($social, 'social_item_output_image_format')); +add_filter('social_get_avatar_image_format', array($social, 'social_get_avatar_image_format')); + +// Service filters +add_filter('social_auto_load_class', array($social, 'auto_load_class')); + +} // End class_exists check