First a teeny bit of background... I have a custom post type where I'd like to use custom post statuses. Since custom post statuses (stati/status/whatever), have not been fully implemented within the core, I've decided to use the gettetext filters to change the names of certain things. For example, I've changed the text "Publish" on the publish button to say "Save". I went with something like Rarst's approach here. A summary of my code is below. I'm really not going for anything drastic here as far as changing what each status does/is.

Anyway, the translation works just fine as far as PHP is concerned. However, while testing, I realized that if I click the Edit link within the misc publishing actions div, then click the cancel link that subsequently appears, my translated "Save" button will revert to a "Publish" button.

This seems to happen as a result of the javascript function updateText() found in /wp-admin/js/post.dev.js. I'm looking for a way to keep the JS from stomping my translation. I'd prefer not to just mess with it using DOM manipulation, but if that's my only option, I'll go for it. I'm running 3.1, btw.

class MyClass {

        function __contsruct() {
            add_action( 'admin_head', array ( &$this, 'load_gettext_filters' ) );

        function load_gettext_filters() {
            add_filter( 'gettext', array ( &$this, 'change_publishing_text' ), 10, 2 );

        function change_publishing_text( $translation, $text ) {
            global $post;

            if ( ! isset ( $post->post_type ) ) {
                return $translation;

            if ( 'mypost' === $post->post_type ) {
                if ( ( 'Publish' === $text ) ) {
                    return 'Save';
            return $translation;


First, you have nasty typo in __contsruct. :)

Second, your hook timing is wrong. Related WP JavaScript is localized via postL10n object (you can see it echoed in page's source), that gets put together on init hook - way earlier then admin_head and your filter is not in place yet.

From quick test this should do it:

add_action( 'init', array ( &$this, 'load_gettext_filters' ), 9 );


Ok, scratch that. Won't work if we need context. Let's try this:

add_action('admin_footer', array ( &$this, 'localize_post_script' ) );

    function localize_post_script() {

        global $wp_scripts;

        $wp_scripts->registered['post']->extra['l10n'][1]['publish'] = __('Publish');
  • Thanks Rarst! That typo eluded me even after you pointed it out. Maybe I got a little too wrapped up in the proper way to pluralize "status" :p – Dave Romsey Apr 5 '11 at 19:16
  • Yes indeed, timing does seem to be the issue here. I confirmed that your solution does generally work, but only if I remove the post_type conditional, which I need since I only want to affect a certain post type. Can you suggest a way that I can take advantage of gettext and the post_type check? Thanks again! – Dave Romsey Apr 5 '11 at 19:48
  • @goto10 ah, slipped me that so early you do not have context set up... I will update my answer later, if I think of something. – Rarst Apr 5 '11 at 19:55
  • Awesome! Yes, I combined your updated code with what I started with (thanks for the note on t310s's post btw), and now the translated text stays translated, even after the js stuff is run. – Dave Romsey Apr 6 '11 at 2:11

You both have the right idea, but you'll actually need both filters, one to catch the button text, another to catch the localized text, so a combination of the two.

This works..

class MyClass {
    function __construct() {
        add_action('admin_head-post.php',     array ( $this, 'load_gettext_filters' ), 1 );
        add_action('admin_head-post-new.php', array ( $this, 'load_gettext_filters' ), 1 );

    function load_gettext_filters() {
        global $post_type, $wp_scripts;

        if( 'YOURTYPENAMEHERE' != $post_type )

        $wp_scripts->registered['post']->extra['l10n'][1]['publish'] = __('Save');

        add_filter( 'gettext', array ( $this, 'change_publishing_text' ), 10, 2 );

    function change_publishing_text( $translation, $text ) {
        if( 'Publish' != $text )
            return $translation;

        return __( 'Save' );
$MyClass = new MyClass;
  • Yes, my update was meant as addition to original code, not replacement. :) – Rarst Apr 5 '11 at 23:57
  • Thank you very much sir! Yes, this is working great, and I appreciate having it all laid out and whatnot. – Dave Romsey Apr 6 '11 at 2:12
  • @Rarst Edit: Dangit. It seems that I'm only able to mark 1 answer as accepted, and if I could, I'd choose both. I'm torn, because Rarst's answer (with the solution edit) was posted first and does accomplish what I asked for, but yours is a bit more polished. Super huge thanks to both of you! This place is amazing. – Dave Romsey Apr 6 '11 at 2:27
  • @goto10 it is better to choose more complete and developed answers as accepted for future visitors to be less confused about solution, so you should change accepted this one. You can always upvote my answer if it was of use. :) – Rarst Apr 6 '11 at 8:48
  • You were here answering the question with the all important info first and deserve the accept, i just tagged on at the end.. :) – t31os Apr 6 '11 at 11:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.