From 9505e5d63f214facbc76d187e2ec2864e3df4e95 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Wed, 10 Oct 2012 10:21:04 +0100 Subject: [PATCH] Better permalink settings. Closes #1579. --- admin/settings/settings-init.php | 75 ++--------- admin/woocommerce-admin-init.php | 189 ++++++++++++++++++++++++++- admin/woocommerce-admin-install.php | 39 +++++- admin/woocommerce-admin-settings.php | 4 +- readme.txt | 3 + woocommerce-core-functions.php | 42 +++++- woocommerce.php | 59 ++++----- 7 files changed, 302 insertions(+), 109 deletions(-) diff --git a/admin/settings/settings-init.php b/admin/settings/settings-init.php index c725b2bb021..a7c5c6bba49 100644 --- a/admin/settings/settings-init.php +++ b/admin/settings/settings-init.php @@ -339,17 +339,22 @@ if ( $shop_page_id > 0 && sizeof(get_pages("child_of=$shop_page_id")) > 0 ) $woocommerce_settings['pages'] = apply_filters('woocommerce_page_settings', array( - array( 'name' => __( 'Page Setup', 'woocommerce' ), 'type' => 'title', 'desc' => '', 'id' => 'page_options' ), + array( + 'name' => __( 'Page Setup', 'woocommerce' ), + 'type' => 'title', + 'desc' => sprintf( __( 'Set up core WooCommerce pages here, for example the base page. The base page can also be used in your %sproduct permalinks%s.', 'woocommerce' ), '', '' ), + 'id' => 'page_options' + ), array( 'name' => __( 'Shop Base Page', 'woocommerce' ), - 'desc' => sprintf( __( 'This sets the base page of your shop - this is where your product archive will be.', 'woocommerce' ), '', '' ), + 'desc' => __( 'This sets the base page of your shop - this is where your product archive will be.', 'woocommerce' ), 'id' => 'woocommerce_shop_page_id', 'type' => 'single_select_page', 'std' => '', 'class' => 'chosen_select_nostd', 'css' => 'min-width:300px;', - 'desc_tip' => true, + 'desc_tip' => true ), array( @@ -383,66 +388,6 @@ $woocommerce_settings['pages'] = apply_filters('woocommerce_page_settings', arra array( 'type' => 'sectionend', 'id' => 'page_options' ), - array( 'name' => __( 'Permalinks', 'woocommerce' ), 'type' => 'title', 'desc' => '', 'id' => 'permalink_options' ), - - array( - 'name' => __( 'Product base category', 'woocommerce' ), - 'desc' => __( 'Prepend product permalinks with product category', 'woocommerce' ), - 'id' => 'woocommerce_prepend_category_to_products', - 'std' => 'no', - 'type' => 'checkbox', - 'checkboxgroup' => 'start' - ), - - array( - 'name' => __( 'Product base page', 'woocommerce' ), - 'desc' => sprintf(__( 'Prepend product permalinks with shop base page (%s)', 'woocommerce' ), $base_slug) . $woocommerce_prepend_shop_page_to_products_warning, - 'id' => 'woocommerce_prepend_shop_page_to_products', - 'std' => 'yes', - 'type' => 'checkbox', - 'checkboxgroup' => 'end' - ), - - array( - 'name' => __( 'Product slug', 'woocommerce' ), - 'desc' => __( 'Shows in the single product URLs. Leave blank to use the default slug. Can only be used if shop base page isn\'t prepended.', 'woocommerce' ), - 'id' => 'woocommerce_product_slug', - 'type' => 'text', - 'css' => 'min-width:300px;', - 'std' => '', - 'desc_tip' => true, - ), - - array( - 'name' => __( 'Taxonomy base page', 'woocommerce' ), - 'desc' => sprintf(__( 'Prepend shop categories/tags with shop base page (%s)', 'woocommerce' ), $base_slug), - 'id' => 'woocommerce_prepend_shop_page_to_urls', - 'std' => 'no', - 'type' => 'checkbox', - ), - - array( - 'name' => __( 'Product category slug', 'woocommerce' ), - 'desc' => __( 'Shows in the product category URLs. Leave blank to use the default slug.', 'woocommerce' ), - 'id' => 'woocommerce_product_category_slug', - 'type' => 'text', - 'css' => 'min-width:300px;', - 'std' => '', - 'desc_tip' => true, - ), - - array( - 'name' => __( 'Product tag slug', 'woocommerce' ), - 'desc' => __( 'Shows in the product tag URLs. Leave blank to use the default slug.', 'woocommerce' ), - 'id' => 'woocommerce_product_tag_slug', - 'type' => 'text', - 'css' => 'min-width:300px;', - 'std' => '', - 'desc_tip' => true, - ), - - array( 'type' => 'sectionend', 'id' => 'permalink_options' ), - array( 'name' => __( 'Shop Pages', 'woocommerce' ), 'type' => 'title', 'desc' => __( 'The following pages need selecting so that WooCommerce knows where they are. These pages should have been created upon installation of the plugin, if not you will need to create them.', 'woocommerce' ) ), array( @@ -535,7 +480,7 @@ $woocommerce_settings['pages'] = apply_filters('woocommerce_page_settings', arra array( 'name' => __( 'Lost Password Page', 'woocommerce' ), - 'desc' => __( 'Page contents: [woocommerce_lost_password]', 'woocommerce' ), + 'desc' => __( 'Page contents: [woocommerce_lost_password] Parent: "My Account"', 'woocommerce' ), 'id' => 'woocommerce_lost_password_page_id', 'type' => 'single_select_page', 'std' => '', @@ -544,7 +489,7 @@ $woocommerce_settings['pages'] = apply_filters('woocommerce_page_settings', arra 'desc_tip' => true, ), - array( 'type' => 'sectionend', 'id' => 'page_options'), + array( 'type' => 'sectionend', 'id' => 'page_options') )); // End pages settings diff --git a/admin/woocommerce-admin-init.php b/admin/woocommerce-admin-init.php index d1dbb9908f8..4c06fee3da4 100644 --- a/admin/woocommerce-admin-init.php +++ b/admin/woocommerce-admin-init.php @@ -735,4 +735,191 @@ function woocommerce_admin_comment_types_dropdown( $types ) { return $types; } -add_filter( 'admin_comment_types_dropdown', 'woocommerce_admin_comment_types_dropdown' ); \ No newline at end of file +add_filter( 'admin_comment_types_dropdown', 'woocommerce_admin_comment_types_dropdown' ); + + +/** + * woocommerce_permalink_settings function. + * + * @access public + * @return void + */ +function woocommerce_permalink_settings() { + + echo wpautop( __( 'These settings control the permalinks used for products. These settings only apply when not using "default" permalinks above.', 'woocommerce' ) ); + + $permalinks = get_option( 'woocommerce_permalinks' ); + $product_permalink = $permalinks['product_base']; + + // Get shop page + $shop_page_id = woocommerce_get_page_id( 'shop' ); + $base_slug = ( $shop_page_id > 0 && get_page( $shop_page_id ) ) ? get_page_uri( $shop_page_id ) : _x( 'shop', 'default-slug', 'woocommerce' ); + $product_base = _x( 'product', 'default-slug', 'woocommerce' ); + + $structures = array( + 0 => '', + 1 => '/' . trailingslashit( $product_base ), + 2 => '/' . trailingslashit( $base_slug ), + 3 => '/' . trailingslashit( $base_slug ) . trailingslashit( '%product_cat%' ) + ); + ?> + + + + + + + + + + + + + + + + + + + + + + + + + +
/?product=sample-product
//sample-product/
//sample-product/
//product-category/sample-product/
+ must be set or WordPress will use default instead.', 'woocommerce' ); ?> +
+ + + + + + + /attribute-name/attribute/ + 0 ) { + + $base_slug = $shop_page_id > 0 && get_page( $shop_page_id ) ? get_page_uri( $shop_page_id ) : 'shop'; + + $category_base = get_option('woocommerce_prepend_shop_page_to_urls') == "yes" ? trailingslashit( $base_slug ) : ''; + $category_slug = get_option('woocommerce_product_category_slug') ? get_option('woocommerce_product_category_slug') : _x( 'product-category', 'slug', 'woocommerce' ); + $tag_slug = get_option('woocommerce_product_tag_slug') ? get_option('woocommerce_product_tag_slug') : _x( 'product-tag', 'slug', 'woocommerce' ); + + if ( 'yes' == get_option('woocommerce_prepend_shop_page_to_products') ) { + $product_base = trailingslashit( $base_slug ); + } else { + if ( ( $product_slug = get_option('woocommerce_product_slug') ) !== false && ! empty( $product_slug ) ) { + $product_base = trailingslashit( $product_slug ); + } else { + $product_base = trailingslashit( _x('product', 'slug', 'woocommerce') ); + } + } + + if ( get_option('woocommerce_prepend_category_to_products') == 'yes' ) + $product_base .= trailingslashit('%product_cat%'); + + $permalinks = array( + 'product_base' => untrailingslashit( $product_base ), + 'category_base' => untrailingslashit( $category_base . $category_slug ), + 'attribute_base' => untrailingslashit( $category_base ), + 'tag_base' => untrailingslashit( $category_base . $tag_slug ) + ); + + update_option( 'woocommerce_permalinks', $permalinks ); + } // Register post types $woocommerce->init_taxonomy(); @@ -192,6 +226,9 @@ function woocommerce_create_pages() { // My Account page woocommerce_create_page( esc_sql( _x( 'my-account', 'page_slug', 'woocommerce' ) ), 'woocommerce_myaccount_page_id', __( 'My Account', 'woocommerce' ), '[woocommerce_my_account]' ); + // Lost password page + woocommerce_create_page( esc_sql( _x( 'lost-password', 'page_slug', 'woocommerce' ) ), 'woocommerce_lost_password_page_id', __( 'Lost Password', 'woocommerce' ), '[woocommerce_lost_password]', woocommerce_get_page_id( 'myaccount' ) ); + // Edit address page woocommerce_create_page( esc_sql( _x( 'edit-address', 'page_slug', 'woocommerce' ) ), 'woocommerce_edit_address_page_id', __( 'Edit My Address', 'woocommerce' ), '[woocommerce_edit_address]', woocommerce_get_page_id( 'myaccount' ) ); @@ -207,8 +244,6 @@ function woocommerce_create_pages() { // Thanks page woocommerce_create_page( esc_sql( _x( 'order-received', 'page_slug', 'woocommerce' ) ), 'woocommerce_thanks_page_id', __( 'Order Received', 'woocommerce' ), '[woocommerce_thankyou]', woocommerce_get_page_id( 'checkout' ) ); - // Lost password page - woocommerce_create_page( esc_sql( _x( 'lost-password', 'page_slug', 'woocommerce' ) ), 'woocommerce_lost_password_page_id', __( 'Lost Password', 'woocommerce' ), '[woocommerce_lost_password]' ); } diff --git a/admin/woocommerce-admin-settings.php b/admin/woocommerce-admin-settings.php index 47097ade874..650835c14c3 100644 --- a/admin/woocommerce-admin-settings.php +++ b/admin/woocommerce-admin-settings.php @@ -119,8 +119,7 @@ if ( ! function_exists( 'woocommerce_settings' ) ) { } - // Flush rules and clear any unwanted data - flush_rewrite_rules( false ); + // Clear any unwanted data $woocommerce->clear_product_transients(); // Redirect back to the settings page @@ -152,7 +151,6 @@ if ( ! function_exists( 'woocommerce_settings' ) ) { // Were the settings saved? if ( ! empty( $_GET['saved'] ) ) { - flush_rewrite_rules( false ); do_action('woocommerce_settings_saved'); } diff --git a/readme.txt b/readme.txt index 89885c870f8..ba89d1ff0b5 100644 --- a/readme.txt +++ b/readme.txt @@ -170,6 +170,9 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc * Feature - Expanded bulk edit for prices. Change to, increase by, decrease by. * Feature - Set attribute order (globally, per attribute). * Feature - Allow setting the product post type slug to a static (non-translatable) text, mainly to be used for translating and WPML setups. +* Feature - Added lost password shortcode / email notification (thanks Max Rice). +* Feature - Simplified permalink/base settings now found in Settings > Permalinks. +* Feature - Support more permalink structures (from http://codex.wordpress.org/Using_Permalinks) * Templating - email-order-items.php change get_downloadable_file_url() to get_downloadable_file_urls() to support multiple files. * Templating - loop-end and start for product loops, allow changing the UL's used by default to something else. diff --git a/woocommerce-core-functions.php b/woocommerce-core-functions.php index 51cd7948a33..f62d7d6d581 100644 --- a/woocommerce-core-functions.php +++ b/woocommerce-core-functions.php @@ -1016,31 +1016,59 @@ add_action('woocommerce_order_status_completed', 'woocommerce_paying_customer'); * @param object $post * @return string */ -function woocommerce_product_cat_filter_post_link( $permalink, $post ) { +function woocommerce_product_post_type_link( $permalink, $post ) { // Abort if post is not a product if ( $post->post_type !== 'product' ) return $permalink; - + // Abort early if the placeholder rewrite tag isn't in the generated URL - if ( false === strpos( $permalink, '%product_cat%' ) ) + if ( false === strpos( $permalink, '%' ) ) return $permalink; - + // Get the custom taxonomy terms in use by this post $terms = get_the_terms( $post->ID, 'product_cat' ); if ( empty( $terms ) ) { // If no terms are assigned to this post, use a string instead (can't leave the placeholder there) - $permalink = str_replace( '%product_cat%', _x('product', 'slug', 'woocommerce'), $permalink ); + $product_cat = _x( 'uncategorized', 'slug', 'woocommerce' ); } else { // Replace the placeholder rewrite tag with the first term's slug $first_term = array_shift( $terms ); - $permalink = str_replace( '%product_cat%', $first_term->slug, $permalink ); + $product_cat = $first_term->slug; } + + $find = array( + '%year%', + '%monthnum%', + '%day%', + '%hour%', + '%minute%', + '%second%', + '%post_id%', + '%category%', + '%product_cat%' + ); + + $replace = array( + date_i18n( 'Y', strtotime( $post->post_date ) ), + date_i18n( 'm', strtotime( $post->post_date ) ), + date_i18n( 'd', strtotime( $post->post_date ) ), + date_i18n( 'H', strtotime( $post->post_date ) ), + date_i18n( 'i', strtotime( $post->post_date ) ), + date_i18n( 's', strtotime( $post->post_date ) ), + $post->ID, + $product_cat, + $product_cat + ); + + $replace = array_map( 'sanitize_title', $replace ); + + $permalink = str_replace( $find, $replace, $permalink ); return $permalink; } -add_filter( 'post_type_link', 'woocommerce_product_cat_filter_post_link', 10, 2 ); +add_filter( 'post_type_link', 'woocommerce_product_post_type_link', 10, 2 ); diff --git a/woocommerce.php b/woocommerce.php index 8ff63ef1e7d..330401a3ad1 100644 --- a/woocommerce.php +++ b/woocommerce.php @@ -277,6 +277,9 @@ class Woocommerce { * @return void */ function init() { + //Before init action + do_action( 'before_woocommerce_init' ); + // Set up localisation $this->load_plugin_textdomain(); @@ -616,36 +619,30 @@ class Woocommerce { */ function init_taxonomy() { - if ( post_type_exists('product') ) return; + if ( post_type_exists('product') ) + return; /** * Slugs **/ - $shop_page_id = woocommerce_get_page_id('shop'); - - $base_slug = ( $shop_page_id > 0 && get_page( $shop_page_id ) ) ? get_page_uri( $shop_page_id ) : 'shop'; - - $category_base = ( get_option('woocommerce_prepend_shop_page_to_urls') == "yes" ) ? trailingslashit($base_slug) : ''; - - $category_slug = ( get_option('woocommerce_product_category_slug') ) ? get_option('woocommerce_product_category_slug') : _x('product-category', 'slug', 'woocommerce'); - - $tag_slug = ( get_option('woocommerce_product_tag_slug') ) ? get_option('woocommerce_product_tag_slug') : _x('product-tag', 'slug', 'woocommerce'); - - if ( 'yes' == get_option('woocommerce_prepend_shop_page_to_products') ) { - $product_base = trailingslashit( $base_slug ); - } else { - if ( ( $product_slug = get_option('woocommerce_product_slug') ) !== false && ! empty( $product_slug ) ) { - $product_base = trailingslashit( $product_slug ); - } else { - $product_base = trailingslashit( _x('product', 'slug', 'woocommerce') ); - } - } - - if ( get_option('woocommerce_prepend_category_to_products') == 'yes' ) $product_base .= trailingslashit('%product_cat%'); - - $product_base = untrailingslashit($product_base); - - if ( current_user_can('manage_woocommerce') ) $show_in_menu = 'woocommerce'; else $show_in_menu = true; + $permalinks = get_option( 'woocommerce_permalinks' ); + $shop_page_id = woocommerce_get_page_id( 'shop' ); + + // Base slug is also used for the product post type archive + $base_slug = $shop_page_id > 0 && get_page( $shop_page_id ) ? get_page_uri( $shop_page_id ) : 'shop'; + + // Get bases + $product_category_slug = empty( $permalinks['category_base'] ) ? _x( 'product-category', 'slug', 'woocommerce' ) : $permalinks['category_base']; + $product_tag_slug = empty( $permalinks['tag_base'] ) ? _x( 'product-tag', 'slug', 'woocommerce' ) : $permalinks['tag_base']; + $product_attribute_base = empty( $permalinks['attribute_base'] ) ? '' : $permalinks['attribute_base']; + $product_permalink = empty( $permalinks['product_base'] ) ? _x( 'product', 'slug', 'woocommerce' ) : $permalinks['product_base']; + + if ( $product_permalink ) + $rewrite = array( 'slug' => untrailingslashit( $product_permalink ), 'with_front' => false ); + else + $rewrite = false; + + $show_in_menu = current_user_can( 'manage_woocommerce' ) ? 'woocommerce' : true; /** * Taxonomies @@ -692,7 +689,7 @@ class Woocommerce { 'delete_terms' => 'delete_product_terms', 'assign_terms' => 'assign_product_terms', ), - 'rewrite' => array( 'slug' => $category_base . $category_slug, 'with_front' => false, 'hierarchical' => true ), + 'rewrite' => array( 'slug' => $product_category_slug, 'with_front' => false, 'hierarchical' => true ), ) ); @@ -723,7 +720,7 @@ class Woocommerce { 'delete_terms' => 'delete_product_terms', 'assign_terms' => 'assign_product_terms', ), - 'rewrite' => array( 'slug' => $category_base . $tag_slug, 'with_front' => false ), + 'rewrite' => array( 'slug' => $product_tag_slug, 'with_front' => false ), ) ); @@ -821,7 +818,7 @@ class Woocommerce { 'assign_terms' => 'assign_product_terms', ), 'show_in_nav_menus' => $show_in_nav_menus, - 'rewrite' => array( 'slug' => $category_base . strtolower(sanitize_title($tax->attribute_name)), 'with_front' => false, 'hierarchical' => $hierarchical ), + 'rewrite' => array( 'slug' => $product_attribute_base . strtolower( sanitize_title( $tax->attribute_name ) ), 'with_front' => false, 'hierarchical' => $hierarchical ), ) ); @@ -833,7 +830,7 @@ class Woocommerce { * Post Types **/ do_action( 'woocommerce_register_post_type' ); - + register_post_type( "product", apply_filters( 'woocommerce_register_post_type_product', array( @@ -861,7 +858,7 @@ class Woocommerce { 'publicly_queryable' => true, 'exclude_from_search' => false, 'hierarchical' => false, // Hierarcal causes memory issues - WP loads all records! - 'rewrite' => array( 'slug' => $product_base, 'with_front' => false, 'feeds' => $base_slug ), + 'rewrite' => $rewrite, 'query_var' => true, 'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'comments', 'custom-fields', 'page-attributes' ), 'has_archive' => $base_slug,