URL重写OpenCart产品SEO [英] URL Rewriting OpenCart Products SEO

查看:95
本文介绍了URL重写OpenCart产品SEO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从我的opencart网上商店重写我的产品网址. Opencart本身有一个seo实现,确实很糟糕.我已经更新了seo实现,以便能够对多个类别使用相同的关键字,请参见: Opencart重复URL关键字 但这仅适用于类别.对于这些产品,我只需要一个htaccess重写规则.

原始网址如下:

http://domain.com/index.php?route=product/product&path=25_28_93&product_id=1759

此刻我的网址看起来像这样:

http://domain.com/In-Stock/Retreaded-Tires/Agricultural?product_id=1759

如您所见,类别确实已经更改.

我希望它像这样:

http://domain.com/In-Stock/Retreaded-Tires/Agricultural/1759/1050-50R32-Mega-X-Bib

然后进行分页(在一个类别内)我有这个网址:

http://domain.com/index.php?route=product/category&path=36_70_67&page=2

我已经将其设置为:

http://domain.com/Tire-Retreading/Equalizing/&page=2

但是我希望成为

http://domain.com/Tire-Retreading/Equalizing/2

我的htaccess文件如下:

Options +FollowSymlinks
Options -Indexes
<FilesMatch "(?i)((\.tpl|\.ini|\.log|(?<!robots)\.txt))">
 Order deny,allow
 Deny from all
</FilesMatch>
RewriteEngine On
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]

我的seo_url.php文件稍作改动,看起来像这样:

public function index() {
    $this->load->model('catalog/category');
    // Add rewrite to url class
    if ($this->config->get('config_seo_url')) {
        $this->url->addRewrite($this);
    }

    // Decode URL
    if (isset($this->request->get['_route_'])) {
        $parts = explode('/', $this->request->get['_route_']);

        // remove any empty arrays from trailing
        if (utf8_strlen(end($parts)) == 0) {
            array_pop($parts);
        }

        $categories = array();

        for ($i = 0; $i < count($parts); $i++) {
            $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE keyword = '" . $this->db->escape($parts[$i]) . "'");

            if ($query->num_rows) {
                $url = explode('=', $query->row['query']);

                if ($url[0] == 'product_id') {
                    $this->request->get['product_id'] = $url[1];
                }

                if ($url[0] == 'category_id') {
                    $categories[$i] = $this->model_catalog_category->getCategory($url[1]);

                    if (!isset($this->request->get['path'])) {
                        $this->request->get['path'] = $categories[$i]['category_id'];
                    } else {
                        foreach ($query->rows as $row) {
                            $url = explode('=', $row['query']);
                            $category_id = $url[1];

                            $category = $this->model_catalog_category->getCategory($category_id);

                            if ($category['parent_id'] == $categories[$i - 1]['category_id']) {
                                $this->request->get['path'] .= '_' . $category['category_id'];
                            }
                        }
                    }
                }

                if ($url[0] == 'manufacturer_id') {
                    $this->request->get['manufacturer_id'] = $url[1];
                }

                if ($url[0] == 'information_id') {
                    $this->request->get['information_id'] = $url[1];
                }

                if ($query->row['query'] && $url[0] != 'information_id' && $url[0] != 'manufacturer_id' && $url[0] != 'category_id' && $url[0] != 'product_id') {
                    $this->request->get['route'] = $query->row['query'];
                }

            } else {
                $this->request->get['route'] = 'error/not_found';

                break;
            }
        }

        if (!isset($this->request->get['route'])) {
            if (isset($this->request->get['product_id'])) {
                $this->request->get['route'] = 'product/product';
            } elseif (isset($this->request->get['path'])) {
                $this->request->get['route'] = 'product/category';
            } elseif (isset($this->request->get['manufacturer_id'])) {
                $this->request->get['route'] = 'product/manufacturer/info';
            } elseif (isset($this->request->get['information_id'])) {
                $this->request->get['route'] = 'information/information';
            }
        }

        if (isset($this->request->get['route'])) {
            return new Action($this->request->get['route']);
        }
    }
}

public function rewrite($link) {
    $url_info = parse_url(str_replace('&amp;', '&', $link));

    $url = '';

    $data = array();

    parse_str($url_info['query'], $data);

    foreach ($data as $key => $value) {
        if (isset($data['route'])) {
            if (($data['route'] == 'product/product' && $key == 'product_id') || (($data['route'] == 'product/manufacturer/info' || $data['route'] == 'product/product') && $key == 'manufacturer_id') || ($data['route'] == 'information/information' && $key == 'information_id')) {
                $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE `query` = '" . $this->db->escape($key . '=' . (int)$value) . "'");

                if ($query->num_rows && $query->row['keyword']) {
                    $url .= '/' . $query->row['keyword'];

                    unset($data[$key]);
                }
            } elseif ($key == 'path') {
                $categories = explode('_', $value);

                foreach ($categories as $category) {
                    $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE `query` = 'category_id=" . (int)$category . "'");

                    if ($query->num_rows && $query->row['keyword']) {
                        $url .= '/' . $query->row['keyword'];
                    } else {
                        $url = '';

                        break;
                    }
                }

                unset($data[$key]);
            } else  {
                $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE `query` = '" .$data['route'] . "'");

                if ($query->num_rows && $query->row['keyword']) {
                    $url .= '/' . $query->row['keyword'];

                    unset($data[$key]);
                }
            }
        }
    }

    if ($url) {
        unset($data['route']);

        $query = '';

        if ($data) {
            foreach ($data as $key => $value) {
                $query .= '&' . rawurlencode((string)$key) . '=' . rawurlencode((string)$value);
            }

            if ($query) {
                $query = '?' . str_replace('&', '&amp;', trim($query, '&'));
            }
        }

        return $url_info['scheme'] . '://' . $url_info['host'] . (isset($url_info['port']) ? ':' . $url_info['port'] : '') . str_replace('/index.php', '', $url_info['path']) . $url . $query;
    } else {
        return $link;
    }
}

分页代码如下:

class Pagination {
    public $total = 0;
    public $page = 1;
    public $limit = 20;
    public $num_links = 8;
    public $url = '';
    public $text_first = '|&lt;';
    public $text_last = '&gt;|';
    public $text_next = '&gt;';
    public $text_prev = '&lt;';

    public function render() {
        $total = $this->total;

        if ($this->page < 1) {
            $page = 1;
        } else {
            $page = $this->page;
        }

        if (!(int)$this->limit) {
            $limit = 10;
        } else {
            $limit = $this->limit;
        }

        $num_links = $this->num_links;
        $num_pages = ceil($total / $limit);

        $this->url = str_replace('%7Bpage%7D', '{page}', $this->url);

        $output = '<ul class="pagination">';

        if ($page > 1) {
            $output .= '<li><a href="' . str_replace('{page}', 1, $this->url) . '">' . $this->text_first . '</a></li>';
            $output .= '<li><a href="' . str_replace('{page}', $page - 1, $this->url) . '">' . $this->text_prev . '</a></li>';
        }

        if ($num_pages > 1) {
            if ($num_pages <= $num_links) {
                $start = 1;
                $end = $num_pages;
            } else {
                $start = $page - floor($num_links / 2);
                $end = $page + floor($num_links / 2);

                if ($start < 1) {
                    $end += abs($start) + 1;
                    $start = 1;
                }

                if ($end > $num_pages) {
                    $start -= ($end - $num_pages);
                    $end = $num_pages;
                }
            }

            for ($i = $start; $i <= $end; $i++) {
                if ($page == $i) {
                    $output .= '<li class="active"><span>' . $i . '</span></li>';
                } else {
                    $output .= '<li><a href="' . str_replace('{page}', $i, $this->url) . '">' . $i . '</a></li>';
                }
            }
        }

        if ($page < $num_pages) {
            $output .= '<li><a href="' . str_replace('{page}', $page + 1, $this->url) . '">' . $this->text_next . '</a></li>';
            $output .= '<li><a href="' . str_replace('{page}', $num_pages, $this->url) . '">' . $this->text_last . '</a></li>';
        }

        $output .= '</ul>';

        if ($num_pages > 1) {
            return $output;
        } else {
            return '';
        }
    }
}

我所有的页面都重定向到 http://domain.com/index.php 从那里,它从route参数决定要使用的目录/文件. 因此,route=product/product告诉转到目录产品中的product.php.目录产品还包含通向路由的categories.php:route=product/category

字符串中的Path变量表示类别的ID.在我的示例中,25代表In-Stock. 25_28代表In-Stock/Retreaded-Tires等.

product_id变量代表产品的相应ID.

page变量表示分页,并用于类别内的产品列表.此列表的长度可以变化,因为它可以计算类别中有多少产品,以及他应该在一页上显示多少产品. 因此,如果原始网址的路由路径为route=product/category,且其路径为&page=2,则应使用这样的网址:http://domain.com/Tire-Retreading/Equalizing/2

解决方案

我仍然发现添加的说明令人困惑,这听起来像是我不太了解URL重写的工作原理,所以我将尽力解释一些URL重写基础.

您可以使用URL重写将<漂亮> URL 段(显示给用户的URL)转换成实际长段段,非漂亮"网址(使用变量来提供特定内容).为此,您可以使用正则表达式匹配漂亮的细分,然后为您的php变量提供预定义的值或匹配的值.

因此,您首先要做的是弄清楚漂亮的URL的外观,以及它们各自的细分如何转换为您的变量. (尽管您当然也可以使用任意数量的新变量,然后可以将其值转换并分配给php脚本中已经存在的或预定义的变量.)

您给出了以下示例: http://example.com/Tire-Retreading/Equalizing/2

此URL似乎由三个要转换为变量的部分组成:

  • Tire-Retreading(变量route)
  • Equalizing(变量path)
  • 2(变量page)

您必须基于拼写各个段的所有可能方式(包括允许的任何特殊字符等)来构建用于匹配段的RegEx.完成后,您可以将匹配的值传递给变量使用向后引用(或者您可以定义自己的值以供变量使用).

使用后向引用,您可以使用此功能:

RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/([0-9]+)$ index.php?route=$1&path=$2&page=$3 [NC,L]

您必须将用于段匹配(例如[A-Za-z-]+)的各个RegEx放在圆括号中,以便能够以$1$2等形式将结果分配给您的php变量. /p>

根据是否还应允许用户浏览产品/类别或路径的概述"页面,您可能必须开始从可能的最小漂亮" URL到最长的URL重写.

例如

RewriteRule ^([A-Za-z-]+)$ $1/ [NC,R]
RewriteRule ^([A-Za-z-]+)/$ index.php?route=$1 [NC,L]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)$ $1/$2/ [NC,R]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/$ index.php?route=$1&path=$2 [NC,L]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/([0-9]+)$ $1/$2/$3/ [NC,R]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/([0-9]+)/$ index.php?route=$1&path=$2&page=$3 [NC,L]

对域本身的重写在所有路径"重写之前进行.

您还必须找出需要使用的标志(末尾方括号中的部分),这意味着您必须阅读Opencart duplicate URL keywords But this is only working for the categories. For the products i'd just need a htaccess rewrite rule i think.

The original url looks like this:

http://domain.com/index.php?route=product/product&path=25_28_93&product_id=1759

my url looks like this at the moment:

http://domain.com/In-Stock/Retreaded-Tires/Agricultural?product_id=1759

As you can see the categories did change already.

And I want it to be like this:

http://domain.com/In-Stock/Retreaded-Tires/Agricultural/1759/1050-50R32-Mega-X-Bib

Then for pagination (within a category) I have this url:

http://domain.com/index.php?route=product/category&path=36_70_67&page=2

I've already made this into:

http://domain.com/Tire-Retreading/Equalizing/&page=2

But i'd like this to be

http://domain.com/Tire-Retreading/Equalizing/2

My htaccess file looks like this:

Options +FollowSymlinks
Options -Indexes
<FilesMatch "(?i)((\.tpl|\.ini|\.log|(?<!robots)\.txt))">
 Order deny,allow
 Deny from all
</FilesMatch>
RewriteEngine On
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]

My seo_url.php file which is a bit altered looks like this:

public function index() {
    $this->load->model('catalog/category');
    // Add rewrite to url class
    if ($this->config->get('config_seo_url')) {
        $this->url->addRewrite($this);
    }

    // Decode URL
    if (isset($this->request->get['_route_'])) {
        $parts = explode('/', $this->request->get['_route_']);

        // remove any empty arrays from trailing
        if (utf8_strlen(end($parts)) == 0) {
            array_pop($parts);
        }

        $categories = array();

        for ($i = 0; $i < count($parts); $i++) {
            $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE keyword = '" . $this->db->escape($parts[$i]) . "'");

            if ($query->num_rows) {
                $url = explode('=', $query->row['query']);

                if ($url[0] == 'product_id') {
                    $this->request->get['product_id'] = $url[1];
                }

                if ($url[0] == 'category_id') {
                    $categories[$i] = $this->model_catalog_category->getCategory($url[1]);

                    if (!isset($this->request->get['path'])) {
                        $this->request->get['path'] = $categories[$i]['category_id'];
                    } else {
                        foreach ($query->rows as $row) {
                            $url = explode('=', $row['query']);
                            $category_id = $url[1];

                            $category = $this->model_catalog_category->getCategory($category_id);

                            if ($category['parent_id'] == $categories[$i - 1]['category_id']) {
                                $this->request->get['path'] .= '_' . $category['category_id'];
                            }
                        }
                    }
                }

                if ($url[0] == 'manufacturer_id') {
                    $this->request->get['manufacturer_id'] = $url[1];
                }

                if ($url[0] == 'information_id') {
                    $this->request->get['information_id'] = $url[1];
                }

                if ($query->row['query'] && $url[0] != 'information_id' && $url[0] != 'manufacturer_id' && $url[0] != 'category_id' && $url[0] != 'product_id') {
                    $this->request->get['route'] = $query->row['query'];
                }

            } else {
                $this->request->get['route'] = 'error/not_found';

                break;
            }
        }

        if (!isset($this->request->get['route'])) {
            if (isset($this->request->get['product_id'])) {
                $this->request->get['route'] = 'product/product';
            } elseif (isset($this->request->get['path'])) {
                $this->request->get['route'] = 'product/category';
            } elseif (isset($this->request->get['manufacturer_id'])) {
                $this->request->get['route'] = 'product/manufacturer/info';
            } elseif (isset($this->request->get['information_id'])) {
                $this->request->get['route'] = 'information/information';
            }
        }

        if (isset($this->request->get['route'])) {
            return new Action($this->request->get['route']);
        }
    }
}

public function rewrite($link) {
    $url_info = parse_url(str_replace('&amp;', '&', $link));

    $url = '';

    $data = array();

    parse_str($url_info['query'], $data);

    foreach ($data as $key => $value) {
        if (isset($data['route'])) {
            if (($data['route'] == 'product/product' && $key == 'product_id') || (($data['route'] == 'product/manufacturer/info' || $data['route'] == 'product/product') && $key == 'manufacturer_id') || ($data['route'] == 'information/information' && $key == 'information_id')) {
                $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE `query` = '" . $this->db->escape($key . '=' . (int)$value) . "'");

                if ($query->num_rows && $query->row['keyword']) {
                    $url .= '/' . $query->row['keyword'];

                    unset($data[$key]);
                }
            } elseif ($key == 'path') {
                $categories = explode('_', $value);

                foreach ($categories as $category) {
                    $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE `query` = 'category_id=" . (int)$category . "'");

                    if ($query->num_rows && $query->row['keyword']) {
                        $url .= '/' . $query->row['keyword'];
                    } else {
                        $url = '';

                        break;
                    }
                }

                unset($data[$key]);
            } else  {
                $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias WHERE `query` = '" .$data['route'] . "'");

                if ($query->num_rows && $query->row['keyword']) {
                    $url .= '/' . $query->row['keyword'];

                    unset($data[$key]);
                }
            }
        }
    }

    if ($url) {
        unset($data['route']);

        $query = '';

        if ($data) {
            foreach ($data as $key => $value) {
                $query .= '&' . rawurlencode((string)$key) . '=' . rawurlencode((string)$value);
            }

            if ($query) {
                $query = '?' . str_replace('&', '&amp;', trim($query, '&'));
            }
        }

        return $url_info['scheme'] . '://' . $url_info['host'] . (isset($url_info['port']) ? ':' . $url_info['port'] : '') . str_replace('/index.php', '', $url_info['path']) . $url . $query;
    } else {
        return $link;
    }
}

The Pagination code is like this:

class Pagination {
    public $total = 0;
    public $page = 1;
    public $limit = 20;
    public $num_links = 8;
    public $url = '';
    public $text_first = '|&lt;';
    public $text_last = '&gt;|';
    public $text_next = '&gt;';
    public $text_prev = '&lt;';

    public function render() {
        $total = $this->total;

        if ($this->page < 1) {
            $page = 1;
        } else {
            $page = $this->page;
        }

        if (!(int)$this->limit) {
            $limit = 10;
        } else {
            $limit = $this->limit;
        }

        $num_links = $this->num_links;
        $num_pages = ceil($total / $limit);

        $this->url = str_replace('%7Bpage%7D', '{page}', $this->url);

        $output = '<ul class="pagination">';

        if ($page > 1) {
            $output .= '<li><a href="' . str_replace('{page}', 1, $this->url) . '">' . $this->text_first . '</a></li>';
            $output .= '<li><a href="' . str_replace('{page}', $page - 1, $this->url) . '">' . $this->text_prev . '</a></li>';
        }

        if ($num_pages > 1) {
            if ($num_pages <= $num_links) {
                $start = 1;
                $end = $num_pages;
            } else {
                $start = $page - floor($num_links / 2);
                $end = $page + floor($num_links / 2);

                if ($start < 1) {
                    $end += abs($start) + 1;
                    $start = 1;
                }

                if ($end > $num_pages) {
                    $start -= ($end - $num_pages);
                    $end = $num_pages;
                }
            }

            for ($i = $start; $i <= $end; $i++) {
                if ($page == $i) {
                    $output .= '<li class="active"><span>' . $i . '</span></li>';
                } else {
                    $output .= '<li><a href="' . str_replace('{page}', $i, $this->url) . '">' . $i . '</a></li>';
                }
            }
        }

        if ($page < $num_pages) {
            $output .= '<li><a href="' . str_replace('{page}', $page + 1, $this->url) . '">' . $this->text_next . '</a></li>';
            $output .= '<li><a href="' . str_replace('{page}', $num_pages, $this->url) . '">' . $this->text_last . '</a></li>';
        }

        $output .= '</ul>';

        if ($num_pages > 1) {
            return $output;
        } else {
            return '';
        }
    }
}

EDIT:

All of my pages are redirected to http://domain.com/index.php From there it decides what directory/file to use from the route parameter. So route=product/product is telling go to the product.php within the directory product. The directory product contains also categories.php which leads to a route: route=product/category

The Path variable from the string represents the id of a category. In my example 25 stands for In-Stock. And 25_28 stands for In-Stock/Retreaded-Tires etc.

The product_id variable represents the corresponding id for the product.

The page variable represents pagination and is used on the list of products within a category. This list can have a variable length as it calculates how many products are within a category and how many he should show on 1 page. So if the original url has &page=2 with the route route=product/category it should make an url like this: http://domain.com/Tire-Retreading/Equalizing/2

解决方案

I still find the added explanations confusing and it sounds to me like you don't quite know how URL rewriting works, so I'll try to explain some URL rewriting basics.

What you can do with URL rewriting is to translate 'pretty' URL segments (of URLs shown to the user) into segments of your actual, long, 'non-pretty' URLs (which use variables to serve certain content). You do that by using regular expressions to match the pretty segments, and then giving either pre-defined values or those matched values to your php variables.

So, what you do first is figure out how your pretty URLs should look, and how their individual segments translate to your variables. (Though you can of course also use any number of new variables, whose values you can then convert and assign to already existing or pre-defined variables in your php scripts.)

You gave this example: http://example.com/Tire-Retreading/Equalizing/2

This URL seems to be made up of three parts that you want to translate to variables:

  • Tire-Retreading (variable route)
  • Equalizing (variable path)
  • 2 (variable page)

You'll have to build your RegEx for matching your segments based on all possible ways the individual segments can be spelled, including any special characters that are allowed etc. Once that is done, you can pass the matched values to your variables using a backreference (or you could define your own values to be used by your variables).

Using backreferences, you could possibly use this:

RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/([0-9]+)$ index.php?route=$1&path=$2&page=$3 [NC,L]

You'll have to put the individual RegEx for the segment matching (like [A-Za-z-]+) in round brackets to be able to assign the results to your php variables in the form of $1, $2 etc.

Depending on if users should also be allowed to browse 'overview' pages for your products/categories or paths or not, you might have to start your rewriting from the smallest possible 'pretty' URL to the longest one.

E.g.

RewriteRule ^([A-Za-z-]+)$ $1/ [NC,R]
RewriteRule ^([A-Za-z-]+)/$ index.php?route=$1 [NC,L]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)$ $1/$2/ [NC,R]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/$ index.php?route=$1&path=$2 [NC,L]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/([0-9]+)$ $1/$2/$3/ [NC,R]
RewriteRule ^([A-Za-z-]+)/([A-Za-z-]+)/([0-9]+)/$ index.php?route=$1&path=$2&page=$3 [NC,L]

The Rewriting for the domain itself goes before all the 'path' rewriting.

You'll also have to figure out which flags – the part in square brackets at the end – you need to use, meaning you'll have to read up on URL rewriting in more detail. In the above example, all URLs the user types in that do not end with a slash are automatically redirected (that's what the R in square brackets stands for) to the same URL but with an added slash. So, http://example.com/blah would redirect to http://example.com/blah/ etc.

Based on the info you provided, you'll have URLs starting with one of two possible segments:

http://example.com/In-Stock/...

vs.

http://example.com/Product-or-Category/....

So, you'll have to take extra care these two don't get confused. If In-Stock gets funnelled into its own variable and is always spelled exactly like that, you'll probably want to make your first rules deal with that and use the RegEx for matching the products/categories only later (all rewrite rules are dealt with chronologically, one after the other).

I hope that helps.

这篇关于URL重写OpenCart产品SEO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆