/** * Similar to `media_sideload_image` except that it simply returns the attachment's ID on success * * @param (string) $file the url of the image to download and attach to the post * @param (integer) $post_id the post ID to attach the image to * @param (string) $desc an optional description for the image * * @since 0.1 */ function pmp_media_sideload_image($file, $post_id, $desc = null) { if (!empty($file)) { pmp_debug(" ** sideloading-image {$file} for post[{$post_id}]"); include_once ABSPATH . 'wp-admin/includes/image.php'; include_once ABSPATH . 'wp-admin/includes/file.php'; include_once ABSPATH . 'wp-admin/includes/media.php'; // Set variables for storage, fix file filename for query strings. preg_match('/[^\\?]+\\.(jpe?g|jpe|gif|png)\\b/i', $file, $matches); $file_array = array(); if (empty($matches)) { $file_array['name'] = basename($file); } else { $file_array['name'] = basename($matches[0]); } // Download file to temp location. $file_array['tmp_name'] = download_url($file); // If error storing temporarily, return the error. if (is_wp_error($file_array['tmp_name'])) { return $file_array['tmp_name']; } // Do the validation and storage stuff. $id = media_handle_sideload($file_array, $post_id, $desc); // If error storing permanently, unlink. if (is_wp_error($id)) { @unlink($file_array['tmp_name']); } return $id; } }
/** * For each saved search query, query the PMP and perform the appropriate action (e.g., auto draft, auto publish or do nothing) * * @since 0.3 */ function pmp_import_for_saved_queries() { $search_queries = pmp_get_saved_search_queries(); $sdk = new SDKWrapper(); foreach ($search_queries as $id => $query_data) { if ($query_data->options->query_auto_create == 'off') { continue; } $default_opts = array('profile' => 'story', 'limit' => 25); $cron_name = 'pmp_last_saved_search_cron_' . sanitize_title($query_data->options->title); $last_saved_search_cron = get_option($cron_name, false); if (!empty($last_saved_search_cron)) { $default_opts['startcreated'] = $last_saved_search_cron; } else { // First time pulling, honor the initial pull limit if (!empty($query_data->options->initial_pull_limit)) { $default_opts['limit'] = $query_data->options->initial_pull_limit; } } $query_args = array_merge($default_opts, (array) $query_data->query); pmp_debug("========== saved-searching: {$query_data->options->title} =========="); pmp_debug($query_args); $result = $sdk->queryDocs($query_args); if (empty($result)) { pmp_debug(' -- NO RESULTS!'); continue; } else { pmp_debug(" -- got {$result->items()->count()} of {$result->items()->totalItems()} total"); } // process results, recording the biggest "created" date $last_created = null; foreach ($result->items() as $item) { $syncer = PmpPost::fromDoc($item); if ($syncer->post) { $syncer->pull(); } else { if ($query_data->options->query_auto_create == 'draft') { $syncer->pull(false, 'draft'); } else { $syncer->pull(false, 'publish'); } } // make sure we got a post out of the deal $post_id = $syncer->post->ID; if (!$post_id) { continue; } if (is_null($last_created) || $item->attributes->created > $last_created) { $last_created = $item->attributes->created; } // set the category(s) if (isset($query_data->options->post_category)) { // Make sure "Uncategorized" category doesn't stick around if it // wasn't explicitly set as a category for the saved search import. $assigned_categories = wp_get_post_categories($post_id); $uncategorized = get_category(1); // Check for "Uncategorized" in the already-assigned categories $in_assigned_cats = array_search($uncategorized->term_id, $assigned_categories); // Check for "Uncategorized" in the saved-search categories $in_saved_search_cats = array_search($uncategorized->term_id, $query_data->options->post_category); // If "Uncategorized" is in assigned categories and NOT in saved-search categories, ditch it. if ($in_assigned_cats >= 0 && $in_saved_search_cats === false) { unset($assigned_categories[array_search($uncategorized->term_id, $assigned_categories)]); } // Set the newly generated list of categories for the post wp_set_post_categories($post_id, array_values(array_unique(array_merge($assigned_categories, $query_data->options->post_category)))); } } // only set the last-searched-cron if we got a date if ($last_created) { update_option($cron_name, $last_created); } } }
/** * When the PMP notification hub sends an update, handle it * * @since 0.3 */ function pmp_do_notification_callback() { global $wpdb; pmp_debug('========== pmp_do_notification_callback =========='); $body = file_get_contents('php://input'); $hash = hash_hmac('sha1', $body, PMP_NOTIFICATIONS_SECRET); // get a COMPLETE mapping of known-PMP-guids to top-level WP-posts $pmp_post_data = $wpdb->get_results("select post_id, meta_value, post_parent " . "from {$wpdb->posts} join {$wpdb->postmeta} on (ID = post_id) " . "where meta_key = 'pmp_guid'", ARRAY_A); // map to the TOP LEVEL post (attachments map to their parent) $pmp_guids = array(); foreach ($pmp_post_data as $row) { if ($row['post_parent'] > 0) { $pmp_guids[$row['meta_value']] = $row['post_parent']; } else { $pmp_guids[$row['meta_value']] = $row['post_id']; } } // check hub signature if ($_SERVER['HTTP_X_HUB_SIGNATURE'] !== "sha1={$hash}") { var_log('INVALID PMP notifications HTTP_X_HUB_SIGNATURE'); var_log(" Expected: sha1={$hash}"); var_log(" Got: " . $_SERVER['HTTP_X_HUB_SIGNATURE']); return; } // parse xml pubsubhubbub body $xml = simplexml_load_string($body); foreach ($xml->channel->item as $item) { $item_json = json_decode(json_encode($item)); $item_guid = $item_json->guid; // look for Posts tied to that guid if (isset($pmp_guids[$item_guid])) { $post = get_post($pmp_guids[$item_guid]); if ($post) { $syncer = PmpPost::fromPost($post); $syncer->pull(); } } } }
/** * Debug helper to attach post/doc information */ protected function pmp_debug($msg) { if ($this->post) { $msg = "{$msg} wp[{$this->post->ID}]"; } if ($this->doc) { $msg = "{$msg} pmp[{$this->doc->attributes->guid}]"; } pmp_debug($msg); }
/** * Get the first valid audio-enclosure-url from an audio doc * * @since 0.2 */ public static function getPlayableUrl($audio_doc) { $guid = $audio_doc->attributes->guid; $enclosure = $audio_doc->links('enclosure')->first(); if (!$enclosure) { pmp_debug(" ** NO ENCLOSURES for audio[{$guid}]"); return null; } // supplementary data $href = $enclosure->href; $type = isset($enclosure->type) ? $enclosure->type : null; $uri_parts = parse_url($href); $extension = pathinfo($uri_parts['path'], PATHINFO_EXTENSION); if (!in_array($uri_parts['scheme'], array('http', 'https'))) { pmp_debug(" ** INVALID ENCLOSURE HREF ({$href}) for audio[{$guid}]"); return null; } // dereference playlists (m3u) if ($type == 'audio/m3u' || $extension == 'm3u') { pmp_debug(" ** dereferencing playlist for audio[{$guid}]"); $response = wp_remote_get($href); $lines = explode("\n", $response['body']); $href = $lines[0]; $uri_parts = parse_url($href); $extension = pathinfo($uri_parts['path'], PATHINFO_EXTENSION); $type = null; // we don't know this anymore } // check for "known" types that start with audio/* if ($type && in_array($type, array_values(get_allowed_mime_types()))) { if (preg_match('/^audio/', $type)) { pmp_debug(" ** known mime type '{$type}' for audio[{$guid}]"); return $href; } } if (in_array($extension, wp_get_audio_extensions())) { pmp_debug(" ** known extension '{$extension}' for audio[{$guid}]"); return $href; } // not sure what this is pmp_debug(" ** UNABLE TO PLAY enclosure ({$href}) for audio[{$guid}]"); return null; }