Set posts of a custom post type to be private by default?

Say I created a custom post type called ‘Private Posts’ ($post_type = itsme_private_posts) and want all posts under the custom post type to be set to ‘Private’ automatically when published i.e. by default. How do I do it?

Based on @brasofilo’s answer to a related question on StackOverflow, I tried this:

Read More
add_filter( 'wp_insert_post_data', 'itsme_cpt_private', '99', 2 );
function itsme_cpt_private( $data , $postarr ) {
    if( $postarr['post_type'] == 'itsme_private_posts' ) {
        $data['post_status'] = 'private';
    }
    return $data;
}

It doesn’t work i.e. it doesn’t do anything; everything’s the way it was before adding the function. It’s as though the function doesn’t exist or simply does nothing.

Then, based on this article titled, “Force custom post type to be private“, I tried this:

add_filter( 'wp_insert_post_data', 'itsme_cpt_private' );
function itsme_cpt_private( $post ) {
    if( $post['post_type'] == 'itsme_private_posts' ) {
        $post['post_status'] = 'private';
    }
    return $post;
}

It works, in that, when I publish or update a post it turns private. Good! But when I create a new post (‘Add New’) and leave without doing anything, it creates a ‘private’ (auto-)draft and saves it. Moreover I can’t even trash that thing!

Essentially I can’t figure out how to do it. So, how do I set posts of a custom post type to be private by default?

Related posts

3 comments

  1. The problem with the code in your question is it always intercepts. You completely lose the ability to not publish, no drafts possible. Why this leads to untrashable post is something I didn’t inspect further. Anyway this isn’t what one wants.

    I’m glad the javascript solution is working for you, but personally I have two problems with it, first, you can save post as public, second, it makes it harder – because the script always sets the radio button to private – to handle working with drafts. In a way there are now two solutions to the answer.


    1. Forcing post type to be private plus visual indication:

    This is why I took another look at doing it with post status transitions and, like I said, it can be done with Post Status Transitions.

    Code:

    add_action( 'transition_post_status', 'wpse118970_post_status_new', 10, 3 );
    function wpse118970_post_status_new( $new_status, $old_status, $post ) { 
        if ( $post->post_type == 'itsme_private_posts' && $new_status == 'publish' && $old_status  != $new_status ) {
            $post->post_status = 'private';
            wp_update_post( $post );
        }
    } 
    

    This forces published posts of your post type to be private. Without interfering with the ability to save drafts. This on it’s own would be enough to solve the problem of having a private post type.
    But of course it would be nice to have the private nature of the post type represented in the publishing metabox. For this I adjusted the javascript a little bit. Mainly by not setting the checkbox by default, but still changing the text shown, additionally I added a note.

    Code:

    add_action( 'post_submitbox_misc_actions' , 'wpse118970_change_visibility_metabox' );
    function wpse118970_change_visibility_metabox(){
        global $post;
        if ($post->post_type != 'post')
            return;
            $message = __('<strong>Note:</strong> Published posts are always <strong>private</strong>.');
            $post->post_password = '';
            $visibility = 'private';
            $visibility_trans = __('Private');
        ?>
        <style type="text/css">
            .priv_pt_note {
                background-color: lightgreen;
                border: 1px solid green;
                border-radius: 2px;
                margin: 4px;
                padding: 4px;
            }
        </style>
        <script type="text/javascript">
            (function($){
                try {
                    $('#post-visibility-display').text('<?php echo $visibility_trans; ?>');
                    $('#hidden-post-visibility').val('<?php echo $visibility; ?>');
                } catch(err){}
            }) (jQuery);
        </script>
        <div class="priv_pt_note">
            <?php echo $message; ?>
        </div>
        <?php
    }
    

    Source: How to set new posts visibility to private by default?
    Note: Compared to the code below I removed the checking of the radio button and additionally added code for the message.

    Of course you don’t need the javascript to make your post type private, but it’s always nice to have things visually indicated. For that reason it’s a nice addition.


    2. Making private the standard option in the publishing meta box:

    I’m keeping this because @its_me accepted the answer for this as solution. Like I said in the comment I found a helpful piece of code, it takes care of setting the visibility at the meta box to private by hooking into post_submitbox_misc_actions. Like I said in the beginning »I have two problems with it, first, you can save post as public, second, it makes it harder – because the script always sets the radio button to private – to handle working with drafts«. It’s still possible to have and work with drafts, just not as intuitive as before, but the private publishing status is in no way enforced.

    Code:

    add_action( 'post_submitbox_misc_actions' , 'wpse118970_change_visibility_metabox_value' );
    function wpse118970_change_visibility_metabox_value(){
        global $post;
        if ($post->post_type != 'itsme_private_posts')
            return;
        $post->post_password = '';
        $visibility = 'private';
        $visibility_trans = __('Private');
        ?>
        <script type="text/javascript">
            (function($){
                try {
                    $('#post-visibility-display').text('<?php echo $visibility_trans; ?>');
                    $('#hidden-post-visibility').val('<?php echo $visibility; ?>');
                    $('#visibility-radio-<?php echo $visibility; ?>').attr('checked', true);
                } catch(err){}
            }) (jQuery);
        </script>
        <?php
    }
    

    Source: How to set new posts visibility to private by default?
    Note: I shortened the code to fit the needs here.

  2. This is the most “standard” way that I have found so far to set posts visibility to private by default:

    function wp_118970_force_type_private($post) {
      if ($post['post_status'] != 'trash' && $post['post_status'] != "draft" && $post['post_status'] != "auto-draft") {
        $post['post_status'] = 'private';
      }
      return $post;
    }
    add_filter('wp_insert_post_data', 'wp_118970_force_type_private');
    

    Note that you have to ensure that post_status is not “trash” otherwise you wouldn’t be able to delete your post.
    We also check for “draft” and “auto-draft” status to avoid setting posts as “private” while redacting them.

    With this, there is no need to add some JS, the visibility will be set to private from the beginning.

    If you want to target a specific post type, you can do it this way:

    function wp_118970_force_type_private($post) {
      if ($post['post_status'] != 'trash' && $post['post_status'] != "draft" && $post['post_status'] != "auto-draft" && $post['post_type'] == 'my_post_type') {
        $post['post_status'] = 'private';
      }
      return $post;
    }
    add_filter('wp_insert_post_data', 'wp_118970_force_type_private');
    

    I first found the solution here: http://wpsnipp.com/index.php/functions-php/force-custom-post-type-to-be-private/

  3. Based on the answer above, here’s what I came to, with the client (javascript) part:

    add_action( 'post_submitbox_misc_actions' , 'ourcpt_change_visibility_metabox' );
    function ourcpt_change_visibility_metabox() {
      global $post;
      if ( 'ourcpt' != $post->post_type ) { return; }
      //else          
      $post->post_password = '';
      ?>
      <script type="text/javascript">
          (function($){
              try {
                  $( "<div class='misc-pub-section'><em>(when it's published, the status becomes private)</em></div>" ).insertAfter( $('#post-visibility-select') );
                  $('a.edit-visibility').css({'display': 'none'});
              } catch(err){}
          }) (jQuery);
      </script>
      <?php
    }
    

    Because I love seeing what exactly is going on with the status. The code for add_filter( 'wp_insert_post_data' I used unchanged.

    Thank you very much for your solutions!

Comments are closed.