WordPress.org

Make WordPress Core


Ignore:
Timestamp:
11/23/2016 09:52:27 AM (5 years ago)
Author:
helen
Message:

Theme starter content: Add support for featured images and page templates.

Featured image support means that attachments can now be imported. Media can be sideloaded from within theme or plugin directories. Like other posts, attachments are auto-drafts until customizer changes are published, and are not duplicated when they already exist in the customized state. Attachment IDs can be used for any number of purposes, much like post IDs. Twenty Seventeen now includes 3 images used as featured images to best showcase the multi-section homepage setup.

As featured image IDs are stored in post meta, it also made sense to add support for page templates. Twenty Seventeen does not include any such templates, but the functionality can be quite important for displaying themes to their best effect.

props westonruter, helen, flixos90.
fixes #38615.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-customize-manager.php

    r39345 r39346  
    917917
    918918        $sidebars_widgets = isset( $starter_content['widgets'] ) && ! empty( $this->widgets ) ? $starter_content['widgets'] : array();
     919        $attachments = isset( $starter_content['attachments'] ) && ! empty( $this->nav_menus ) ? $starter_content['attachments'] : array();
    919920        $posts = isset( $starter_content['posts'] ) && ! empty( $this->nav_menus ) ? $starter_content['posts'] : array();
    920921        $options = isset( $starter_content['options'] ) ? $starter_content['options'] : array();
     
    966967        }
    967968
     969        $starter_content_auto_draft_post_ids = array();
     970        if ( ! empty( $changeset_data['nav_menus_created_posts']['value'] ) ) {
     971            $starter_content_auto_draft_post_ids = array_merge( $starter_content_auto_draft_post_ids, $changeset_data['nav_menus_created_posts']['value'] );
     972        }
     973
     974        $existing_starter_content_posts = array();
     975        if ( ! empty( $starter_content_auto_draft_post_ids ) ) {
     976            $existing_posts_query = new WP_Query( array(
     977                'post__in' => $starter_content_auto_draft_post_ids,
     978                'post_status' => 'auto-draft',
     979                'post_type' => 'any',
     980                'number' => -1,
     981            ) );
     982            foreach ( $existing_posts_query->posts as $existing_post ) {
     983                $existing_starter_content_posts[ $existing_post->post_type . ':' . $existing_post->post_name ] = $existing_post;
     984            }
     985        }
     986
     987        // Attachments are technically posts but handled differently.
     988        if ( ! empty( $attachments ) ) {
     989            // Such is The WordPress Way.
     990            require_once( ABSPATH . 'wp-admin/includes/file.php' );
     991            require_once( ABSPATH . 'wp-admin/includes/media.php' );
     992            require_once( ABSPATH . 'wp-admin/includes/image.php' );
     993
     994            $attachment_ids = array();
     995
     996            foreach ( $attachments as $symbol => $attachment ) {
     997
     998                // A file is required and URLs to files are not currently allowed.
     999                if ( empty( $attachment['file'] ) || preg_match( '#^https?://$#', $attachment['file'] ) ) {
     1000                    continue;
     1001                }
     1002
     1003                $file_array = array();
     1004                $file_path = null;
     1005                if ( file_exists( $attachment['file'] ) ) {
     1006                    $file_path = $attachment['file']; // Could be absolute path to file in plugin.
     1007                } elseif ( is_child_theme() && file_exists( get_stylesheet_directory() . '/' . $attachment['file'] ) ) {
     1008                    $file_path = get_stylesheet_directory() . '/' . $attachment['file'];
     1009                } elseif ( file_exists( get_template_directory() . '/' . $attachment['file'] ) ) {
     1010                    $file_path = get_template_directory() . '/' . $attachment['file'];
     1011                } else {
     1012                    continue;
     1013                }
     1014                $file_array['name'] = basename( $attachment['file'] );
     1015
     1016                // Skip file types that are not recognized.
     1017                $checked_filetype = wp_check_filetype( $file_array['name'] );
     1018                if ( empty( $checked_filetype['type'] ) ) {
     1019                    continue;
     1020                }
     1021
     1022                // Ensure post_name is set since not automatically derived from post_title for new auto-draft posts.
     1023                if ( empty( $attachment['post_name'] ) ) {
     1024                    if ( ! empty( $attachment['post_title'] ) ) {
     1025                        $attachment['post_name'] = sanitize_title( $attachment['post_title'] );
     1026                    } else {
     1027                        $attachment['post_name'] = sanitize_title( preg_replace( '/\.\w+$/', '', $file_array['name'] ) );
     1028                    }
     1029                }
     1030
     1031                $attachment_id = null;
     1032                $attached_file = null;
     1033                if ( isset( $existing_starter_content_posts[ 'attachment:' . $attachment['post_name'] ] ) ) {
     1034                    $attachment_post = $existing_starter_content_posts[ 'attachment:' . $attachment['post_name'] ];
     1035                    $attachment_id = $attachment_post->ID;
     1036                    $attached_file = get_attached_file( $attachment_id );
     1037                    if ( empty( $attached_file ) || ! file_exists( $attached_file ) ) {
     1038                        $attachment_id = null;
     1039                        $attached_file = null;
     1040                    } elseif ( $this->get_stylesheet() !== get_post_meta( $attachment_post->ID, '_starter_content_theme', true ) ) {
     1041
     1042                        // Re-generate attachment metadata since it was previously generated for a different theme.
     1043                        $metadata = wp_generate_attachment_metadata( $attachment_post->ID, $attached_file );
     1044                        wp_update_attachment_metadata( $attachment_id, $metadata );
     1045                        update_post_meta( $attachment_id, '_starter_content_theme', $this->get_stylesheet() );
     1046                    }
     1047                }
     1048
     1049                // Insert the attachment auto-draft because it doesn't yet exist or the attached file is gone.
     1050                if ( ! $attachment_id ) {
     1051
     1052                    // Copy file to temp location so that original file won't get deleted from theme after sideloading.
     1053                    $temp_file_name = wp_tempnam( basename( $file_path ) );
     1054                    if ( $temp_file_name && copy( $file_path, $temp_file_name ) ) {
     1055                        $file_array['tmp_name'] = $temp_file_name;
     1056                    }
     1057                    if ( empty( $file_array['tmp_name'] ) ) {
     1058                        continue;
     1059                    }
     1060
     1061                    $attachment_post_data = array_merge(
     1062                        wp_array_slice_assoc( $attachment, array( 'post_title', 'post_content', 'post_excerpt', 'post_name' ) ),
     1063                        array(
     1064                            'post_status' => 'auto-draft', // So attachment will be garbage collected in a week if changeset is never published.
     1065                        )
     1066                    );
     1067
     1068                    // In PHP < 5.6 filesize() returns 0 for the temp files unless we clear the file status cache.
     1069                    // Technically, PHP < 5.6.0 || < 5.5.13 || < 5.4.29 but no need to be so targeted.
     1070                    // See https://bugs.php.net/bug.php?id=65701
     1071                    if ( version_compare( PHP_VERSION, '5.6', '<' ) ) {
     1072                        clearstatcache();
     1073                    }
     1074
     1075                    $attachment_id = media_handle_sideload( $file_array, 0, null, $attachment_post_data );
     1076                    if ( is_wp_error( $attachment_id ) ) {
     1077                        continue;
     1078                    }
     1079                    update_post_meta( $attachment_id, '_starter_content_theme', $this->get_stylesheet() );
     1080                }
     1081
     1082                $attachment_ids[ $symbol ] = $attachment_id;
     1083                $starter_content_auto_draft_post_ids = array_merge( $starter_content_auto_draft_post_ids, array_values( $attachment_ids ) );
     1084            }
     1085        }
     1086
    9681087        // Posts & pages.
    9691088        if ( ! empty( $posts ) ) {
    970             $nav_menus_created_posts = array();
    971             if ( ! empty( $changeset_data['nav_menus_created_posts']['value'] ) ) {
    972                 $nav_menus_created_posts = $changeset_data['nav_menus_created_posts']['value'];
    973             }
    974 
    975             $existing_posts = array();
    976             if ( ! empty( $nav_menus_created_posts ) ) {
    977                 $existing_posts_query = new WP_Query( array(
    978                     'post__in' => $nav_menus_created_posts,
    979                     'post_status' => 'auto-draft',
    980                     'post_type' => 'any',
    981                     'number' => -1,
    982                 ) );
    983                 foreach ( $existing_posts_query->posts as $existing_post ) {
    984                     $existing_posts[ $existing_post->post_type . ':' . $existing_post->post_name ] = $existing_post;
    985                 }
    986             }
    987 
    9881089            foreach ( array_keys( $posts ) as $post_symbol ) {
    9891090                if ( empty( $posts[ $post_symbol ]['post_type'] ) ) {
     
    10001101
    10011102                // Use existing auto-draft post if one already exists with the same type and name.
    1002                 if ( isset( $existing_posts[ $post_type . ':' . $post_name ] ) ) {
    1003                     $posts[ $post_symbol ]['ID'] = $existing_posts[ $post_type . ':' . $post_name ]->ID;
     1103                if ( isset( $existing_starter_content_posts[ $post_type . ':' . $post_name ] ) ) {
     1104                    $posts[ $post_symbol ]['ID'] = $existing_starter_content_posts[ $post_type . ':' . $post_name ]->ID;
    10041105                    continue;
     1106                }
     1107
     1108                // Translate the featured image symbol.
     1109                if ( ! empty( $posts[ $post_symbol ]['thumbnail'] )
     1110                    && preg_match( '/^{{(?P<symbol>.+)}}$/', $posts[ $post_symbol ]['thumbnail'], $matches )
     1111                    && isset( $attachment_ids[ $matches['symbol'] ] ) ) {
     1112                    $posts[ $post_symbol ]['meta_input']['_thumbnail_id'] = $attachment_ids[ $matches['symbol'] ];
     1113                }
     1114
     1115                if ( ! empty( $posts[ $post_symbol ]['template'] ) ) {
     1116                    $posts[ $post_symbol ]['meta_input']['_wp_page_template'] = $posts[ $post_symbol ]['template'];
    10051117                }
    10061118
     
    10111123            }
    10121124
    1013             // The nav_menus_created_posts setting is why nav_menus component is dependency for adding posts.
     1125            $starter_content_auto_draft_post_ids = array_merge( $starter_content_auto_draft_post_ids, wp_list_pluck( $posts, 'ID' ) );
     1126        }
     1127
     1128        // The nav_menus_created_posts setting is why nav_menus component is dependency for adding posts.
     1129        if ( ! empty( $this->nav_menus ) && ! empty( $starter_content_auto_draft_post_ids ) ) {
    10141130            $setting_id = 'nav_menus_created_posts';
    1015             if ( empty( $changeset_data[ $setting_id ] ) || ! empty( $changeset_data[ $setting_id ]['starter_content'] ) ) {
    1016                 $nav_menus_created_posts = array_unique( array_merge( $nav_menus_created_posts, wp_list_pluck( $posts, 'ID' ) ) );
    1017                 $this->set_post_value( $setting_id, array_values( $nav_menus_created_posts ) );
    1018                 $this->pending_starter_content_settings_ids[] = $setting_id;
    1019             }
     1131            $this->set_post_value( $setting_id, array_unique( array_values( $starter_content_auto_draft_post_ids ) ) );
     1132            $this->pending_starter_content_settings_ids[] = $setting_id;
    10201133        }
    10211134
Note: See TracChangeset for help on using the changeset viewer.