Moving off WP Event Manager: what's in your database and what breaks

Moving off WP Event Manager: what’s in your database and what breaks

迁移 WP Event Manager:数据库里有什么,以及哪些地方会出问题

WP Event Manager is on about 20,000 sites. The core plugin is free; recurring events, ticket sales and registrations are paid add-ons. If you’re leaving it, or just want your events out in a form another tool can read, here’s how it stores them. I read this from version 3.4.1, mostly the code that saves an event from the admin screen and the front-end form. WP Event Manager 目前被应用在大约 20,000 个网站上。其核心插件是免费的,但周期性活动、门票销售和注册功能属于付费扩展。如果你打算弃用它,或者只是想以其他工具可读取的格式导出活动数据,以下是该插件的存储方式。本文基于 3.4.1 版本分析,主要参考了从后台管理界面和前端表单保存活动的代码逻辑。

Where your events live

活动数据存储位置

Each event is a post of type event_listing. The title, description and featured image are where you’d expect. 每个活动都是一种名为 event_listing 的文章类型(post type)。标题、描述和特色图片都在你预期的位置。

  • Dates: _event_start_date and _event_end_date hold the date and time together in local time (2026-10-17 10:00:00). Use those rather than the separate time fields.
  • 日期: _event_start_date 和 _event_end_date 以本地时间格式(2026-10-17 10:00:00)同时存储日期和时间。请使用这些字段,而不是单独的时间字段。
  • _event_timezone: the event’s own zone (see trap 4 before you use it).
  • _event_timezone: 活动所属的时区(使用前请参阅下文的“陷阱 4”)。
  • _event_online: “yes” or “no”.
  • _event_online: “yes” 或 “no”。
  • The address: _event_location, _event_pincode and _event_country, stored on the event itself.
  • 地址: _event_location、_event_pincode 和 _event_country,直接存储在活动条目中。
  • Venues and organizers are their own post types, event_venue and event_organizer. Events point at them by ID in _event_venue_ids and _event_organizer_ids.
  • 场地和组织者拥有各自的文章类型:event_venue 和 event_organizer。活动通过 _event_venue_ids 和 _event_organizer_ids 中的 ID 关联它们。
  • Categories are the event_listing_category taxonomy.
  • 分类属于 event_listing_category 分类法(taxonomy)。
  • Event types are a second taxonomy, event_listing_type.
  • 活动类型是第二个分类法:event_listing_type。
  • The banner image URL is in _event_banner.
  • 横幅图片 URL 存储在 _event_banner 中。
  • The ticket choice and price are in _event_ticket_options and _event_ticket_price.
  • 门票选择和价格存储在 _event_ticket_options 和 _event_ticket_price 中。

The traps

陷阱

  1. The address belongs to the event, not the venue. A venue post has a name, a description and some links, but no address. Two events at “The Loft” can carry two different addresses. If you migrate venues on their own you lose every address; build each venue’s address from its events instead. 地址属于活动,而非场地。 场地文章包含名称、描述和一些链接,但没有地址。在“The Loft”举办的两个活动可以有不同的地址。如果你单独迁移场地,你会丢失所有地址;请务必根据活动数据来构建每个场地的地址。

  2. Dates are usually Y-m-d H:i:s, but not always. When the plugin can’t parse a date on save it stores what was typed instead, in your site’s date format. Check for those rows before you trust a straight copy: 日期通常是 Y-m-d H:i:s 格式,但并非总是如此。 当插件在保存时无法解析日期,它会直接存储用户输入的内容(即你网站的日期格式)。在进行直接复制前,请检查这些行: SELECT p.ID, p.post_title, pm.meta_value AS start_date FROM wp_posts p JOIN wp_postmeta pm ON pm.post_id = p.ID AND pm.meta_key = '_event_start_date' WHERE p.post_type = 'event_listing' AND p.post_status NOT IN ('trash', 'auto-draft') AND pm.meta_value NOT REGEXP '^[0-9]{4}-[0-9]{2}-[0-9]{2}';

  3. Past events have their own status. Once an event is over it becomes expired, a post status the plugin registers itself. Deactivate the plugin and WordPress no longer knows that status, so the admin screens and anything built on WP_Query stop seeing those posts, even though they’re still in the table. Query wp_posts directly, or export before you deactivate. 过期活动有其特定的状态。 活动结束后,其状态会变为 expired,这是插件自行注册的文章状态。一旦停用插件,WordPress 就不再识别该状态,因此后台管理界面和任何基于 WP_Query 构建的功能都将无法读取这些文章,尽管它们仍存在于数据库表中。请直接查询 wp_posts 表,或在停用插件前进行导出。

  4. _event_timezone doesn’t always mean anything. The plugin only uses it when its timezone setting (event_manager_timezone_setting) is each_event. On the default, site_timezone, events show in the site’s zone whatever that field says. So check the option before you apply the field, or a leftover value will move events by hours. _event_timezone 并不总是有效。 只有当插件的时区设置 (event_manager_timezone_setting) 为 each_event 时,该字段才会被使用。在默认的 site_timezone 设置下,无论该字段内容如何,活动都会显示在网站的时区中。因此,在应用该字段前请检查设置,否则残留的数值会导致活动时间出现数小时的偏差。

  5. The ID fields change shape. _event_organizer_ids can be an array, a single number, or a comma-separated string, depending on how the event was saved. _event_venue_ids is usually one ID. Normalise them before you look anything up: ID 字段的格式不统一。 根据活动保存方式的不同,_event_organizer_ids 可能是数组、单个数字或逗号分隔的字符串。_event_venue_ids 通常是一个 ID。在进行任何查询前,请先对其进行标准化处理:

    function wpem_ids( $value ): array { 
        $list = is_array( $value ) ? $value : preg_split( '/\s*,\s*/', (string) $value ); 
        return array_values( array_filter( array_map( 'intval', (array) $list ) ) ); 
    }
  6. Event types are a second set of labels. They’re separate from categories, with their own /event-type/<slug>/ pages. Decide whether they become categories or tags in the new system, and redirect those URLs to match. 活动类型是第二套标签。 它们与分类是分开的,拥有独立的 /event-type/<slug>/ 页面。请决定在新系统中将它们转换为分类还是标签,并相应地重定向这些 URL。

  7. Add-ons keep their own data. Ticket sales and registrations from the paid add-ons don’t live on the event post. Migrate or archive them separately. 扩展插件保留各自的数据。 付费扩展插件产生的门票销售和注册数据并不存储在活动文章中。请单独迁移或归档这些数据。


URLs

URL 结构

The defaults are /event/<slug>/, /event-category/<slug>/, /event-type/<slug>/, and the /events/ archive. All three bases can be changed under the plugin’s permalink settings, so check yours before you plan redirects. 默认结构为 /event/<slug>/、/event-category/<slug>/、/event-type/<slug>/ 以及 /events/ 归档页。这三个基础路径都可以在插件的固定链接设置中修改,因此在规划重定向之前,请先检查你的设置。

Before you switch

切换前准备

  • Run the date query above and fix any rows it returns.
  • 运行上述日期查询,并修复返回的任何异常行。
  • Check event_manager_timezone_setting.
  • 检查 event_manager_timezone_setting 设置。
  • Export while the plugin is still active, or read the table directly, so expired events come along.
  • 在插件激活状态下导出数据,或直接读取数据库表,以确保过期活动被包含在内。
  • Write down your three URL bases.
  • 记录下你的三个 URL 基础路径。
  • Decide where event types go.
  • 决定活动类型的去向。

Disclosure

披露

I build Beacon Events, a free events calendar on wordpress.org, and its importer handles all of this as of 0.11.1: https://wordpress.org/plugins/beacon-events/ . It builds venues with the address from their events, brings expired events across as past events, follows the timezone setting, and turns event types into categories with their /event-type/ links redirected. Its /event/ and /event-category/ URLs are the same as the plugin’s defaults, so most links keep working. It doesn’t import ticket sales or registrations from the paid add-ons. 我开发了 Beacon Events(一个 wordpress.org 上的免费活动日历插件),从 0.11.1 版本开始,其导入器已处理了上述所有问题:https://wordpress.org/plugins/beacon-events/。它能根据活动数据构建场地地址,将过期活动作为历史活动导入,遵循时区设置,并将活动类型转换为分类,同时重定向 /event-type/ 链接。它的 /event/ 和 /event-category/ URL 与该插件的默认设置相同,因此大多数链接可以保持有效。它不会导入付费扩展插件中的门票销售或注册数据。