namespace,
'/' . $this->rest_base . '/import_sample_products',
array(
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'import_sample_products' ),
'permission_callback' => array( $this, 'import_products_permission_check' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/create_store_pages',
array(
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_store_pages' ),
'permission_callback' => array( $this, 'create_pages_permission_check' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/create_homepage',
array(
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_homepage' ),
'permission_callback' => array( $this, 'create_pages_permission_check' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
}
/**
* Check if a given request has access to create a product.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function import_products_permission_check( $request ) {
if ( ! wc_rest_check_post_permissions( 'product', 'create' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-admin' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to create a product.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function create_pages_permission_check( $request ) {
if ( ! wc_rest_check_post_permissions( 'page', 'create' ) || ! current_user_can( 'manage_options' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create new pages.', 'woocommerce-admin' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Import sample products from WooCommerce sample CSV.
*
* @return WP_Error|WP_REST_Response
*/
public static function import_sample_products() {
include_once WC_ABSPATH . 'includes/import/class-wc-product-csv-importer.php';
$file = WC_ABSPATH . 'sample-data/sample_products.csv';
if ( file_exists( $file ) && class_exists( 'WC_Product_CSV_Importer' ) ) {
// Override locale so we can return mappings from WooCommerce in English language stores.
add_filter( 'locale', '__return_false', 9999 );
$importer_class = apply_filters( 'woocommerce_product_csv_importer_class', 'WC_Product_CSV_Importer' );
$args = array(
'parse' => true,
'mapping' => self::get_header_mappings( $file ),
);
$args = apply_filters( 'woocommerce_product_csv_importer_args', $args, $importer_class );
$importer = new $importer_class( $file, $args );
$import = $importer->import();
return rest_ensure_response( $import );
} else {
return new \WP_Error( 'woocommerce_rest_import_error', __( 'Sorry, the sample products data file was not found.', 'woocommerce-admin' ) );
}
}
/**
* Get header mappings from CSV columns.
*
* @param string $file File path.
* @return array Mapped headers.
*/
public static function get_header_mappings( $file ) {
include_once WC_ABSPATH . 'includes/admin/importers/mappings/mappings.php';
$importer_class = apply_filters( 'woocommerce_product_csv_importer_class', 'WC_Product_CSV_Importer' );
$importer = new $importer_class( $file, array() );
$raw_headers = $importer->get_raw_keys();
$default_columns = wc_importer_default_english_mappings( array() );
$special_columns = wc_importer_default_special_english_mappings( array() );
$headers = array();
foreach ( $raw_headers as $key => $field ) {
$index = $field;
$headers[ $index ] = $field;
if ( isset( $default_columns[ $field ] ) ) {
$headers[ $index ] = $default_columns[ $field ];
} else {
foreach ( $special_columns as $regex => $special_key ) {
if ( preg_match( self::sanitize_special_column_name_regex( $regex ), $field, $matches ) ) {
$headers[ $index ] = $special_key . $matches[1];
break;
}
}
}
}
return $headers;
}
/**
* Sanitize special column name regex.
*
* @param string $value Raw special column name.
* @return string
*/
public static function sanitize_special_column_name_regex( $value ) {
return '/' . str_replace( array( '%d', '%s' ), '(.*)', trim( quotemeta( $value ) ) ) . '/';
}
/**
* Returns a valid cover block with an image, if one exists, or background as a fallback.
*
* @param array $image Image to use for the cover block. Should contain a media ID and image URL.
* @return string Block content.
*/
private static function get_homepage_cover_block( $image ) {
if ( ! empty( $image['url'] ) && ! empty( $image['id'] ) ) {
return '
' . __( 'Welcome to the store', 'woocommerce-admin' ) . '
' . __( 'Write a short welcome message here', 'woocommerce-admin' ) . '
';
}
return '
' . __( 'Welcome to the store', 'woocommerce-admin' ) . '
' . __( 'Write a short welcome message here', 'woocommerce-admin' ) . '
';
}
/**
* Returns a valid media block with an image, if one exists, or a uninitialized media block the user can set.
*
* @param array $image Image to use for the cover block. Should contain a media ID and image URL.
* @param string $align If the image should be aligned to the left or right.
* @return string Block content.
*/
private static function get_homepage_media_block( $image, $align = 'left' ) {
$media_position = 'right' === $align ? '"mediaPosition":"right",' : '';
$css_class = 'right' === $align ? ' has-media-on-the-right' : '';
if ( ! empty( $image['url'] ) && ! empty( $image['id'] ) ) {
return '
';
}
return '
';
}
/**
* Returns a homepage template to be inserted into a post. A different template will be used depending on the number of products.
*
* @param int $post_id ID of the homepage template.
* @return string Template contents.
*/
private static function get_homepage_template( $post_id ) {
$products = wp_count_posts( 'product' );
if ( $products->publish >= 4 ) {
$images = self::sideload_homepage_images( $post_id, 1 );
$image_1 = ! empty( $images[0] ) ? $images[0] : '';
$cover = self::get_homepage_cover_block( $image_1 );
return $cover . '
' . __( 'Shop by Category', 'woocommerce-admin' ) . '
[product_categories limit="3" columns="3" orderby="menu_order"]
' . __( 'New In', 'woocommerce-admin' ) . '
[products limit="4" columns="4" orderby="date" order="DESC"]
' . __( 'Fan Favorites', 'woocommerce-admin' ) . '
[products limit="4" columns="4" orderby="rating"]
' . __( 'On Sale', 'woocommerce-admin' ) . '
[products limit="4" columns="4" orderby="date" order="DESC" on_sale="1"]
' . __( 'Best Sellers', 'woocommerce-admin' ) . '
[products limit="4" columns="4" best_selling="1"]
';
}
$images = self::sideload_homepage_images( $post_id, 3 );
$image_1 = ! empty( $images[0] ) ? $images[0] : '';
$image_2 = ! empty( $images[1] ) ? $images[1] : '';
$image_3 = ! empty( $images[2] ) ? $images[2] : '';
$cover = self::get_homepage_cover_block( $image_1 );
return $cover . '
' . __( 'New Products', 'woocommerce-admin' ) . '
' .
self::get_homepage_media_block( $image_1, 'right' ) .
self::get_homepage_media_block( $image_2, 'left' ) .
self::get_homepage_media_block( $image_3, 'right' ) . '
';
}
/**
* Gets the possible industry images from the plugin folder for sideloading. If an image doesn't exist, other.jpg is used a fallback.
*
* @return array An array of images by industry.
*/
private static function get_available_homepage_images() {
$industry_images = array();
$industries = Onboarding::get_allowed_industries();
foreach ( $industries as $industry_slug => $label ) {
$file_path = WC_ADMIN_ABSPATH . 'images/onboarding/' . $industry_slug . '.jpg';
if ( 'other' === $industry_slug || ! file_exists( $file_path ) ) {
$industry_images[ $industry_slug ] = apply_filters( 'woocommerce_admin_onboarding_industry_image', plugins_url( 'images/onboarding/other.jpg', WC_ADMIN_PLUGIN_FILE ), $industry_slug );
continue;
}
$industry_images[ $industry_slug ] = apply_filters( 'woocommerce_admin_onboarding_industry_image', plugins_url( 'images/onboarding/' . $industry_slug . '.jpg', WC_ADMIN_PLUGIN_FILE ), $industry_slug );
}
return $industry_images;
}
/**
* Uploads a number of images to a homepage template, depending on the selected industry from the profile wizard.
*
* @param int $post_id ID of the homepage template.
* @param int $number_of_images The number of images that should be sideloaded (depending on how many media slots are in the template).
* @return array An array of images that have been attached to the post.
*/
private static function sideload_homepage_images( $post_id, $number_of_images ) {
$profile = get_option( Onboarding::PROFILE_DATA_OPTION, array() );
$images_to_sideload = array();
$available_images = self::get_available_homepage_images();
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
if ( ! empty( $profile['industry'] ) ) {
foreach ( $profile['industry'] as $selected_industry ) {
$images_to_sideload[] = ! empty( $available_images[ $selected_industry ] ) ? $available_images[ $selected_industry ] : $available_images['other'];
}
}
// Make sure we have at least {$number_of_images} images.
if ( count( $images_to_sideload ) < $number_of_images ) {
for ( $i = count( $images_to_sideload ); $i < $number_of_images; $i++ ) {
$images_to_sideload[] = ! empty( $profile['industry'] ) && ! empty( $available_images[ $profile['industry'][0] ] ) ? $available_images[ $profile['industry'][0] ] : $available_images['other'];
}
}
$already_sideloaded = array();
$images_for_post = array();
foreach ( $images_to_sideload as $image ) {
// Avoid uploading two of the same image, if an image is repeated.
if ( ! empty( $already_sideloaded[ $image ] ) ) {
$images_for_post[] = $already_sideloaded[ $image ];
continue;
}
$sideload_id = \media_sideload_image( $image, $post_id, null, 'id' );
if ( ! is_wp_error( $sideload_id ) ) {
$sideload_url = wp_get_attachment_url( $sideload_id );
$already_sideloaded[ $image ] = array(
'id' => $sideload_id,
'url' => $sideload_url,
);
$images_for_post[] = $already_sideloaded[ $image ];
}
}
return $images_for_post;
}
/**
* Creates base store starter pages like my account and checkout.
* Note that WC_Install::create_pages already checks if pages exist before creating them again.
*
* @return bool
*/
public static function create_store_pages() {
\WC_Install::create_pages();
return true;
}
/**
* Create a homepage from a template.
*
* @return WP_Error|array
*/
public static function create_homepage() {
$post_id = wp_insert_post(
array(
'post_title' => __( 'Homepage', 'woocommerce-admin' ),
'post_type' => 'page',
'post_status' => 'draft',
'post_content' => '', // Template content is updated below, so images can be attached to the post.
)
);
if ( ! is_wp_error( $post_id ) ) {
$template = self::get_homepage_template( $post_id );
wp_update_post(
array(
'ID' => $post_id,
'post_content' => $template,
)
);
update_option( 'woocommerce_onboarding_homepage_post_id', $post_id );
return array(
'status' => 'success',
'message' => __( 'Homepage created successfully.', 'woocommerce-admin' ),
'post_id' => $post_id,
'edit_post_link' => htmlspecialchars_decode( get_edit_post_link( $post_id ) ),
);
} else {
return $post_id;
}
}
}