Index: wp-admin/includes/settings.php
===================================================================
--- wp-admin/includes/settings.php	(revision 0)
+++ wp-admin/includes/settings.php	(revision 0)
@@ -0,0 +1,328 @@
+<?php
+/**
+ *  Settings Page, Group, and Field API
+ */
+
+class WP_Settings {
+	private static $instance;
+
+	private $settings_pages;
+
+	/**
+	 * Returns singleton instance of api
+	 *
+	 * @return WP_Settings
+	 */
+	public static function GetInstance() {
+		if(!isset(self::$instance)) {
+			self::$instance = new WP_Settings();
+		}
+		return self::$instance;
+	}
+
+	private function __construct() {
+		$this->settings_pages = array();
+	}
+
+	public function get_setting($setting_key, $group_key, $default = null) {
+		if(is_array($setting_group = get_option($group_key)) && isset($setting_group[$setting_key])) {
+				return $setting_group[$setting_key];
+		} elseif(($group = $this->get_group($group_key)) && isset($group->settings[$setting_key]) && !empty($group->settings[$setting_key]->default_value)) {
+			return $group->settings[$setting_key]->default_value;
+		}
+		return $default;
+	}
+
+	private function get_group($group_key) {
+		foreach($this->settings_pages as $settings_page) {
+			if(isset($settings_page->groups[$group_key])) {
+				return $settings_page->groups[$group_key];
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Adds a new settings page if one doesn't already exist
+	 *
+	 * @param string $page_key
+	 * @param string $page_title
+	 * @param string $menu_title
+	 * @param string $capability
+	 * @param string $description
+	 * @param string $parent_page slug for parent page, leave empty to create new menu
+	 * @return WP_Settings_Page
+	 */
+	public function add_page($page_title, $menu_title, $page_key, $capability = 'manage_options', $description = '', $parent_page = '') {
+		if(!$capability) $capability = 'manage_options';
+
+		if ( ! $page_key ) {
+			$page_key = 'wp_'.sanitize_key($this->title);
+		}
+		if(!isset($this->settings_pages[$page_key])) {
+			$page = new WP_Settings_Page($page_title, $menu_title, $page_key, $capability, $description, $parent_page);
+			$this->settings_pages[$page_key] = $page;
+		}
+		return $this->settings_pages[$page_key];
+	}
+}
+
+class WP_Settings_Page {
+
+	public $title;
+	public $menu_title;
+	public $page_key;
+	public $capability;
+	public $description;
+
+	/**
+	 * Key of this page's parent page if it is a submenu item
+	 *
+	 * @var string
+	 */
+	public $parent_page;
+	public $groups;
+
+	public function __construct($title, $menu_title, $page_key, $capability = 'manage_options', $description = '', $parent_page = '') {
+		$this->title = $title;
+		$this->page_key = $page_key;
+		$this->menu_title = $menu_title;
+		$this->capability = $capability;
+		$this->description = $description;
+		$this->parent_page = $parent_page;
+		$this->groups = array();
+
+		global $pagenow;
+		// Quick hack to avoid adding the menu for core files.
+		if ( 0 !== strpos( 'options-', $pagenow) )
+			add_action('admin_menu', array($this, 'admin_menu'));
+		if (current_user_can($this->capability)) {
+			add_action('admin_head', array($this, 'admin_head'));
+		}
+	}
+
+	public function add_error($code, $message, $type = 'error') {
+			add_settings_error($this->page_key, $code, $message, $type);
+	}
+
+	/**
+	 * Adds a new group to the page
+	 *
+	 * @param string $group_key
+	 * @param string $title
+	 * @param string $capability
+	 * @param string $description
+	 * @return WP_Settings_Group
+	 */
+	public function add_group($title, $group_key, $capability = '', $description = '') {
+		if(!isset($this->groups[$group_key])) {
+			$group = new WP_Settings_Group($this, $title, $group_key, $capability, $description);
+			$this->groups[$group_key] = $group;
+		}
+		return $this->groups[$group_key];
+	}
+
+	public function admin_menu() {
+		if(current_user_can($this->capability)) {
+			//only add the page if groups exist
+			if($this->parent_page) {
+				add_submenu_page($this->parent_page, $this->title, $this->menu_title, $this->capability, $this->page_key, array($this, 'display'));
+			} else {
+				add_menu_page($this->title, $this->menu_title, $this->capability, $this->page_key, array($this, 'display'));
+			}
+		}
+	}
+
+	public function admin_head() {
+		register_setting($this->page_key, $this->page_key, array($this, 'sanitize_callback'));
+	}
+
+	public function sanitize_callback($new_values) {
+		if(current_user_can($this->capability)) {
+			$this->add_error('all', 'Your changes have been saved.', 'updated');
+
+			foreach($this->groups as $group) {
+				$new_value = isset($new_values[$group->group_key]) ? $new_values[$group->group_key] : array();
+				$group->sanitize_callback($new_value);
+			}
+		}
+		/**
+		 * return false so a new option doesn't get added for this.
+		 */
+		return false;
+	}
+
+	public function display() {
+		if(current_user_can($this->capability)) {
+			?>
+			<div class="wrap">
+				<?php screen_icon(); ?>
+				<h2><?php echo $this->title ?></h2>
+				<?php settings_errors($this->page_key); ?>
+				<?php if($this->description) echo "<p>{$this->description}</p>"; ?>
+				<form action="options.php" method="POST">
+					<?php settings_fields($this->page_key); ?>
+					<?php do_settings_sections($this->page_key); ?>
+					<p class="submit">
+						<input type="submit" value="Save Changes" class="button-primary" name="Submit">
+					</p>
+				</form>
+			</div>
+			<?php
+		}
+	}
+}
+
+class WP_Settings_Group {
+	/**
+	 * Pointer to this Section's Page
+	 *
+	 * @var WP_Settings_Page
+	 */
+	public $page;
+
+	public $title;
+	public $capability;
+	public $group_key;
+	public $description;
+	public $settings;
+
+	public function __construct($page, $title, $group_key, $capability = '', $description = '') {
+		$this->page = $page;
+		$this->group_key = $group_key;
+		$this->title = $title;
+		$this->capability = $capability ? $capability : $this->page->capability;
+		$this->description = $description;
+		if(current_user_can($this->capability)) {
+			add_action('admin_head', array($this, 'admin_head'));
+		}
+	}
+
+	public function add_error($code, $message, $type = 'error') {
+			$this->page->add_error($code, $message, $type);
+	}
+
+
+	public function admin_head() {
+			add_settings_section($this->group_key, $this->title, array($this, 'display'), $this->page->page_key);
+	}
+
+	/**
+	 * Adds a group to the group
+	 *
+	 * @param string $title
+	 * @param string $group_key
+	 * @param string $capability
+	 * @param string $description
+	 * @return WP_Setting
+	 */
+	public function add_setting($title, $setting_key, $args = array()) {
+		if(!isset($this->settings[$setting_key])) {
+			$setting = new WP_Setting($this, $title, $setting_key, $args);
+			$this->settings[$setting_key] = $setting;
+		}
+		return $this->settings[$setting_key];
+	}
+
+	public function display() {
+		if(current_user_can($this->capability)) {
+			if($this->description) echo "<p>{$this->description}</p>";
+		}
+	}
+
+	public function sanitize_callback($new_values) {
+		$old_values = get_option($this->group_key, array());
+		if(current_user_can($this->capability)) {
+			foreach($this->settings as $setting) {
+				$new_value = isset($new_values[$setting->setting_key]) ? $new_values[$setting->setting_key] : null;
+				$old_value = isset($old_values[$setting->setting_key]) ? $old_values[$setting->setting_key] : null;
+				$old_values[$setting->setting_key] = $setting->sanitize($new_value, $old_value);
+			}
+		}
+		update_option($this->group_key, $old_values);
+	}
+}
+
+class WP_Setting {
+
+	/**
+	 * Pointer to this settings group
+	 *
+	 * @var WP_Settings_Group
+	 */
+	public $group;
+	public $title;
+	public $setting_key;
+	public $capability;
+	public $default_value;
+	public $args;
+
+	/**
+	 * Constructor for WP Setting
+	 *
+	 * @param WP_Settings_Group $group
+	 * @param string $title
+	 * @param string $setting_key
+	 * @param array $args
+	 */
+	public function __construct($group, $title, $setting_key, $args = array()) {
+		$this->group = $group;
+		$this->title = $title;
+		$this->setting_key = $setting_key;
+
+		$args = wp_parse_args($args, $defaults = array(
+			'capability' => $this->group->capability,
+			'default_value' => '',
+			'display_callback' => '',
+			'sanitize_callbacks' => array(),
+			'description' => ''
+			));
+
+		$this->default_value = $args['default_value'];
+		$this->capability = $args['capability'];
+		$this->args = $args;
+		if(current_user_can($this->capability)) {
+			add_action('admin_head', array($this, 'admin_head'));
+		}
+	}
+
+	public function add_error($message, $type = 'error') {
+		$this->group->add_error($this->setting_key, $message, $type);
+	}
+
+	public function admin_head() {
+		add_settings_field($this->setting_key, $this->title, array($this, 'display'), $this->group->page->page_key, $this->group->group_key);
+	}
+
+	public function get_field_name() {
+		return $this->group->page->page_key . '[' . $this->group->group_key . '][' . $this->setting_key . ']';
+	}
+
+	public function get_field_id() {
+		return $this->group->page->page_key . '-' . $this->group->group_key . '-' . $this->setting_key;
+	}
+
+	public function display() {
+		$value = WP_Settings::GetInstance()->get_setting($this->setting_key, $this->group->group_key, $this->default_value);
+		if(!empty($this->args['display_callback'])) {
+			call_user_func_array($this->args['display_callback'], array($value, $this, $this->args));
+		} else {
+			?>
+			<input name="<?php echo $this->get_field_name() ?>" id="<?php echo $this->get_field_id() ?>" value="<?php echo esc_attr($value) ?>" class="regular-text" type="text">
+			<?php if(!empty($this->args['description'])) : ?>
+				<span class="description"><?php echo $this->args['description'] ?></span>
+			<?php endif; ?>
+			<?php
+		}
+	}
+
+	public function sanitize($new_value, $old_value) {
+		if(current_user_can($this->capability)) {
+			$old_value = $new_value;
+			foreach($this->args['sanitize_callbacks'] as $callback) {
+				$old_value = call_user_func_array($callback, array($old_value, $this, $this->args));
+			}
+		}
+		return $old_value;
+	}
+}
Index: wp-admin/includes/admin.php
===================================================================
--- wp-admin/includes/admin.php	(revision 18488)
+++ wp-admin/includes/admin.php	(working copy)
@@ -33,6 +33,8 @@
 /** WordPress Post Administration API */
 require_once(ABSPATH . 'wp-admin/includes/post.php');
 
+require_once(ABSPATH . 'wp-admin/includes/settings.php');
+
 /** WordPress Taxonomy Administration API */
 require_once(ABSPATH . 'wp-admin/includes/taxonomy.php');
 
Index: wp-admin/options-media.php
===================================================================
--- wp-admin/options-media.php	(revision 18488)
+++ wp-admin/options-media.php	(working copy)
@@ -25,117 +25,92 @@
 	'<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
 );
 
-include('./admin-header.php');
-
-?>
-
-<div class="wrap">
-<?php screen_icon(); ?>
-<h2><?php echo esc_html( $title ); ?></h2>
-
-<form action="options.php" method="post">
-<?php settings_fields('media'); ?>
-
-<h3><?php _e('Image sizes') ?></h3>
-<p><?php _e('The sizes listed below determine the maximum dimensions in pixels to use when inserting an image into the body of a post.'); ?></p>
-
-<table class="form-table">
-<tr valign="top">
-<th scope="row"><?php _e('Thumbnail size') ?></th>
-<td>
+function setting_thumbnail_size() { ?>
 <label for="thumbnail_size_w"><?php _e('Width'); ?></label>
 <input name="thumbnail_size_w" type="text" id="thumbnail_size_w" value="<?php form_option('thumbnail_size_w'); ?>" class="small-text" />
 <label for="thumbnail_size_h"><?php _e('Height'); ?></label>
 <input name="thumbnail_size_h" type="text" id="thumbnail_size_h" value="<?php form_option('thumbnail_size_h'); ?>" class="small-text" /><br />
 <input name="thumbnail_crop" type="checkbox" id="thumbnail_crop" value="1" <?php checked('1', get_option('thumbnail_crop')); ?>/>
 <label for="thumbnail_crop"><?php _e('Crop thumbnail to exact dimensions (normally thumbnails are proportional)'); ?></label>
-</td>
-</tr>
+<?php
+}
 
-<tr valign="top">
-<th scope="row"><?php _e('Medium size') ?></th>
-<td><fieldset><legend class="screen-reader-text"><span><?php _e('Medium size'); ?></span></legend>
+function setting_medium_size() { ?>
+<fieldset><legend class="screen-reader-text"><span><?php _e('Medium size'); ?></span></legend>
 <label for="medium_size_w"><?php _e('Max Width'); ?></label>
 <input name="medium_size_w" type="text" id="medium_size_w" value="<?php form_option('medium_size_w'); ?>" class="small-text" />
 <label for="medium_size_h"><?php _e('Max Height'); ?></label>
 <input name="medium_size_h" type="text" id="medium_size_h" value="<?php form_option('medium_size_h'); ?>" class="small-text" />
-</fieldset></td>
-</tr>
+</fieldset>
+<?php
+}
 
-<tr valign="top">
-<th scope="row"><?php _e('Large size') ?></th>
-<td><fieldset><legend class="screen-reader-text"><span><?php _e('Large size'); ?></span></legend>
+function setting_large_size() { ?>
+<fieldset><legend class="screen-reader-text"><span><?php _e('Large size'); ?></span></legend>
 <label for="large_size_w"><?php _e('Max Width'); ?></label>
 <input name="large_size_w" type="text" id="large_size_w" value="<?php form_option('large_size_w'); ?>" class="small-text" />
 <label for="large_size_h"><?php _e('Max Height'); ?></label>
 <input name="large_size_h" type="text" id="large_size_h" value="<?php form_option('large_size_h'); ?>" class="small-text" />
-</fieldset></td>
-</tr>
+</fieldset>
+<?php
+}
 
-<?php do_settings_fields('media', 'default'); ?>
-</table>
-
-<h3><?php _e('Embeds') ?></h3>
-
-<table class="form-table">
-
-<tr valign="top">
-<th scope="row"><?php _e('Auto-embeds'); ?></th>
-<td><fieldset><legend class="screen-reader-text"><span><?php _e('When possible, embed the media content from a URL directly onto the page. For example: links to Flickr and YouTube.'); ?></span></legend>
+function setting_auto_embed() { ?>
+<fieldset><legend class="screen-reader-text"><span><?php _e('When possible, embed the media content from a URL directly onto the page. For example: links to Flickr and YouTube.'); ?></span></legend>
 <label for="embed_autourls"><input name="embed_autourls" type="checkbox" id="embed_autourls" value="1" <?php checked( '1', get_option('embed_autourls') ); ?>/> <?php _e('When possible, embed the media content from a URL directly onto the page. For example: links to Flickr and YouTube.'); ?></label>
-</fieldset></td>
-</tr>
+</fieldset>
+<?php
+}
 
-<tr valign="top">
-<th scope="row"><?php _e('Maximum embed size') ?></th>
-<td>
+function setting_max_embed_size() { ?>
 <label for="embed_size_w"><?php _e('Width'); ?></label>
 <input name="embed_size_w" type="text" id="embed_size_w" value="<?php form_option('embed_size_w'); ?>" class="small-text" />
 <label for="embed_size_h"><?php _e('Height'); ?></label>
 <input name="embed_size_h" type="text" id="embed_size_h" value="<?php form_option('embed_size_h'); ?>" class="small-text" />
 <?php if ( !empty($content_width) ) echo '<br />' . __("If the width value is left blank, embeds will default to the max width of your theme."); ?>
-</td>
-</tr>
+<?php
+}
 
-<?php do_settings_fields('media', 'embeds'); ?>
-</table>
-
-<?php if ( !is_multisite() ) : ?>
-<h3><?php _e('Uploading Files'); ?></h3>
-<table class="form-table">
-<tr valign="top">
-<th scope="row"><label for="upload_path"><?php _e('Store uploads in this folder'); ?></label></th>
-<td><input name="upload_path" type="text" id="upload_path" value="<?php echo esc_attr(get_option('upload_path')); ?>" class="regular-text code" />
+function setting_upload_path() { ?>
+<input name="upload_path" type="text" id="upload_path" value="<?php echo esc_attr(get_option('upload_path')); ?>" class="regular-text code" />
 <span class="description"><?php _e('Default is <code>wp-content/uploads</code>'); ?></span>
-</td>
-</tr>
+<?php
+}
 
-<tr valign="top">
-<th scope="row"><label for="upload_url_path"><?php _e('Full URL path to files'); ?></label></th>
-<td><input name="upload_url_path" type="text" id="upload_url_path" value="<?php echo esc_attr( get_option('upload_url_path')); ?>" class="regular-text code" />
+function setting_upload_url_patch() { ?>
+<input name="upload_url_path" type="text" id="upload_url_path" value="<?php echo esc_attr( get_option('upload_url_path')); ?>" class="regular-text code" />
 <span class="description"><?php _e('Configuring this is optional. By default, it should be blank.'); ?></span>
-</td>
-</tr>
+<?php
+}
 
-<tr>
-<th scope="row" colspan="2" class="th-full">
+function setting_upload_use_year_month() { ?>
 <label for="uploads_use_yearmonth_folders">
 <input name="uploads_use_yearmonth_folders" type="checkbox" id="uploads_use_yearmonth_folders" value="1"<?php checked('1', get_option('uploads_use_yearmonth_folders')); ?> />
 <?php _e('Organize my uploads into month- and year-based folders'); ?>
 </label>
-</th>
-</tr>
+<?php
+}
 
-<?php do_settings_fields('media', 'uploads'); ?>
-</table>
-<?php endif; ?>
+$settings_page = WP_Settings::GetInstance()->add_page( $title, __('Media'), 'media' );
 
-<?php do_settings_sections('media'); ?>
+$group = $settings_page->add_group( __('Image sizes'), 'default', 'manage_options', __('The sizes listed below determine the maximum dimensions in pixels to use when inserting an image into the body of a post.') );
+$group->add_setting( __('Thumbnail size'), 'thumbnail-size', array( 'display_callback' => 'setting_thumbnail_size' ) );
+$group->add_setting( __('Medium size'), 'medium-size', array( 'display_callback' => 'setting_medium_size' ) );
+$group->add_setting( __('Large size'), 'medium-size', array( 'display_callback' => 'setting_large_size' ) );
 
-<?php submit_button(); ?>
+$group = $settings_page->add_group( __('Embeds'), 'embeds', 'manage_options' );
+$group->add_setting( __('Auto-embeds'), 'embed_autourls', array( 'display_callback' => 'setting_auto_embed' ) );
+$group->add_setting( __('Maximum embed size'), 'max-embed-size', array( 'display_callback' => 'setting_max_embed_size' ) );
 
-</form>
+if ( ! is_multisite() ) {
+	$group = $settings_page->add_group( __('Uploading Files'), 'uploads', 'manage_options' );
+	$group->add_setting( __('Store uploads in this folder'), 'upload_path', array( 'display_callback' => 'setting_upload_path' ) );
+	$group->add_setting( __('Full URL path to files'), 'upload_url_path', array( 'display_callback' => 'setting_upload_url_path' ) );
+	$group->add_setting( '', 'uploads_use_yearmonth_folders', array( 'display_callback' => setting_upload_use_year_month ) );
+}
 
-</div>
+include('./admin-header.php');
 
-<?php include('./admin-footer.php'); ?>
+$settings_page->display();
+
+include('./admin-footer.php');
