Table of Contents
This is an example-based tutorial where you will learn how to create a custom post type called Site, add a URL custom post meta field and generate a screenshot automatically based on that URL (using Automattic’s mShots API service).
The code below uses WordPress.com’s mShots API to generate screenshots on the fly. These images are not stored in your WordPress media library. They are served directly from WordPress.com servers.
As a bonus, we’ll create a shortcode to display everything in a nice loop, and add an option to show or hide the site.
Let’s create our website showcase section!
Custom Post Type
First, we create the Site custom post type:
<?php
function shirley_create_sites() {
$labels = [
'name' => _x('Sites', 'Post Type General Name', 'shirley'),
'singular_name' => _x('Site', 'Post Type Singular Name', 'shirley'),
'menu_name' => __('Sites', 'shirley'),
'name_admin_bar' => __('Site', 'shirley'),
'archives' => __('Site Archives', 'shirley'),
'attributes' => __('Site Attributes', 'shirley'),
'parent_item_colon' => __('Parent Site:', 'shirley'),
'all_items' => __('All Sites', 'shirley'),
'add_new_item' => __('Add New Site', 'shirley'),
'add_new' => __('Add New', 'shirley'),
'new_item' => __('New Site', 'shirley'),
'edit_item' => __('Edit Site', 'shirley'),
'update_item' => __('Update Site', 'shirley'),
'view_item' => __('View Site', 'shirley'),
'view_items' => __('View Sites', 'shirley'),
'search_items' => __('Search Site', 'shirley'),
'not_found' => __('Not found', 'shirley'),
'not_found_in_trash' => __('Not found in Trash', 'shirley'),
'featured_image' => __('Featured Image', 'shirley'),
'set_featured_image' => __('Set featured image', 'shirley'),
'remove_featured_image' => __('Remove featured image', 'shirley'),
'use_featured_image' => __('Use as featured image', 'shirley'),
'insert_into_item' => __('Insert into site', 'shirley'),
'uploaded_to_this_item' => __('Uploaded to this site', 'shirley'),
'items_list' => __('Sites list', 'shirley'),
'items_list_navigation' => __('Sites list navigation', 'shirley'),
'filter_items_list' => __('Filter sites list', 'shirley'),
];
$args = [
'label' => __('Site', 'shirley'),
'description' => __('Site Showcase', 'shirley'),
'labels' => $labels,
'supports' => ['title', 'thumbnail', 'editor', 'custom-fields'],
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-format-image',
'show_in_admin_bar' => false,
'show_in_nav_menus' => false,
'can_export' => true,
'has_archive' => false,
'exclude_from_search' => true,
'publicly_queryable' => false,
'rewrite' => false,
'capability_type' => 'post',
'show_in_rest' => true,
];
register_post_type( 'site', $args);
}
add_action('init', 'shirley_create_sites', 0);
Custom Post Meta
Next, we create the custom post meta field:
<?php
/**
* Add meta box
*
* @param post $post The post object
*/
function shirley_add_meta_boxes($post) {
add_meta_box('site_meta_box', 'Site Settings', 'shirley_build_meta_box', ['site'], 'normal', 'low');
}
/**
* Build custom field meta box
*
* @param post $post The post object
*/
function shirley_build_meta_box($post) {
wp_nonce_field(basename(__FILE__), 'site_meta_box_nonce');
$currentSiteUrl = get_post_meta($post->ID, '_site_url', true);
$currentSiteVisibility = get_post_meta($post->ID, '_site_visibility', true);
?>
<div class="inside">
<p>
<label for="site-url">Site URL</label>
<input type="text" name="site_url" id="site-url" class="regular-text" style="width: 100%;" value="<?php echo $currentSiteUrl; ?>">
</p>
<p>
<label for="site-visibility">Is the site visible in the <b>Showcase</b> section?</label>
<br>
<select name="site_visibility" id="site-visibility">
<option value="0" <?php echo ((int) $currentSiteVisibility === 0) ? 'selected' : ''; ?>>No</option>
<option value="1" <?php echo ((int) $currentSiteVisibility === 1) ? 'selected' : ''; ?>>Yes</option>
</select>
</p>
</div>
<?php
}
/**
* Store custom field meta box data
*
* @param int $post_id The post ID.
*/
function shirley_save_meta_box_data($post_id) {
if (!isset($_POST['site_meta_box_nonce']) || !wp_verify_nonce($_POST['site_meta_box_nonce'], basename(__FILE__))) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
$siteUrl = isset($_POST['site_url']) ? $_POST['site_url'] : '';
$siteVisibility = isset($_POST['site_visibility']) ? $_POST['site_visibility'] : '';
update_post_meta($post_id, '_site_url', $siteUrl);
update_post_meta($post_id, '_site_visibility', $siteVisibility);
}
add_action('add_meta_boxes', 'shirley_add_meta_boxes');
add_action('save_post', 'shirley_save_meta_box_data');
Showcase Shortcode
And last, we display the sites in a nice list:
<?php
function shirley_sites() {
$out = '<div class="projects">';
$args = [
'post_type' => 'site',
'posts_per_page' => -1,
'orderby' => 'menu_order'
];
$the_query = new WP_Query($args);
if ($the_query->have_posts()) {
while ($the_query->have_posts()) {
$the_query->the_post();
$siteId = get_the_ID();
$siteVisibility = get_post_meta($siteId, '_site_visibility', true);
/**
* mShots
*
* Example: https://s.wordpress.com/mshots/v1/https%3A%2F%2F4getbutterfly.com%2F?w=1366
*/
$siteUri = get_post_meta($siteId, '_site_url', true);
$siteUri = urlencode($siteUri);
$siteThumbnail = 'https://s.wordpress.com/mshots/v1/' . $siteUri . '?w=1280&h=960';
// Override automated post thumbnail with a featured image
if (has_post_thumbnail($siteId)) {
$siteThumbnail = get_the_post_thumbnail_url($siteId, 'full');
}
if ((int) $siteVisibility !== 0) {
$out .= '<div class="item" style="background: url(' . $siteThumbnail . ') no-repeat top center; background-size: cover;">
<div class="item-info">
<h2>' . get_the_title($siteId) . '</h2>
<span>
<small>' . get_post_meta($siteId, '_site_url', true) . '</small><br>
<a href="' . get_post_meta($siteId, '_site_url', true) . '" rel="external" target="_blank">Visit Site</a>
</span>
</div>
</div>';
}
}
}
$out .= '</div>';
return $out;
}
add_shortcode('sites', 'shirley_sites');
Shortcode Usage
Use the [sites]
shortcode to display your sites.
That’s it! Enjoy!
Note that there are no other screenshot options. You can’t change the image quality, image format, the IP address, geolocation, or anything else. Images will be cached for an unspecified period, so you’ll need to mangle the link if you want to regenerate it.
mShots is licensed under GNU General Public License v2.0.