搜索全站
Google SEO 16 分钟阅读

LocalBusiness 结构化数据:本地业务的地址、营业时间与坐标标注

本地门店的电话、营业时间、坐标该怎么标才被 Google 采信?本文按字段讲清 LocalBusiness 的必填与推荐项、时区与放假特殊写法、多门店的组织关系,以及与 Review 合规的边界。

U
UFO_PF 2021-12-16 · 阅读 16 分钟
Lo GOOGLE SEO
阅读提示
本文约 6,089 字,预计阅读 16 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:地图里显示的营业时间,靠的不是运气

做外贸工厂、连锁门店、线下培训机构的朋友常问一个问题:Google 搜索”某地 + 某服务”时,竞争对手的结果旁边带着时间轴、电话按钮和星星,自己却只有干巴巴的一行标题。除了 Google Business Profile(商家资料)本身的配置,网页侧的 LocalBusiness 结构化数据是另一半答案——它负责把”这家店在哪、几点开门、电话多少、属于哪个品牌”以机器可读的方式交代清楚。常见的问题是标得太潦草:地址写成一整行字符串、营业时间只写在图片里、坐标从网上随便找了个市中心。这些做法解析器既读不懂也不会采信,更糟的是可能与商家资料里的信息冲突,导致 Google 两边都不敢用。

原理分析:地址必须结构化,且必须与外部信息一致

LocalBusiness 与普通 Organization 的关键差别在两处:地理信息与营业约束。地址不能写成 "address": "上海市某某路 123 号 3 楼",必须展开为 PostalAddress 的子字段:streetAddress、addressLocality(城市)、addressRegion(省/州)、postalCode、addressCountry(ISO 3166-1 alpha-2,如 CN、US)。这种展开才能被地理解析器拆成可计算的要素。

营业时间用 openingHoursSpecification,每个时间段一个 OpeningHoursSpecification 对象,含 dayOfWeek(可以是数组)、opens、closes,时间用 24 小时制 HH:MM。24 小时营业写成 opens 00:00、closes 23:59,法定假日闭店则额外加节点并用 validFrom/validThrough 限定。

坐标 geo 用 GeoCoordinates 的 latitude、longitude,要和实际门牌位置一致,误差尽量小。

场景 推荐做法
单门店 一个 LocalBusiness,同时兼作 Organization 引用源
多门店 母公司用 Organization,各门店用 LocalBusiness 并通过 parentOrganization 关联
连锁且同一个联系号码 各门店仍各自带地址,电话可一致
纯上门服务无固定地址 用 areaServed 表达服务范围,避免编造地址

另外要重提一条硬边界:LocalBusiness 上的 aggregateRating 是 Google 出手最狠的位置之一,规则与 restrictions 同Review 与 AggregateRating 的合规边界所述——由你自己收集并展示在自家页面上的评价,不具备资格。这一条在本地业务场景里几乎家家都在踩,宁可不标。

保姆级实操

第一步:选定具体子类型

不要用通用的 LocalBusiness,schema.org 下有 Restaurant、Dentist、PlumbingService、Store、RealEstateAgent 等大量子类型,选最贴近的那个能提高匹配精度。Restaurant 额外的 servesCuisine、menu、acceptsReservations 字段也是真实可用的。

第二步:按结构化字段写 JSON-LD

{
  "@context": "https://schema.org",
  "@type": "Restaurant",
  "@id": "https://mimangfei.com/stores/shanghai/#localbusiness",
  "name": "迷芒飞咖啡(静安店)",
  "image": "https://mimangfei.com/wp-content/uploads/shop-front.jpg",
  "url": "https://mimangfei.com/stores/shanghai/",
  "telephone": "+86-21-5555-0000",
  "priceRange": "¥¥",
  "servesCuisine": "咖啡与轻食",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "南京西路 1266 号 1 层",
    "addressLocality": "上海市",
    "addressRegion": "静安区",
    "postalCode": "200040",
    "addressCountry": "CN"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": "31.2286",
    "longitude": "121.4544"
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
      "opens": "08:00",
      "closes": "21:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Saturday", "Sunday"],
      "opens": "10:00",
      "closes": "22:00"
    }
  ],
  "parentOrganization": { "@id": "https://mimangfei.com/#organization" }
}

第三步:在 WordPress 里为多门店做模板化输出

把门店信息落到自定义文章类型 location,每篇门店页自动输出对应 JSON-LD,避免人手敲一组字段。

add_action( 'wp_head', function () {
    if ( ! is_singular( 'location' ) ) {
        return;
    }
    $id   = get_the_ID();
    $bits = [
        'phone'   => get_post_meta( $id, '_loc_phone', true ),
        'street'  => get_post_meta( $id, '_loc_street', true ),
        'city'    => get_post_meta( $id, '_loc_city', true ),
        'region'  => get_post_meta( $id, '_loc_region', true ),
        'zip'     => get_post_meta( $id, '_loc_zip', true ),
        'country' => get_post_meta( $id, '_loc_country', true ) ?: 'CN',
        'lat'     => get_post_meta( $id, '_loc_lat', true ),
        'lng'     => get_post_meta( $id, '_loc_lng', true ),
    ];
    if ( ! $bits['street'] || ! $bits['lat'] ) {
        return;
    }
    $node = [
        '@context' => 'https://schema.org',
        '@type'    => 'LocalBusiness',
        '@id'      => get_permalink() . '#localbusiness',
        'name'     => get_the_title(),
        'url'      => get_permalink(),
        'telephone' => $bits['phone'],
        'address'  => [
            '@type'           => 'PostalAddress',
            'streetAddress'   => $bits['street'],
            'addressLocality' => $bits['city'],
            'addressRegion'   => $bits['region'],
            'postalCode'      => $bits['zip'],
            'addressCountry'  => $bits['country'],
        ],
        'geo'      => [
            '@type'     => 'GeoCoordinates',
            'latitude'  => $bits['lat'],
            'longitude' => $bits['lng'],
        ],
        'parentOrganization' => [ '@id' => home_url( '/#organization' ) ],
    ];
    echo '<script type="application/ld+json">' . wp_json_encode( $node, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) . '</script>';
}, 20 );

第四步:与 Google Business Profile 对齐

JSON-LD 里的电话、营业时间、地址必须与商家资料后台完全一致。任何一处分歧(比如网页写 9:00 关门、商家资料写 20:00 关门)都会让 Google 倾向于不展示该项。

第五步:佳节与临时调整的处理

长假期间临时调整,用带 validThrough 的节点临时覆盖,事后自动失效,不必改动主节点。

第六步:校验与复查

用 Rich Results Test 检查是否被识别为 LocalBusiness,用后文提到的Rich Results Test 与 Schema Markup Validator 校验流程区分”词汇错误”与”资暂无资格”两类问题。

常见踩坑

  1. 地址全部塞进 streetAddress:包括国家和省份,解析器无法结构化。
  2. addressCountry 写”中国”:要求 ISO 3166-1 alpha-2 代码,应写 CN 或 US。
  3. 营业时间只对了一半:只标工作日,周末被推定闭店。
  4. 经纬度精度太粗:用城市中心坐标代替门店坐标,地图定位会偏几百米。
  5. image 给了店内图没有门头图:Google 对识别门店外观更看重门头/招牌图。
  6. 案例:一家连锁汽修门店用了某评价插件,插件默认在 LocalBusiness 上输出 aggregateRating,分数据来自门店服务员引导到店的客户评价。上线后该域收到”结构化数据不符合 Review snippets 准则”的人工处理,全部门店的星级消失。整改后他们彻底移除了 LocalBusiness 节点的 aggregateRating,只保留地址与营业时间,并在页面上真实展示第三方平台的评分链接,三个月后才逐步恢复。
  7. 多门店共用同一 @id:节点互相覆盖,Google 只认最后一个。

总结

判断标准:网页上的每家门店,都应该能被一个独立 URL 表达,且地址、电话、营业时间与 Google 商家资料三方面完全一致。行动清单:选准子类型 → 地址展开为 PostalAddress → 坐标精确到门牌 → 工作日与周末分别声明 → 多门店用 parentOrganization 串联 → 彻底不标自筹评价 → 定期与商家资料比对。本地结构化数据的收益来自”一致性”,一旦三处信息打架,宁可不标。站点品牌层面的统一可由Organization / WebSite 站点级结构化数据承接。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。