diff --git a/wp-admin/custom-background.php b/wp-admin/custom-background.php
new file mode 100644
index 0000000000..695d66740b
--- /dev/null
+++ b/wp-admin/custom-background.php
@@ -0,0 +1,245 @@
+admin_header_callback = $admin_header_callback;
+ $this->admin_image_div_callback = $admin_image_div_callback;
+ }
+
+ /**
+ * Setup the hooks for the Custom Background admin page.
+ *
+ * @since unknown
+ */
+ function init() {
+ $page = add_theme_page(__('Custom Background'), __('Custom Background'), 'switch_themes', 'custom-background', array(&$this, 'admin_page'));
+
+ add_action("admin_head-$page", array(&$this, 'take_action'), 50);
+ if ( $this->admin_header_callback )
+ add_action("admin_head-$page", $this->admin_header_callback, 51);
+ }
+
+ /**
+ * Get the current step.
+ *
+ * @since unknown
+ *
+ * @return int Current step
+ */
+ function step() {
+ if ( ! isset( $_GET['step'] ) )
+ return 1;
+
+ $step = (int) $_GET['step'];
+ if ( $step < 1 || 3 < $step )
+ $step = 1;
+
+ return $step;
+ }
+
+ /**
+ * Execute custom background modification.
+ *
+ * @since unknown
+ */
+ function take_action() {
+ if ( isset($_POST['reset-background']) ) {
+ check_admin_referer('custom-background');
+ remove_theme_mods();
+ }
+ if ( isset($_POST['repeat-background']) ) {
+ check_admin_referer('custom-background');
+ $repeat = $_POST['repeat-background'] ? true: false;
+ set_theme_mod('background_repeat', $repeat);
+ } elseif ( isset($_POST['save-background-options']) ) {
+ set_theme_mod('background_repeat', false);
+ }
+ if ( isset($_POST['remove-background']) ) {
+ check_admin_referer('custom-background');
+ set_theme_mod('background_image', '');
+ }
+ }
+
+ /**
+ * Display first step of custom background image page.
+ *
+ * @since unknown
+ */
+ function step_1() {
+ if ( isset($_GET['updated']) && $_GET['updated'] ) { ?>
+
+
Visit your site to see how it looks.'), home_url()); ?>
+
+
+
+
+
+
+
+
+
+
admin_image_div_callback ) {
+ call_user_func($this->admin_image_div_callback);
+} else {
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false);
+ $file = wp_handle_upload($_FILES['import'], $overrides);
+
+ if ( isset($file['error']) )
+ die( $file['error'] );
+
+ $url = $file['url'];
+ $type = $file['type'];
+ $file = $file['file'];
+ $filename = basename($file);
+
+ // Construct the object array
+ $object = array(
+ 'post_title' => $filename,
+ 'post_content' => $url,
+ 'post_mime_type' => $type,
+ 'guid' => $url);
+
+ // Save the data
+ $id = wp_insert_attachment($object, $file);
+
+ // Add the meta-data
+ wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
+
+ set_theme_mod('background_image', esc_url($url));
+ do_action('wp_create_file_in_uploads', $file, $id); // For replication
+ return $this->finished();
+ }
+
+ /**
+ * Display last step of custom header image page.
+ *
+ * @since unknown
+ */
+ function finished() {
+ $_GET['updated'] = 1;
+ $this->step_1();
+ }
+
+ /**
+ * Display the page based on the current step.
+ *
+ * @since unknown
+ */
+ function admin_page() {
+ $step = $this->step();
+ if ( 1 == $step )
+ $this->step_1();
+ elseif ( 2 == $step )
+ $this->step_2();
+ }
+
+}
+?>
diff --git a/wp-content/themes/twentyten/functions.php b/wp-content/themes/twentyten/functions.php
index 9abe3653f6..4774b1ac17 100644
--- a/wp-content/themes/twentyten/functions.php
+++ b/wp-content/themes/twentyten/functions.php
@@ -28,6 +28,7 @@ function twentyten_admin_header_style() {
add_custom_image_header('', 'twentyten_admin_header_style');
// and thus ends the changeable header business
+add_custom_background();
// This theme needs post thumbnails
add_theme_support( 'post-thumbnails' );
diff --git a/wp-includes/theme.php b/wp-includes/theme.php
index 2e0a45f12f..7ec46af4b8 100644
--- a/wp-includes/theme.php
+++ b/wp-includes/theme.php
@@ -1334,6 +1334,80 @@ function add_custom_image_header($header_callback, $admin_header_callback, $admi
add_action('admin_menu', array(&$GLOBALS['custom_image_header'], 'init'));
}
+/**
+ * Retrieve background image for custom background.
+ *
+ * @since 3.0.0
+ *
+ * @return string
+ */
+function get_background_image() {
+ $default = defined('BACKGROUND_IMAGE') ? BACKGROUND_IMAGE : '';
+
+ return get_theme_mod('background_image', $default);
+}
+
+/**
+ * Display background image path.
+ *
+ * @since 3.0.0
+ */
+function background_image() {
+ echo get_background_image();
+}
+
+/**
+ * Add callbacks for background image display.
+ *
+ * The parameter $header_callback callback will be required to display the
+ * content for the 'wp_head' action. The parameter $admin_header_callback
+ * callback will be added to Custom_Background class and that will be added
+ * to the 'admin_menu' action.
+ *
+ * @since 3.0.0
+ * @uses Custom_Background Sets up for $admin_header_callback for administration panel display.
+ *
+ * @param callback $header_callback Call on 'wp_head' action.
+ * @param callback $admin_header_callback Call on custom background administration screen.
+ * @param callback $admin_image_div_callback Output a custom background image div on the custom background administration screen. Optional.
+ */
+function add_custom_background($header_callback = '', $admin_header_callback = '', $admin_image_div_callback = '') {
+ if ( empty($header_callback) )
+ $header_callback = '_custom_background_cb';
+
+ add_action('wp_head', $header_callback);
+
+ if ( ! is_admin() )
+ return;
+ require_once(ABSPATH . 'wp-admin/custom-background.php');
+ $GLOBALS['custom_background'] =& new Custom_Background($admin_header_callback, $admin_image_div_callback);
+ add_action('admin_menu', array(&$GLOBALS['custom_background'], 'init'));
+}
+
+/**
+ * Default custom background callback.
+ *
+ * @since 3.0.0
+ * @see add_custom_background()
+ * @access protected
+ */
+function _custom_background_cb() {
+ $background = get_background_image();
+
+ if ( !$background )
+ return;
+
+ $repeat = get_theme_mod('background_repeat');
+ $repeat = $repeat ? '' : ' no-repeat';
+?>
+
+