Get Shopware 6 Product URL

426 Views Asked by At

How do I get the product URL from Shopware 6.

When I 'read' data for a particular product via the product ID, the 'seoURL' field is usually empty. How do I retrieve the correct product URL?

1

There are 1 best solutions below

0
Jacob On

There are more than one way to do it depending on where you want to do it from, but by using the Database Abstraction Layer (DAL) from PHP, you want to use getAssociation on seoUrl, and also remember to filter by the language you want.

1. First you need to create the context, this is used to fetch the right URL depending on language and sales channel. How exactly to create the context also depends on your specific scenario.

In this example we are altering a HTTP response from a Shopware plugin, so to get the sales channel id and language id, we can use the request object. E.g:

$salesChannelId = $event->getRequest()->get('sw-sales-channel-id');
$languageId = $event->getRequest()->headers->get('sw-language-id');

// To avoid rare errors when null
// just return in those cases and let Shopware deal with it
if (empty($this->salesChannelId) || empty($this->languageId)) {
  return;
}

We need these IDs for creating the context itself:

// Note. $this->salesChannelContextFactory should be defined in your constructor
$context = (
$this->salesChannelContextFactory->create(
  '', $salesChannelId, [SalesChannelContextService::LANGUAGE_ID => $languageId]
  )
)->getContext();

2. For simplicity, this is how to fetch the seo url by productId and our created $context:

$criteria = new Criteria();

$criteria->addFilter(
  new EqualsFilter(
    'id', [$productId]
  )
);
$criteria->getAssociation('seoUrls')->addFilter(
  new EqualsFilter(
    'languageId', $context->getLanguageId()
  )
);

// Attempt to fetch the product
$product = $this->productRepository->search($criteria, $context);

// Since we get by ID, the first() will always be what we are looking for,
// but we still need to check if something was actually returned.
// E.g. Check for "null"
if (null === ($product = $product->first())) {
  // throw new Exception('No product returned.');
  // Note. "return;" can be used in some scenarios,
  //       and Shopware will instead handle the
  //       situation and decide what response to send.
  return;
}

// Check if a seo url exists for the returned product
// Again. The first() URL returned will be the one we want
if (null === ($firstSeoUrl = $product->getSeoUrls()->first())) {
  // throw new Exception('Product found, but no seo URL found.');
  return;
}

// The actual seo url string is stored in seoPathInfo
// in the seo_url table. Fetch this with getSeoPathInfo().
$seoUrlString = $firstSeoUrl->getSeoPathInfo();

// Check if the string is not empty (This can sometimes happen too. Sigh!)
if (null === $seoUrlString || strlen($seoUrlString) <= 0) {
  // throw new Exception('No product returned.');
  return;
}

Fyi. It is done in similar ways in the vue.js based administration.

The vue.js based administration

For the administration backend, create the productRepository:

computed: {
  productRepository() {
    return this.repositoryFactory.create('product');
  },
}

2. Then create a method to fetch a product:

methods: {
  getProduct() {
    productId = 'Your Product ID';
    const criteria = new Criteria();
    criteria.getAssociation('seoUrls');
    criteria.addFilter(
      Criteria.equals('id', productId)
    );
    this.productRepository.search(criteria).then((data) => {
      this.product = data.first();

      // Show the fetched product data in console
      console.log(this.product);
      this.$emit('element-update', this.element);
    });
  }
}

Note: If you want to avoid this huge mess of code to do such a simple thing, sometimes you can "do with" a simple storefront detail-URL, that will be automatically redirected to the actual seoUrl:

example.com/detail/[ProductId]