$theme_obj->ID, 'post_status' => 'any', 'post_type' => 'theme_file', ) ); return false; } /** * Gets revision data for a file. * * @param string $theme * @param string $file Not implemented. * @return array Revision data */ function get_theme_file_revision_data( $theme, $file = null ) { if ( ! $file_data = get_theme_file_data( $theme ) ) return false; $ids = array(); foreach ( $file_data as $file ) $ids[] = $file->ID; $revisions = get_posts( array( 'post_type' => 'theme_file_revision', 'post_status' => 'any', 'suppress_filters' => false, 'post_parent__in' => array( $ids ), ) ); // @todo map this to each file. return $revisions; } // // Revision setters. // /** * Creates a theme revision based on a file. * * @param string $theme Theme root * @param string $file File, relative to theme * @param string|null $new_content Optional. New content. Defaults to null, which then uses content on disk. * @param bool $check_changes Optional. Whether the file should be checked for changes before generating a revision. * @return int|WP_Error The value 0 or WP_Error on failure. The post ID on success. */ function create_theme_file_revision( $theme, $file, $new_content = null, $check_changes = true ) { if ( null === $new_content ) { $f = fopen( $file, 'r' ); $new_content = fread( $f, filesize( $file ) ); } $revised_theme = get_theme_revision_data( $theme ); $revisions = get_theme_file_revision_data( $theme, $file ); $last_revision = empty( $revisions ) ? 0 : end( $revisions ); if ( $last_revision && $check_changes && $last_revision->post_name == md5( $new_content ) ) return false; $args = array( 'post_type' => 'theme_revision', 'post_content' => $new_content, 'post_name' => $last_revision ? md5( $new_content ) : $file, 'post_parent' => $last_revision ? $last_revision->ID : $revised_theme->ID, 'post_status' => 'draft', 'post_author' => get_current_user_id(), ); return wp_insert_post( $args ); } /** * Generates initial revisions for a theme. * * Returns false if theme already has revisions. * * @param string $theme * @return bool True on success, false on failure. */ function start_theme_revisions( $theme ) { if ( get_revised_theme_object( $theme ) ) return false; $theme_data = get_theme( $theme ); $allowed_files = array_merge( $theme_data['Stylesheet Files'], $theme_data['Template Files'] ); foreach ( $allowed_files as $file ) create_theme_file_revision( $theme, $file ); return true; } /** * Deletes a theme file revision. * * @param int $revision * @return bool|WP_Error True on success, WP_Error on failure. */ function delete_theme_file_revision( $revision ) { if ( ! $post = get_post( $revision ) ) return false; if ( $post->post_type != 'theme_file_revision' ) return false; return wp_delete_post( $revision, true ); } // // Snapshot functions // /** * Create a theme snapshot. * * @param string $theme * @return int|WP_Error ID of snapshot term on success, WP_Error on failure. */ function create_theme_snapshot( $theme ) { $revised_theme = get_theme_revision_data( $theme ); $for_snapshot = array(); $term_id = wp_insert_term( 'snapshot-' . current_time('timestamp'), 'snapshot' ); if ( is_wp_error( $term_id ) ) return $term_id; foreach ( $revised_theme as $revised_file ) { $file = end( $revised_file['revisions'] ); wp_set_object_terms( $file->ID, array( $term_id ), 'snapshot', true ); } return $term_id; } /** * Restores a theme snapshot. * * @param int $snapshot Snapshot's term ID * @return bool|WP_Error True on success, WP_Error on failure. */ function restore_theme_snapshot( $snapshot ) { $snapshot_term = get_objects_in_term( $snapshot, 'snapshot' ); // fetch most recent theme file revision IDs // copy over the snapshot term } /** * Delete a theme snapshot. * * @param int $snapshot Snapshot's term ID * @return bool|WP_Error ID of snapshot term on success, WP_Error on failure. */ function delete_theme_snapshot( $snapshot ) { return wp_delete_term( $snapshot, 'snapshot' ); } /** * Restores a file to a revision. * * @todo This code doesn't make much sense yet. Yeah. * * @param string $theme * @param string $file * @return bool|WP_Error True on success, WP_Error on failure. */ function restore_theme_file_revision( $theme, $file, $revision ) { $revised_theme = get_theme_revision_data( $theme ); $revised_file = get_theme_file_revision_data( $theme, $file ); $restoring = get_post( $revised_file[0]->ID ); $restoring['ID'] = $revision; return wp_insert_post( $restoring ); } /** * Gets most recent revisions to a theme's files. * * @param string $theme * @param int $count Optional. Number of recent revisions. Default 20. * @param bool $duplicate Optional. Whether to return multiple revisions of the same file. Default true. * @return array Revision data, sorted by date descending. */ function get_recent_theme_revisions( $theme, $count = 20, $duplicate = true ) {}