Skip to content

Commit

Permalink
fix: replace interfering special characters from product and category…
Browse files Browse the repository at this point in the history
… slugs (#469)
  • Loading branch information
shauke committed Nov 30, 2020
1 parent 57bcabb commit 591fc99
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 10 deletions.
10 changes: 7 additions & 3 deletions src/app/core/routing/category/category.route.spec.ts
Expand Up @@ -18,7 +18,11 @@ import {
} from './category.route';

describe('Category Route', () => {
const specials = { categoryPath: ['Specials'], uniqueId: 'Specials', name: 'Spezielles (Aktion)' } as Category;
const specials = {
categoryPath: ['Specials'],
uniqueId: 'Specials',
name: 'Spezielles - 1/2 Preis - (Aktion) & mehr',
} as Category;
const topSeller = {
categoryPath: ['Specials', 'Specials.TopSeller'],
uniqueId: 'Specials.TopSeller',
Expand Down Expand Up @@ -81,7 +85,7 @@ describe('Category Route', () => {
const category = createCategoryView(categoryTree([specials]), specials.uniqueId);

it('should be created', () => {
expect(generateCategoryUrl(category)).toMatchInlineSnapshot(`"/Spezielles-Aktion-catSpecials"`);
expect(generateCategoryUrl(category)).toMatchInlineSnapshot(`"/Spezielles-1/2-Preis-Aktion-mehr-catSpecials"`);
});

it('should not be a match for matcher', () => {
Expand Down Expand Up @@ -133,7 +137,7 @@ describe('Category Route', () => {
describe('generateLocalizedCategorySlug', () => {
it('should generate slug for top level category', () => {
const category = createCategoryView(categoryTree([specials]), specials.uniqueId);
expect(generateLocalizedCategorySlug(category)).toMatchInlineSnapshot(`"Spezielles-Aktion"`);
expect(generateLocalizedCategorySlug(category)).toMatchInlineSnapshot(`"Spezielles-1/2-Preis-Aktion-mehr"`);
});

it('should generate slug for deep category', () => {
Expand Down
3 changes: 2 additions & 1 deletion src/app/core/routing/category/category.route.ts
Expand Up @@ -5,9 +5,10 @@ import { filter } from 'rxjs/operators';
import { Category } from 'ish-core/models/category/category.model';
import { CoreState } from 'ish-core/store/core/core-store';
import { selectRouteParam } from 'ish-core/store/core/router';
import { reservedCharactersRegEx } from 'ish-core/utils/routing';

export function generateLocalizedCategorySlug(category: Category) {
return category?.name?.replace(/[ \(\)]+/g, '-').replace(/-+$/g, '') || '';
return category?.name?.replace(reservedCharactersRegEx, '-').replace(/-+/g, '-').replace(/-+$/, '') || '';
}

const categoryRouteFormat = /^\/(?!category\/.*$)(.*-)?cat(.*)$/;
Expand Down
14 changes: 10 additions & 4 deletions src/app/core/routing/product/product.route.spec.ts
Expand Up @@ -84,8 +84,8 @@ describe('Product Route', () => {
});

it('should include filtered slug when product has a name with special characters', () => {
const product2 = { ...product, name: 'name & speci@l char$ (RETAIL)' };
expect(generateProductUrl(product2)).toMatchInlineSnapshot(`"/name-&-speci@l-char$-RETAIL-skuA"`);
const product2 = { ...product, name: 'name & speci@l char$ - 1/2 price - (RETAIL)' };
expect(generateProductUrl(product2)).toMatchInlineSnapshot(`"/name-speci@l-char$-1/2-price-RETAIL-skuA"`);
});

it('should be a match for matcher', () => {
Expand All @@ -103,13 +103,19 @@ describe('Product Route', () => {
sku: 'A',
name: 'some example name',
type: 'VariationProduct',
variableVariationAttributes: [{ value: 'SSD(HDD)' }, { value: 'Cobalt Blue' }],
variableVariationAttributes: [
{ value: 'SSD - (HDD)' },
{ value: 'Cobalt Blue & Yellow' },
{ value: '500 r/min' },
],
} as VariationProduct,
categoryTree()
);

it('should include attribute values in slug when product is a variation', () => {
expect(generateProductUrl(product)).toMatchInlineSnapshot(`"/some-example-name-SSD-HDD-Cobalt-Blue-skuA"`);
expect(generateProductUrl(product)).toMatchInlineSnapshot(
`"/some-example-name-SSD-HDD-Cobalt-Blue-Yellow-500-r/min-skuA"`
);
});
});
});
Expand Down
5 changes: 3 additions & 2 deletions src/app/core/routing/product/product.route.ts
Expand Up @@ -8,20 +8,21 @@ import { ProductHelper } from 'ish-core/models/product/product.model';
import { generateLocalizedCategorySlug } from 'ish-core/routing/category/category.route';
import { CoreState } from 'ish-core/store/core/core-store';
import { selectRouteParam } from 'ish-core/store/core/router';
import { reservedCharactersRegEx } from 'ish-core/utils/routing';

function generateProductSlug(product: ProductView) {
if (!product || !product.name) {
return;
}

let slug = product.name.replace(/[ \(\)]+/g, '-').replace(/-+$/g, '');
let slug = product.name.replace(reservedCharactersRegEx, '-').replace(/-+/g, '-').replace(/-+$/, '');

if (ProductHelper.isVariationProduct(product) && product.variableVariationAttributes) {
slug += '-';
slug += product.variableVariationAttributes
.map(att => att.value)
.filter(val => typeof val === 'string' || typeof val === 'boolean' || typeof val === 'number')
.map(val => val.toString().replace(/[ \(\)]+/g, '-'))
.map(val => val.toString().replace(reservedCharactersRegEx, '-'))
.join('-')
.replace(/-+/g, '-');
}
Expand Down
5 changes: 5 additions & 0 deletions src/app/core/utils/routing.ts
Expand Up @@ -23,3 +23,8 @@ export function addGlobalGuard(
}
});
}

/**
* RegEx that finds reserved characters that should not be contained in non functional parts of routes/URLs (e.g product slugs for SEO)
*/
export const reservedCharactersRegEx = /[ &\(\)]/g;

0 comments on commit 591fc99

Please sign in to comment.