Created
February 21, 2012 22:14
-
-
Save mikeschinkel/1879381 to your computer and use it in GitHub Desktop.
WordPress plugin to download list of WordPress' plugins into the WordPress database (written pre-Custom Post Types)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Plugin Name: Sync Plugin Info | |
Plugin URI: http://mikeschinkel.com/wordpress-plugins/sync-plugin-info | |
Description: Synchronizes Plugin Info from <a href="http://api.wordpress.org" target="_blank">api.wordpress.org</a> to tables in the local MySQL database | |
Version: 0.1 | |
Author: Mike Schinkel | |
Author URI: http://mikeschinkel.com | |
*/ | |
//global $sync_plugin_info; | |
//$sync_plugin_info = | |
$sync_plugin_info = new SyncPluginInfo(true); | |
//while ($sync_plugin_info->sync()!=0); | |
class SyncPluginInfo { | |
const PLUGINS_TABLE_NAME = 'extend_plugins'; | |
const DB_VERSION = '0.1'; | |
const PLUGIN_KEY = 'sync-plugin-info'; | |
const NEXT_PLUGIN_KEY = 'sync-plugin-info_next-plugin'; | |
const DB_VERSION_KEY = 'sync-plugin-info_db-version'; | |
const SCHEDULED_TASK = 'sync-plugin-info_hourly-sync'; | |
const LAST_BATCH_FILE = 'sync-plugin-info_last-batch.txt'; | |
const LAST_BATCH_SQL = 'sync-plugin-info_last-batch.sql'; | |
const PLUGIN_API_URL = 'http://api.wordpress.org/plugins/info/1.0/'; | |
const BATCH_SIZE = 50; | |
const DEBUG = true; | |
private $debug; | |
static $singleton; | |
function SyncPluginInfo($debug=false) { | |
$singleton = $this; // Holds onto a reference so cron will work. | |
global $wpdb; | |
$wpdb->extend_plugins = $wpdb->prefix . self::PLUGINS_TABLE_NAME; | |
register_activation_hook(__FILE__, array(&$this,'install')); | |
register_deactivation_hook(__FILE__, array(&$this,'uninstall')); | |
if (wp_next_scheduled(self::SCHEDULED_TASK)===false) { | |
add_filter('cron_schedules', array(&$this, 'cron_schedules')); | |
wp_schedule_event(time(), 'hourly', self::SCHEDULED_TASK); | |
} | |
add_action(self::SCHEDULED_TASK, array(&$this,'sync')); | |
$this->debug = $debug; | |
} | |
function debug($msg) { | |
if($this->debug) { | |
if($f = @fopen(self::PLUGIN_KEY . '.log', 'a')) { | |
fwrite($f, date(DATE_RFC822) . ": $msg\r\n"); | |
fclose($f); | |
} | |
} | |
} | |
function install() { | |
global $wpdb; | |
if($wpdb->get_var("SHOW TABLES LIKE '$wpdb->extend_plugins'") != $wpdb->extend_plugins || | |
get_option(self::DB_VERSION_KEY) != self::DB_VERSION) | |
{ | |
$sql = $this->get_create_table_sql(); | |
require_once(ABSPATH.'/wp-admin/includes/upgrade.php'); | |
dbDelta($sql); | |
add_option(self::DB_VERSION_KEY, self::DB_VERSION); | |
} | |
} | |
function uninstall() { | |
//DebugBreak(); | |
global $wpdb; | |
$sql = $wpdb->prepare("DROP TABLE $wpdb->extend_plugins;"); | |
$wpdb->query($sql); | |
wp_clear_scheduled_hook(self::SCHEDULED_TASK); | |
delete_option(self::DB_VERSION_KEY); | |
delete_option(self::NEXT_PLUGIN_KEY); | |
} | |
function cron_schedules() { | |
return array( 'everyminute' => array('interval' => 10, 'display' => 'Every Minute')); | |
} | |
function sync($sync_all=false) { | |
$plugin_count = -1; | |
//DebugBreak(); | |
$plugins_to_query = self::BATCH_SIZE; | |
$first_plugin = intval(get_option(self::NEXT_PLUGIN_KEY)); | |
$offset= intval($first_plugin/self::BATCH_SIZE); | |
$plugin_count = $this->get_plugin_count(); | |
while($offset*self::BATCH_SIZE+1 <= $plugin_count) { | |
$next_plugin = ($offset+1)*self::BATCH_SIZE; | |
if ( $next_plugin > $plugin_count) { | |
$plugins_to_query = $plugin_count - $offset*self::BATCH_SIZE; | |
$next_plugin = 0; | |
} | |
$first = $offset*self::BATCH_SIZE; | |
$last = $first + $plugins_to_query - 1; | |
$this->debug("Syncing info for plugins $first to $last..."); | |
$plugins = $this->get_plugin_list($plugins_to_query,$offset); | |
if (is_array($plugins)) | |
$plugin_count = count($plugins); | |
$this->save_plugins($plugins); | |
$this->write_to_mysql($plugins); | |
unset($plugins); // Clear the memory; | |
if (!$sync_all) { | |
update_option(self::NEXT_PLUGIN_KEY,$next_plugin); | |
break; | |
} | |
$offset++; | |
} | |
if ($sync_all) update_option(self::NEXT_PLUGIN_KEY,0); | |
$this->debug('Done!'); | |
return $plugin_count; | |
} | |
function save_plugins($plugins) { | |
ob_start(); | |
print_r($plugins); | |
$plugin_text = ob_get_clean(); | |
file_put_contents(self::LAST_BATCH_FILE,$plugin_text); | |
} | |
function save_sql($sql) { | |
file_put_contents(self::LAST_BATCH_SQL,$sql); | |
} | |
function write_to_mysql($plugins) { | |
global $wpdb; | |
$sql = array(); | |
$sql[] = "REPLACE INTO $wpdb->extend_plugins (slug,name,version,author,author_url,author_link,requires,tested,rating,num_ratings,downloads,last_updated,homepage,description,downloadlink,tags) VALUES "; | |
$max_tag_len = 0; | |
$i = 0; | |
if (is_array($plugins)) | |
foreach($plugins as $plugin) { | |
$plugin->downloads = intval($plugin->downloads); | |
$plugin->tags = implode(', ',array_flip($plugin->tags)); | |
$max_tag_len = max(strlen($plugin->tags),$max_tag_len); | |
$plugin->description = $this->strip_hi_bits($plugin->description); | |
$author_info = $this->get_author_info($plugin->author); | |
$plugin->author = $author_info['name']; | |
$plugin->author_url = $author_info['url']; | |
$plugin->author_link = $author_info['link']; | |
$plugin->name = $this->strip_hi_bits($plugin->name); | |
$plugin->downloadlink = (isset($plugin->downloadlink) ? $plugin->downloadlink : ''); | |
$plugin->downloads = (isset($plugin->downloads) ? intval($plugin->downloads) : -1); | |
$sql[] = $wpdb->prepare("\r\n\t(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s),", | |
$plugin->slug, $plugin->name, $plugin->version, $plugin->author, $plugin->author_url, $plugin->author_link, | |
$plugin->requires, $plugin->tested, $plugin->rating, $plugin->num_ratings, $plugin->downloads, | |
$plugin->last_updated, $plugin->homepage, $plugin->description, | |
$plugin->download_link, $plugin->tags); // Note strange bug in API makes downloadlink on request and download_link in object | |
$i++; | |
} | |
unset($plugins); // Clear the memory; | |
$sql = substr(implode(" ",$sql),0,-1) . ';'; | |
$wpdb->query($sql); | |
$this->save_sql($sql); | |
unset($sql); // Clear the memory; | |
} | |
function get_author_info($author) { | |
$author = $this->strip_hi_bits($author); | |
$author_info = array('name'=>'','url'=>'','link'=>$author); | |
if (preg_match('#<a href="([^"]+)">([^<]+)</a>#',$author,$matches)) { | |
$author_info['url'] = $matches[1]; | |
$author_info['name'] = $matches[2]; | |
} | |
return $author_info; | |
} | |
function strip_hi_bits($string) { | |
$string = utf8_decode($string); | |
if (preg_match("/[\x80-\xff]/", $string)) { | |
for ($i=0; $i < strlen($string); $i++) { | |
if (ord($string{$i})>126) { | |
$string = substr_replace($string, '?', $i, 1); | |
} | |
} | |
} | |
return $string; | |
} | |
function get_plugin_count() { | |
$args->search=''; | |
$args->page=1; | |
$args->per_page=1; | |
$results = $this->do_action('query_plugins',$args); | |
return intval($results->info['results']); | |
} | |
function get_plugin_list($plugins_to_query,$offset) { | |
$args->search=''; | |
$args->page= $offset+1; | |
$args->per_page= $plugins_to_query; | |
$args->fields = array( | |
'slug'=>true, | |
'name'=>true, | |
'version'=>true, | |
'author'=>true, | |
'requires'=>true, | |
'tested'=>true, | |
'rating'=>true, | |
'num_ratings'=>true, | |
'downloads'=>true, | |
'last_updated'=>true, | |
'homepage'=>true, | |
'description'=>true, | |
'sections'=>false, | |
'downloadlink'=>true, | |
'tags'=> true, | |
); | |
$results = $this->do_action('query_plugins',$args); | |
return $results->plugins; | |
} | |
function do_action($action,$args) { | |
$response = wp_remote_post(self::PLUGIN_API_URL, array( | |
'body' => array( | |
'action' => $action, | |
'request' => serialize($args) | |
) | |
) | |
); | |
$results = $this->get_results($response); | |
return $results; | |
} | |
function get_results($response) { | |
if ( is_wp_error($response) ) { | |
$results = new WP_Error('plugins_api_failed', __('An Unexpected HTTP Error occured during the API request.</p> <p><a href="?" onclick="document.location.reload(); return false;">Try again</a>'), $response->get_error_message() ); | |
} else { | |
$results = unserialize($response['body']); | |
if (!$results) { | |
$results = new WP_Error('plugins_api_failed', __('An unknown error occured'), $request['body']); | |
} | |
} | |
return $results; | |
} | |
function get_create_table_sql() { | |
global $wpdb; | |
$table_name = $wpdb->prefix . self::PLUGINS_TABLE_NAME; | |
$sql =<<<CREATE_TABLE | |
CREATE TABLE {$table_name} ( | |
slug varchar(128) NOT NULL UNIQUE PRIMARY KEY, | |
name varchar(128) NOT NULL UNIQUE, | |
version varchar(256), | |
author varchar(128), | |
author_url varchar(192), | |
author_link varchar(256), | |
requires varchar(256), | |
tested varchar(256), | |
rating float unsigned, | |
num_ratings int(10) unsigned, | |
downloads int(10) unsigned, | |
last_updated date, | |
homepage varchar(255), | |
description text, | |
downloadlink varchar(255), | |
tags varchar(1024) | |
); | |
CREATE_TABLE; | |
return $sql; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment