Rule, or rows?

A repeating event can be stored two ways. As a rule: one event, plus a line saying “every second Tuesday”, with the dates worked out when a page is drawn. Or as rows: one real database entry for each occurrence, created ahead of time.

Rows are easier to build. Every occurrence is a normal post, so listing, filtering and editing all work without any special handling. That is why so many plugins do it, and why so many of this category's odd bugs trace back to it.

What the rows approach costs

Volume first: a weekly class over two years is 104 posts. They sit in your posts table, your sitemap, your search results, your Posts count, your backups, and every query any other plugin runs.

Then editing. Change the series and something has to reconcile 104 rows — updating the future ones, leaving the past ones, and deciding what to do about the one you moved by hand last March.

Then generation. The rows have to be created by something, usually a scheduled job. WordPress cron only runs when somebody visits, so on a quiet site the future silently runs out of occurrences until a visitor triggers the job.

And then permalinks. The best-known bug in this category is occurrence slugs that grow with every repeat — each one appending its date to the previous one's slug until they hit the database's length limit and get truncated into nonsense. That is not a typo somewhere; it is what happens when you build occurrence records in a loop and write them straight to the database instead of letting WordPress generate unique slugs.

What the rule approach costs

Honestly: more work up front. The plugin has to implement recurrence expansion properly, including the ordinal patterns, and it has to handle exceptions — a cancelled or moved occurrence — as something other than “edit that row”.

The standard answer, and the one calendars have used for decades, is that only exceptions become records. Cancel one Tuesday and there is one small entry recording that cancellation. The other fifty-one are still just the rule.

What to check in any plugin

Give it an ordinal rule — “the second Tuesday”, “the last Friday” — and count three months of dates against the expander above. Then create a two-year weekly series and look at your posts table. Those two checks tell you which of the two designs you are dealing with, and they take five minutes.