【问题标题】:Fancy URL structure, conditional content, and search - using CPT, custom fields and taxonomies花哨的 URL 结构、条件内容和搜索 - 使用 CPT、自定义字段和分类法
【发布时间】:2016-08-08 15:19:05
【问题描述】:

我们正在 3 个国家(美国、加拿大和墨西哥)建立与汽车相关的企业目录。

我创建了一个自定义帖子类型“列表”并尝试继续以下操作。

出于各种 SEO 目的,我们需要如下特定的 URL 结构:

1) 个人列表页面

没什么太花哨的 - domain.com/usa/listing-slug

2) 各州档案

也没有什么花哨的 - domain.com/usa/texas

3) 每个城市的档案

这个比较有意思,我们需要如下结构:

  • domain.com/usa/cleveland/oh
  • domain.com/usa/cleveland/nd

第一个是俄亥俄州克利夫兰的档案,另一个是内华达州克利夫兰的档案。

4) 每个 ZIP 存档

很平常 - domain.com/usa/05657

5) 混合位置类别档案

  • domain.com/usa/cleveland/oh/car-parts
  • domain.com/usa/ohio/car-parts
  • domain.com/usa/05657/car-parts

6) 上述所有存档页面的自定义内容(模板),ZIP 除外

我们试图在某种程度上模仿this website

如果您检查一下,比如说,俄亥俄州克利夫兰和内华达州克利夫兰的相同示例:http://www.familydaysout.com/kids-things-to-do-usa/cleveland/ohhttp://www.familydaysout.com/kids-things-to-do-usa/cleveland/nd,您就会明白我的意思 - 这些页面的开头有自定义内容(描述)。

以上是每个城市的自定义内容示例。对于每个状态 http://www.familydaysout.com/kids-things-to-do-usa/ohio 和混合存在同样的情况: http://www.familydaysout.com/kids-things-to-do-usa/ohio/major-theme-parks http://www.familydaysout.com/kids-things-to-do-usa/cleveland/oh/major-theme-parks http://www.familydaysout.com/kids-things-to-do-usa/5601/major-theme-parks

我可以在添加新列表时自动填充位置数据,所以当我粘贴完整地址时,例如“21200 Saint Clair Avenue Euclid, Ohio 44117”,我明白了:

如您所见,国家、州、城市和邮政编码都在那里。类别(汽车零件)也作为列表类别存在。

现在我如何使用这些值来构建档案的 URL 和页面/模板?我应该自动将自定义字段值转换为自定义分类法并从那里开始吗?我知道我可以用https://codex.wordpress.org/Plugin_API/Action_Reference/save_posthttps://codex.wordpress.org/Function_Reference/wp_set_object_terms 做到这一点

我知道自定义分类法可以有描述,并且我知道如何输出这些描述。除此之外,分类法可以是分层的,因此我可以将俄亥俄州和内华达州添加为父级,并将每个克利夫兰添加为它们的子级。

所以我现在设法收集和存储所有信息位,但不确定如何开始操纵它们以实现上述模型。

Q1:我应该将位置数据(国家、州、城市、邮编)存储在哪里,以便能够在上述 URL 中使用它?自定义字段或分类术语?

Q2:如何构建如上所述的存档页面/模板,以便为它们自定义模板?

我们将不胜感激任何其他有用的提示。

【问题讨论】:

  • 我假设您不会探索其他选项,但是对于复杂的 URL 结构只会变得更加复杂和难以管理,您可能需要查看像 slimframework.com 这样的 php 路由框架.我还建议将前端编写为 API,例如在 php (twig) 或 javascript (knockout, angular 等) 中使用模板系统。您仍然可以通过 $wpdb() 轻松访问 WordPress 数据库。或者,查看 WordPress 重写 API codex.wordpress.org/Rewrite_API
  • 谢谢,我会检查重写 API。替代前端不是一种选择,至少现在不是。

标签: wordpress wordpress-theming permalinks custom-fields custom-taxonomy


【解决方案1】:

根据您的要求,您可以通过创建如下所述的类别来实现此目的:

domain.com/usa/cleveland/ohdomain.com/usa/cleveland/nd

  1. 俄亥俄州克利夫兰 (/usa/cleveland/oh)
  2. 内华达州克利夫兰 (/usa/cleveland/nd)

因此,将父类别创建为“美国”,然后将子类别创建为“克利夫兰”,在该子类别下再创建一个子类别为“俄亥俄”,并将其子类别创建为“哦”。

所以层次结构应该是USA->Cleveland->Ohio,在slugs中应该是usa->cleveland->oh

类似地,USA->Cleveland->Nevada 和 slug 为 usa->cleveland->nd

现在,要在 URL 上显示帖子:

  1. domain.com/category/usa = 为他们提供“美国”类别
  2. domain.com/category/usa/cleveland/ = 为他们提供“克利夫兰” 类别
  3. domain.com/category/usa/cleveland/oh = 向他们提供“俄亥俄州” 类别

现在您只需要从 URL 中删除 category 即可。因此,在位于根文件夹中的.htaccess 文件中写入以下代码。

RewriteRule . /wordpress/index.php [L]

【讨论】:

  • 父类别 USA 将起作用,其他一切都不起作用。一旦我创建了第一个克利夫兰 - 它的蛞蝓将是 /cleveland/,所有其他的将变成 /cleveland-1/ 或类似的。这就是问题所在 - WP 要求 slug 是独一无二的。
  • @bugnumber9 这听起来很奇怪!我认为 WordPress 不会像那样创建类别的 slug。
  • 丹,确实如此。另一个问题是我必须为每个“城市”类别创建“州”子类别。我的意思是,如果我们想象我们在 50 个州拥有 Cleveland 和 Lone Pines - 我最终会在 USA 下创建 Cleveland 和 Lone Pines,并为每个州创建 50 个相同的子类别。现在即使我走这条路——克利夫兰的爱达荷州和俄亥俄州会有 /ohio/ 和 /idaho/ 蛞蝓,Lone Pines 也会有 /idaho-lone-pines/ 和 /ohio-lone-pines/
  • 当所有州都是一个独特国家的独特子类别时,我不太明白您要做什么。相同的规则适用于城市、城镇等。为什么必须为所有 50 个州创建 Cleveland 类别?
  • Dan,即使我执行“国家 -> 州 -> 城市”层次结构 - 是的,所有州的 slug 都是独一无二的,因为所有州都是独一无二的。但是城市名称并不是唯一的,例如俄亥俄州的克利夫兰和爱达荷州的克利夫兰。所以第一个克利夫兰将有 slug /usa/ohio/cleveland/,但另一个将是 /usa/idaho/cleveland-idaho/ 或 /usa/idaho/cleveland-1/。在任何 WP 安装中自己尝试一下,你不能拥有具有相同 slug 的类别(不管它们的“级别”,即父子关系)。
【解决方案2】:

我认为有两种方法可以解决您的问题 第一个是使用 mod_rewrite 传输您建议的格式化 URL 以关联模板 php 文件并以您想要的方式处理您的请求。 对于此以下链接可能会有所帮助。谷歌了解更多https://www.addedbytes.com/articles/for-beginners/url-rewriting-for-beginners/

第二种方法是遵循 wordpress 页面模板层次结构并相应地创建模板页面并在模板 php 中处理类似的请求。详细解释参考https://www.smashingmagazine.com/2015/06/wordpress-custom-page-templates/

以及一个快速的页面模板层次结构来了解哪个页面模板将为特定的 url 执行参考https://media-mediatemple.netdna-ssl.com/wp-content/uploads/2015/05/01-wp-template-hierarchy-opt.jpg

【讨论】:

    【解决方案3】:

    搜索了一下,我想我现在可以帮你了。

    1。注册 location taxonomy 以创建基础归档 slug:

    function wpso36667674_register_location_taxonomy() {
        $labels = [
            'name'          => _x('Locations', 'Taxonomy General Name', 'wpso'),
            'singular_name' => _x('Location', 'Taxonomy Singular Name', 'wpso'),
            'all_items'     => __('All Locations', 'wpso'),
        ];
        $args = [
            'labels'        => $labels,
            'public'        => true,
            'hierarchical'  => true,
            'rewrite'       => ['hierarchical' => true],
        ];
        register_taxonomy('location', 'listing', $args);
    }
    add_action('init', 'wpso36667674_register_location_taxonomy', 0);
    

    我们必须将 WordPress 自动生成的术语 slug 更改为净化术语名称,以便 URL 的结构看起来如您所愿:

    function wpso36667674_filter_term_link($term_link, $term, $taxonomy) {
        $term_link = rtrim($term_link, '/');
        $pos = strrpos($term_link, '/');
        $term_link = substr($term_link, 0, $pos + 1) . sanitize_title($term->name);
        return $term_link;
    }
    add_filter('term_link', 'wpso36667674_filter_term_link', 0, 3);
    

    注意:添加新词时不要手动输入词条,让WordPress为我们生成,否则我们将无法正确查询词条的帖子内容。原因是两个 URL:location/usa/ohio/clevelandlocation/usa/idaho/cleveland 给了我们相同的帖子,因为 WordPress 只使用cleveland 作为查询帖子内容的术语,而不关心父术语。

    2。像这样注册listing帖子类型:

    function wpso36667674_register_listing_post_type() {
        $labels = [
            'name'          => _x('Listings', 'Taxonomy General Name', 'wpso'),
            'singular_name' => _x('Listing', 'Taxonomy Singular Name', 'wpso'),
            'all_items'     => __('All Listings', 'wpse'),
        ];
        $args = [
            'labels'        => $labels,
            'public'        => true,
            'menu_icon'     => 'dashicons-location-alt',
            'menu_position' => 6,
            'supports'      => ['title', 'editor', 'thumbnail', 'custom-fields'],
            'taxonomies'    => ['location'],
            'rewrite'       => ['slug' => '%country%/%state%/%city%/%zip%'],
        ];
        register_post_type('listing', $args);
    }
    add_action('init', 'wpso36667674_register_listing_post_type', 0);
    

    我们不确定列表是否包含 state|city|zip,因此我们必须使用替代 (%country%/%state%/%city%/%zip%)。然后用每个列表元数据替换它(根据我使用 WordPress 的经验,您应该在每个列表中存储位置数据):

    function wpso36667674_filter_post_link($post_link, $post, $leave_name = false, $sample = false) {
        $zip = get_post_meta($post->ID, 'geolocation_postcode', true);
        $city = get_post_meta($post->ID, 'geolocation_city_short', true);
        $state = get_post_meta($post->ID, 'geolocation_state_short', true);
        $country = get_post_meta($post->ID, 'geolocation_country_short', true);
        $post_link = str_replace('%zip%', $zip, $post_link);
        $post_link = str_replace('%city%', $city, $post_link);
        $post_link = str_replace('%state%', $state, $post_link);
        $post_link = str_replace('%country%', $country, $post_link);
        $post_link = preg_replace('/[^:](\/{2,})/', '/', $post_link);  // Remove multiple forward slashes except http://.
        return $post_link;
    }
    add_filter('post_type_link', 'wpso36667674_filter_post_link', 0, 4);
    

    注意:如果您使用大写短名称,则在修改 URL 结构时必须将其转换为小写。

    3。添加重写规则以使我们的自定义 URL 正常工作。

    // Add rewrite rules for location taxonomy.
    function wpso36667674_add_location_rewrite_rules() {
        add_rewrite_rule('^location/([^/]+)/?$', 'index.php?taxonomy=location&term=$matches[1]', 'top');
        add_rewrite_rule('^location/([^/]+)/([^/]+)/?$', 'index.php?taxonomy=location&term=$matches[2]', 'top');
        add_rewrite_rule('^location/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?taxonomy=location&term=$matches[3]', 'top');
    }
    add_action('init', 'wpso36667674_add_location_rewrite_rules', 0);
    
    // Add rewrite rules for listings.
    function wpso36667674_add_listing_rewrite_rules() {
        add_rewrite_rule('^usa/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[1]', 'top');
        add_rewrite_rule('^usa/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[2]', 'top');
        add_rewrite_rule('^usa/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[3]', 'top');
        add_rewrite_rule('^usa/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[4]', 'top');
        add_rewrite_rule('^mexico/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[1]', 'top');
        add_rewrite_rule('^mexico/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[2]', 'top');
        add_rewrite_rule('^mexico/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[3]', 'top');
        add_rewrite_rule('^mexico/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[4]', 'top');
        add_rewrite_rule('^canada/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[1]', 'top');
        add_rewrite_rule('^canada/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[2]', 'top');
        add_rewrite_rule('^canada/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[3]', 'top');
        add_rewrite_rule('^canada/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$', 'index.php?post_type=listing&name=$matches[4]', 'top');    
    }
    add_action('init', 'wpso36667674_add_listing_rewrite_rules', 0);
    

    4。返回正确术语的 slug:

    正如我所说,通过在永久链接中将usa/idaho/cleveland-idaho 更改为usa/idaho/clevelandusa/idaho/cleveland 的查询帖子与usa/ohio/cleveland 相同。所以我们必须帮助 WordPress 知道什么是用于查询帖子内容的正确术语 slug:

    function wpso36667674_modify_requested_url($query) {
        if ( $query->query_vars['taxonomy'] === 'location' ) {
            $slugs = array_filter( explode('/', $query->request) );
            $term = array_pop($slugs) . '-' . array_pop($slugs);
            if ( get_term_by('slug', $term, 'location') ) {
                $query->query_vars['term'] = $term;
            }
        }
    }
    add_action('parse_request', 'wpso36667674_modify_requested_url');
    

    感谢@Jevuska 建议使用parse_request

    5。为每个存档位置创建自定义模板:

    感谢WordPress Template Hierarchy,我们可以轻松搞定。

    例子:

    对于location/usa/ohio,模板为taxonomy-location-ohio.php

    但请记住,我们必须使用由 WordPress 生成的实际术语的 slug,而不是我们在 URL 中修改的内容。

    例子:

    如果在爱达荷州的克利夫兰之前添加俄亥俄州的克利夫兰,则第一个术语 slug 是 cleveland,第二个将是 cleveland-idaho

    那么,第一个模板是taxonomy-location-cleveland.php,第二个模板是taxonomy-location-cleveland-idaho.php

    就是这样!您可以直接放入functions.php 文件中的所有代码。记得刷新永久链接设置。

    【讨论】:

    • 谢谢 Den,太棒了!最后一个问题:我从哪里开始列出类别?我的意思是,比如“主题公园”:familydaysout.com/kids-things-to-do-usa/ohio/major-theme-parksfamilydaysout.com/kids-things-to-do-usa/cleveland/oh/…。这些类别必须存在于州和城市,我也应该能够为它们提供模板。我的意思是,我可以将“主题公园”添加为 CPT“列表”的类别,而且很可能我会这样做。但是我如何为它们获取单独的模板?我非常接近,但仍然缺少这一点。
    • @bugnumber9 嗯!如果您不手动输入蛞蝓,并且在克利夫兰的主要主题公园之前添加了俄亥俄州的主要主题公园。那么对于domain.com/location/usa/ohio/major-theme-parks,模板应该是taxonomy-location-major-theme-parks.php,对于domain.com/location/usa/ohio/cleveland/major-theme-parks,模板是taxonomy-location-major-theme-parks-cleveland.php
    • 嘿@Dan,我有一个小问题。我正在使用你的代码,一切看起来都很顺利,除了一件事。它会去除某个位置的域名的最后一个字母。例如。什么应该是 domain.com/five-star-autos/ 变成 domain.co/five-star-autos/ 我能够解决这个问题到这一行:$post_link = preg_replace('/[^:](\/{2,})/', '/', $post_link); 但不明白它究竟在哪里剥离'm '来自.com
    • @bugnumber9 这听起来很奇怪。我将再次测试正则表达式;-)
    • 我知道已经有一段时间了,我一直忙于设计部分:) 但我想我这里还有更多问题。想获得付费演出吗? ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 2016-02-05
    • 2020-12-11
    • 1970-01-01
    • 2013-09-02
    相关资源
    最近更新 更多