Better permalink settings. Closes #1579.

This commit is contained in:
Mike Jolley 2012-10-10 10:21:04 +01:00
parent 07c9537fbb
commit 9505e5d63f
7 changed files with 302 additions and 109 deletions

View File

@ -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' ), '<a target="_blank" href="' . admin_url( 'options-permalink.php' ) . '">', '</a>' ),
'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' ), '<a target="_blank" href="options-permalink.php">', '</a>' ),
'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 (<code>%s</code>)', '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 (<code>%s</code>)', '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

View File

@ -736,3 +736,190 @@ function woocommerce_admin_comment_types_dropdown( $types ) {
}
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 <strong>not using "default" permalinks above</strong>.', '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%' )
);
?>
<table class="form-table">
<tbody>
<tr>
<th><label><input name="product_permalink" type="radio" value="<?php echo $structures[0]; ?>" class="wctog" <?php checked( $structures[0], $product_permalink ); ?> /> <?php _e( 'Default' ); ?></label></th>
<td><code><?php echo home_url(); ?>/?product=sample-product</code></td>
</tr>
<tr>
<th><label><input name="product_permalink" type="radio" value="<?php echo $structures[1]; ?>" class="wctog" <?php checked( $structures[1], $product_permalink ); ?> /> <?php _e( 'Product', 'woocommerce' ); ?></label></th>
<td><code><?php echo home_url(); ?>/<?php echo $product_base; ?>/sample-product/</code></td>
</tr>
<?php if ( $shop_page_id ) : ?>
<tr>
<th><label><input name="product_permalink" type="radio" value="<?php echo $structures[2]; ?>" class="wctog" <?php checked( $structures[2], $product_permalink ); ?> /> <?php _e( 'Shop base', 'woocommerce' ); ?></label></th>
<td><code><?php echo home_url(); ?>/<?php echo $base_slug; ?>/sample-product/</code></td>
</tr>
<tr>
<th><label><input name="product_permalink" type="radio" value="<?php echo $structures[3]; ?>" class="wctog" <?php checked( $structures[3], $product_permalink ); ?> /> <?php _e( 'Shop base with category', 'woocommerce' ); ?></label></th>
<td><code><?php echo home_url(); ?>/<?php echo $base_slug; ?>/product-category/sample-product/</code></td>
</tr>
<?php endif; ?>
<tr>
<th><label><input name="product_permalink" id="woocommerce_custom_selection" type="radio" value="custom" class="tog" <?php checked( in_array( $product_permalink, $structures ), false ); ?> />
<?php _e( 'Custom Base', 'woocommerce' ); ?></label></th>
<td>
<input name="product_permalink_structure" id="woocommerce_permalink_structure" type="text" value="<?php echo $product_permalink; ?>" class="regular-text code"> <span class="description"><?php _e( 'Enter a custom base to use. A base <strong>must</strong> be set or WordPress will use default instead.', 'woocommerce' ); ?></span>
</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
jQuery(function(){
jQuery('input.wctog').change(function() {
jQuery('#woocommerce_permalink_structure').val( jQuery(this).val() );
});
jQuery('#woocommerce_permalink_structure').focus(function(){
jQuery('#woocommerce_custom_selection').click();
});
});
</script>
<?php
}
/**
* woocommerce_permalink_settings_init function.
*
* @access public
* @return void
*/
function woocommerce_permalink_settings_init() {
// Add a section to the permalinks page
add_settings_section( 'woocommerce-permalink', __( 'Product permalink base', 'woocommerce' ), 'woocommerce_permalink_settings', 'permalink' );
// Add our settings
add_settings_field(
'woocommerce_product_category_slug', // id
__( 'Product category base', 'woocommerce' ), // setting title
'woocommerce_product_category_slug_input', // display callback
'permalink', // settings page
'optional' // settings section
);
add_settings_field(
'woocommerce_product_tag_slug', // id
__( 'Product tag base', 'woocommerce' ), // setting title
'woocommerce_product_tag_slug_input', // display callback
'permalink', // settings page
'optional' // settings section
);
add_settings_field(
'woocommerce_product_attribute_slug', // id
__( 'Product attribute base', 'woocommerce' ), // setting title
'woocommerce_product_attribute_slug_input', // display callback
'permalink', // settings page
'optional' // settings section
);
}
add_action( 'admin_init', 'woocommerce_permalink_settings_init' );
/**
* woocommerce_permalink_settings_save function.
*
* @access public
* @return void
*/
function woocommerce_permalink_settings_save() {
if ( ! is_admin() )
return;
// We need to save the options ourselves; settings api does not trigger save for the permalinks page
if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) {
// Cat and tag bases
$woocommerce_product_category_slug = esc_html( stripslashes( $_POST['woocommerce_product_category_slug'] ) );
$woocommerce_product_tag_slug = esc_html( stripslashes( $_POST['woocommerce_product_tag_slug'] ) );
$woocommerce_product_attribute_slug = esc_html( stripslashes( $_POST['woocommerce_product_attribute_slug'] ) );
$permalinks = get_option( 'woocommerce_permalinks' );
if ( ! $permalinks )
$permalinks = array();
$permalinks['category_base'] = untrailingslashit( $woocommerce_product_category_slug );
$permalinks['tag_base'] = untrailingslashit( $woocommerce_product_tag_slug );
$permalinks['attribute_base'] = untrailingslashit( $woocommerce_product_attribute_slug );
// Product base
$product_permalink = esc_html( stripslashes( $_POST['product_permalink'] ) );
if ( $product_permalink == 'custom' ) {
$product_permalink = esc_html( stripslashes( $_POST['product_permalink_structure'] ) );
} elseif ( empty( $product_permalink ) ) {
$product_permalink = false;
}
$permalinks['product_base'] = untrailingslashit( $product_permalink );
update_option( 'woocommerce_permalinks', $permalinks );
}
}
add_action( 'before_woocommerce_init', 'woocommerce_permalink_settings_save' );
/**
* woocommerce_product_category_slug_input function.
*
* @access public
* @return void
*/
function woocommerce_product_category_slug_input() {
$permalinks = get_option( 'woocommerce_permalinks' );
?>
<input name="woocommerce_product_category_slug" type="text" class="regular-text code" value="<?php if ( isset( $permalinks['category_base'] ) ) echo esc_attr( $permalinks['category_base'] ); ?>" placeholder="<?php echo _x('product-category', 'slug', 'woocommerce') ?>" />
<?php
}
/**
* woocommerce_product_tag_slug_input function.
*
* @access public
* @return void
*/
function woocommerce_product_tag_slug_input() {
$permalinks = get_option( 'woocommerce_permalinks' );
?>
<input name="woocommerce_product_tag_slug" type="text" class="regular-text code" value="<?php if ( isset( $permalinks['tag_base'] ) ) echo esc_attr( $permalinks['tag_base'] ); ?>" placeholder="<?php echo _x('product-tag', 'slug', 'woocommerce') ?>" />
<?php
}
/**
* woocommerce_product_attribute_slug_input function.
*
* @access public
* @return void
*/
function woocommerce_product_attribute_slug_input() {
$permalinks = get_option( 'woocommerce_permalinks' );
?>
<input name="woocommerce_product_attribute_slug" type="text" class="regular-text code" value="<?php if ( isset( $permalinks['attribute_base'] ) ) echo esc_attr( $permalinks['attribute_base'] ); ?>" /><code>/attribute-name/attribute/</code>
<?php
}

View File

@ -24,6 +24,40 @@ function do_install_woocommerce() {
woocommerce_tables_install();
woocommerce_init_roles();
// Setup default permalinks
$permalinks = get_option( 'woocommerce_permalinks' );
$shop_page_id = woocommerce_get_page_id( 'shop' );
if ( empty( $permalinks ) && $shop_page_id > 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]' );
}

View File

@ -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');
}

View File

@ -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.

View File

@ -1016,13 +1016,13 @@ 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
@ -1030,17 +1030,45 @@ function woocommerce_product_cat_filter_post_link( $permalink, $post ) {
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 );

View File

@ -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
**/
$permalinks = get_option( 'woocommerce_permalinks' );
$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';
// 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';
$category_base = ( get_option('woocommerce_prepend_shop_page_to_urls') == "yes" ) ? trailingslashit($base_slug) : '';
// 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'];
$category_slug = ( get_option('woocommerce_product_category_slug') ) ? get_option('woocommerce_product_category_slug') : _x('product-category', 'slug', 'woocommerce');
if ( $product_permalink )
$rewrite = array( 'slug' => untrailingslashit( $product_permalink ), 'with_front' => false );
else
$rewrite = false;
$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;
$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 ),
)
);
@ -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,