Custom Post Type to Plugin

i agree with the other answers, but neither addressed flushing the re-write rules. If you don’t add this, it will confuse your users when they activate the plugin and still can’t access the custom postypes on the front.

The other problem you’re going to have is that LOTS of people will use testimonials so if your clients load a plugin that uses testimonials and is using the same postype or if they were previously using another plugin that had a CPT testimonials, there will be conflicts.

It is better if you prefix your identifier with a short namespace that identifies your plugin, theme or website that implements the custom post type (instead of testimonials, say “haroon_testimonials” to ensure no one else will be using your post type in their systems.

Then to address post links on the front (so they see www.example.com/testimoinals/1 instead of www.example.com/haroon-testimonials/1
you’ll need to use a re-write back to testimonials:

    'rewrite' => array('slug' => 'locations'),

Here is a sample code i use:

<?php
/**
 * @package rt_create_cpt
 * @version 1.0
 */
/*
Plugin Name: Custom Post Creation by RT
Description: A Plugin to create CPT 
Author: RT, Inc
Version: 3.4
Author URI: http://
*/

add_action( 'init', 'rt_custom_post' );
function rt_custom_post() {
  register_post_type( 'rt_locations',
    array(
    'labels' => array(
        'name' => __( 'Locations' ),
        'singular_name' => __( 'Location' ),
        'add_new' => _x('Add New Location', 'Location'),
        'add_new_item' => __("Add New Location"),
        'edit_item' => __("Edit This Location"),
        'new_item' => __("New Location"),
        'view_item' => __("View Location"),
        'search_items' => __("Search in Locations"),
        'uploaded_to_this_item' => __("Used for image for this Location"),
        'featured_image' => __("Location Image"),
        'set_featured_image' => __("Set Location Image"),
        'remove_featured_image' => __("Remove Location Image"),
        'use_featured_image' => __("Use Location Image"),
        'not_found' =>  __('No Locations'),
        'not_found_in_trash' => __('No Locations found in Trash')

      ),
    'public' => true,
    'has_archive' => true,
       'menu_icon'   => 'dashicons-store',
    'supports' => array('title','author','thumbnail','editor'),
    'rewrite' => array('slug' => 'locations'),
    )
  );
}


function rt_rewrite_flush() {
    // First, we "add" the custom post type via the above written function.
    // Note: "add" is written with quotes, as CPTs don't get added to the DB,
    // They are only referenced in the post_type column with a post entry, 
    // when you add a post of this CPT.
    rt_custom_post();

    // ATTENTION: This is *only* done during plugin activation hook in this example!
    // You should *NEVER EVER* do this on every page load!!
    flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'rt_rewrite_flush' );

?>

you’ll just want to put your code function in and then change the rewrite rule to match your code!