Skip to content

Support translations of renamed Post Types - #2937

Merged
corsacca merged 3 commits into
DiscipleTools:developfrom
cairocoder01:feat/post-type-label-translations
Oct 7, 2026
Merged

corsacca merged 3 commits into
DiscipleTools:developfrom
cairocoder01:feat/post-type-label-translations

Conversation

@cairocoder01

Copy link
Copy Markdown
Collaborator

If you renamed Contacts to Disciples, there was no option to set the various localizations of that new name. It just always showed the English version. This adds the ability to localize that custom name.

cairocoder01 and others added 3 commits October 7, 2026 18:02
Custom record type (post type) labels are stored as plain strings in the
dt_custom_post_types option, so they bypass gettext and cannot be translated
the way fields, field options and tiles already can. An admin who renamed
"Contacts" to "Disciples" had no way to give that label a Spanish or Swahili
equivalent.

Adds a translate button beside the Custom Singular/Plural Label inputs on
Settings -> Customizations -> <record type> -> Settings, which expands one
input per language available on the instance. Translations are stored
alongside the labels as label_singular_translations / label_plural_translations
and saved by the existing Update button.

At render time the label for the current user's locale is substituted in
dt_get_post_type_settings_after, so the nav tab, list headers, record pages,
filters and REST responses all follow the viewing user's language. wp-admin is
skipped so the settings screens keep showing and saving the base labels,
matching how field and tile translations behave. Translations are carried
through config export/import with the rest of the record type settings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The main nav and the "New <record type>" menu were built from $this->plural and
$this->singular, which the post type template captures in its constructor
straight from the dt_custom_post_types option. That bypasses
get_post_settings() entirely, so a custom label translation for the viewing
user's locale was never applied and the nav kept showing the base label.

Both now resolve through DT_Posts::get_label_for_post_type(), which is cached
per request and already carries the locale substitution.

Also fixes a long standing bug in header.php: on single records
$post_type_settings was read before being assigned (it is only populated in the
non single branch below), so record page titles always fell back to the raw post
type key - "test contact - Contacts" rather than the configured label. It now
reads the label from the post type, and no longer passes it through ucwords()
so a multi word label renders as the admin typed it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Plugins commonly read a record type's name through get_post_type_labels() or
get_post_type_object( $post_type )->labels rather than through DT_Posts -
Autolink does this for its church view tabs, as do dt-learn and
disciple-tools-import. Those labels come from register_post_type(), which the
post type template fills from properties captured in its constructor, so the
locale substitution never reached them and the labels stayed in the base
language.

Hooking post_type_labels_{$post_type} covers both routes: core runs it while
baking labels onto the WP_Post_Type object at registration, and again on every
direct get_post_type_labels() call. Only the four labels the theme supplies at
registration are replaced; the rest are core's defaults and are left alone.

Also drops the is_admin() guard on the substitution. It was copied from the
field translation hooks, but is_admin() is true for admin-ajax.php, which serves
the front end - any plugin rendering labels over admin-ajax got the base
language. The guard was never load bearing here: the settings screens populate
the label inputs from the dt_custom_post_types option directly, not from these
settings, so they still display and save the base labels. Verified by saving the
form as an admin whose locale has a translation.

Finally, keys the post type settings cache by locale. The cached array now holds
labels resolved for one user, so on a site running a persistent object cache the
old locale-independent key would have served those labels to everyone. Nothing
invalidates this key, so there are no deletion sites to keep in step.

Documents both supported ways to read a label, and that the raw option is not
one of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

Review

High: none found.

Medium: none found.

I traced the new label-translation path from the admin save (update_post_type, with locales validated against dt_get_available_languages) through to the settings filter, the WP post_type_labels_* filter and the per-locale cache key. I found no blocking problems.

  • The settings cache key is now per-locale, and nothing else reads the old key.
  • The nav, New %s menu and header title now resolve labels through DT_Posts::get_label_for_post_type.
  • header.php no longer applies ucwords() to the label. This looks intentional and is minor.

The PR looks ready to merge.

@corsacca
corsacca merged commit 074bc2c into DiscipleTools:develop Oct 7, 2026
3 checks passed
@cairocoder01
cairocoder01 deleted the feat/post-type-label-translations branch October 8, 2026 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants