Categories
WordPress

Creating A Portfolio Website in WordPress Using Custom Post Types

Presentation begins today at 3 PM PT

Download sample plugins referenced during the presentation.

<?php
/**
 * Plugin Name: Portfolio Custom Post Type
 * Description: A custom post type for an additional portfolio blog
 * Author: Joseph Dickson
 * Author URI: https://joseph-dickson.com
 * Version: 1.0
 * License: GPL2
 */

// Prevent direct access to this file
if ( ! defined( 'ABSPATH' ) ) exit;

// defined( 'ABSPATH' ) or die( 'No script kiddies please!' );

/**
 * Create a custom post type  
 * https://codex.wordpress.org/Function_Reference/register_post_type#Arguments
 */
function jd_portfolio_custom_post_type() {

$labels = array(
	'name'			=> 'Portfolio',
	'singular_name'		=> 'Portfolio',
	'menu_name'		=> 'Portfolio',
	'name_admin_bar'	=> 'Portfolio',
	'add_new'		=> 'Add a Portfolio Post',
	'add_new_item' 		=> 'Portfolio Post',
	'new_item'		=> 'Portfolio Post',
	'edit_item'		=> 'Edit Portfolio Post',
	'view_item'		=> 'View Portfolio Post',
	'all_items'		=> 'All Portfolio Posts',
	'search_items' 		=> 'Search Portfolio Posts',
	'parent_item_colon'	=> 'Parent Portfolio Posts:',
	'not_found'		=> 'No Portfolio Posts found.',
	'not_found_in_trash' 	=> 'No Portfolio Posts found in Trash.',
);

$args = array(
	'labels'	     	=> $labels,
	'public'		=> true,
	'publicly_queryable'	=> true,
	'show_ui'		=> true,
	'show_in_menu'		=> true,
	'menu_icon'		=> 'dashicons-format-gallery',
	'query_var'		=> true,
	'rewrite'		=> array( 'slug' => 'portfolio' ),
	'capability_type'	=> 'post',
	'has_archive'		=> true,
	'hierarchical'		=> false,
	'menu_position'		=> 21,
	'show_in_rest'		=> true,
	'supports'		=> array( 'title', 'editor', 'thumbnail' ),
);

register_post_type( 'portfolio', $args );
}

add_action( 'init', 'jd_portfolio_custom_post_type' );

// Flush rewrite rules when plugin is activated
function jd_portfolio_rewrite_flush() {
	jd_portfolio_custom_post_type();
	flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'jd_rewrite_flush' );
<?php
/**
 * Plugin Name: Services Custom Post Type
 * Description: A custom post type Services Pages 
 * Version: 1.0
 * License: GPL2
 */

// Prevent direct access to this file
if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * Create a custom post type  
 * https://codex.wordpress.org/Function_Reference/register_post_type#Arguments
 */
function jd_services_custom_post_type() {

$labels = array(
	'name'			=> 'Services',
	'singular_name'		=> 'Services',
	'menu_name'		=> 'Services',
	'name_admin_bar'	=> 'Services',
	'add_new'		=> 'Add a Services Page',
	'add_new_item'		=> 'Services Page',
	'new_item'		=> 'Services Page',
	'edit_item'		=> 'Edit Services Page',
	'view_item'		=> 'View Services Page',
	'all_items'		=> 'All Services Pages',
	'search_items'		=> 'Search Services Pages',
	'parent_item_colon'	=> 'Parent Services Pages:',
	'not_found'		=> 'No Services Pages found.',
	'not_found_in_trash'	=> 'No Services Pages found in Trash.',
);

$args = array(
	'labels'		=> $labels,
	'public'		=> true,
	'publicly_queryable'	=> true,
	'show_ui'		=> true,
	'show_in_menu'		=> true,
	'menu_icon'		=> 'dashicons-media-document',
	'query_var'		=> true,
	'rewrite'		=> array( 'slug' => 'services' ),
	'capability_type'	=> 'page',
	'has_archive'		=> false,
	'hierarchical'		=> true,
	'menu_position'		=> 22,
	'show_in_rest'		=> true,
	'supports'		=> array( 'title', 'editor', 'thumbnail' ),
);

register_post_type( 'services', $args );
}

add_action( 'init', 'jd_services_custom_post_type' );

// Flush rewrite rules when plugin is activated
function jd_services_rewrite_flush() {
	jd_services_custom_post_type();
	flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'jd_rewrite_flush' );
Categories
Tutorial WordPress

Creating Custom Block Patterns For WordPress

Block Patterns

The WordPress block editor includes Block Patterns which allow designers and developers to copy a block group and build it into a Plugin, Theme or Child Theme then quickly add and re-configure it in a post.

Effectively copy and paste the entire group into an editor

Joseph Dickson

Call to Action Block

		register_block_pattern(
			'josephd-patterns/call-to-action-tiles',
			array(
				'title'       => __( 'Call to Action Tiles', 'textdomain' ),
				'categories'  => array( 'josephd-patterns' ), // use the category slug
				'description' => _x( 'A column row of images and buttons.', 'A column row using images and buttons', 'textdomain' ),
				'content'     => implode(
					'', array(
						'<!-- wp:columns -->',
						'<div class="wp-block-columns"><!-- wp:column -->',
						'<div class="wp-block-column"><!-- wp:group -->',
						'<div class="wp-block-group"><div class="wp-block-group__inner-container"><!-- wp:image  -->',
						'<figure class="wp-block-image"><img src="' . $dir  . '" alt="camera icon" /></figure>',
						'<!-- /wp:image -->',

						'<!-- wp:buttons -->',
						'<div class="wp-block-buttons"><!-- wp:button {"borderRadius":0,"width":100} -->',
						'<div class="wp-block-button has-custom-width wp-block-button__width-100"><a class="wp-block-button__link no-border-radius">Button Text</a></div>',
						'<!-- /wp:button --></div>',
						'<!-- /wp:buttons --></div></div>',
						'<!-- /wp:group --></div>',
						'<!-- /wp:column -->',

						'<!-- wp:column -->',
						'<div class="wp-block-column"><!-- wp:image -->',
						'<figure class="wp-block-image"><img src="' . $dir  . '" alt="camera icon" /></figure>',
						'<!-- /wp:image -->',

						'<!-- wp:buttons -->',
						'<div class="wp-block-buttons"><!-- wp:button {"borderRadius":0,"width":100} -->',
						'<div class="wp-block-button has-custom-width wp-block-button__width-100"><a class="wp-block-button__link no-border-radius">Button Text</a></div>',
						'<!-- /wp:button --></div>',
						'<!-- /wp:buttons --></div>',
						'<!-- /wp:column -->',

						'<!-- wp:column -->',
						'<div class="wp-block-column"><!-- wp:image -->',
						'<figure class="wp-block-image"><img src="' . $dir  . '" alt="camera icon" /></figure>',
						'<!-- /wp:image -->',

						'<!-- wp:buttons -->',
						'<div class="wp-block-buttons"><!-- wp:button {"borderRadius":0,"width":100} -->',
						'<div class="wp-block-button has-custom-width wp-block-button__width-100"><a class="wp-block-button__link no-border-radius">Button Text</a></div>',
						'<!-- /wp:button --></div>',
						'<!-- /wp:buttons --></div>',
						'<!-- /wp:column --></div>',
						'<!-- /wp:columns -->',
					)
				),

			)
		);

YouTube Embed Block

register_block_pattern(
			'josephd-patterns/youtube-video-embed',
			array(
				'title'       => __( 'YouTube Video', 'textdomain' ),
				'categories'  => array( 'josephd-patterns' ), // use the category slug
				'description' => _x( 'A video and supporting text', 'A YouTube embed, text and, buttons', 'textdomain' ),
				'content'     => implode(
					'', array(					
						'<!-- wp:cover {"url":"' . $dir . '","dimRatio":50,"focalPoint":{"x":"0.50","y":"1.00"},"contentPosition":"center center","align":"full","className":"is-style-default"} -->',
						'<div class="wp-block-cover alignfull has-background-dim-50 has-background-dim is-style-default"><img class="wp-block-cover__image-background" alt="" src="' . $dir . '" style="object-position:50% 100%" data-object-fit="cover" data-object-position="50% 100%"/><div class="wp-block-cover__inner-container"><!-- wp:columns {"align":"full"} -->',
						'<div class="wp-block-columns alignfull"><!-- wp:column -->',
						'<div class="wp-block-column"><!-- wp:embed {"url":"https://www.youtube.com/watch?v=JL7DJay1xtA","type":"video","providerNameSlug":"youtube","responsive":true,"className":"wp-embed-aspect-16-9 wp-has-aspect-ratio"} -->',
						'<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">',
						'https://www.youtube.com/watch?v=JL7DJay1xtA',
						'</div></figure>',
						'<!-- /wp:embed --></div>',
						'<!-- /wp:column -->',

						'<!-- wp:column -->',
						'<div class="wp-block-column"><!-- wp:heading -->',
						'<h2>Lorem Ipsum</h2>',
						'<!-- /wp:heading -->',

						'<!-- wp:paragraph -->',
						'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras auctor id odio ut feugiat. In vitae metus libero. Curabitur nulla mi, ultrices ut maximus non, pellentesque non erat. Nam accumsan sapien sodales augue tempus iaculis. Etiam interdum vestibulum eleifend. Ut ornare dignissim lacus sit amet placerat. Mauris et diam pulvinar orci consectetur malesuada non nec libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
						'<!-- /wp:paragraph -->',

						'<!-- wp:buttons {"contentJustification":"center"} -->',
						'<div class="wp-block-buttons is-content-justification-center"><!-- wp:button {"backgroundColor":"black","textColor":"white"} -->',
						'<div class="wp-block-button"><a class="wp-block-button__link has-white-color has-black-background-color has-text-color has-background">Call to Action</a></div>',
						'<!-- /wp:button -->',

						'<!-- wp:button {"textColor":"white","className":"is-style-outline"} -->',
						'<div class="wp-block-button is-style-outline"><a class="wp-block-button__link has-white-color has-text-color">Supporting Action</a></div>',
						'<!-- /wp:button --></div>',
						'<!-- /wp:buttons --></div>',
						'<!-- /wp:column --></div>',
						'<!-- /wp:columns --></div></div>',
						'<!-- /wp:cover -->',
						
					)
				),

			)
		);

Image & Quote

register_block_pattern(
			'josephd-patterns/image-quote',
			array(
				'title'       => __( 'Image & Quote', 'textdomain' ),
				'categories'  => array( 'josephd-patterns' ), // use the category slug
				'description' => _x( 'An image and quote', 'A portrait alongside the quote', 'textdomain' ),
				'content'     => implode(
						'', array(					
						'<!-- wp:columns -->',
						'<div class="wp-block-columns"><!-- wp:column {"width":"33.33%"} -->',
						'<div class="wp-block-column" style="flex-basis:33.33%"><!-- wp:image {"large","linkDestination":"none"} -->',
						'<figure class="wp-block-image"><img src="' . $dir  . '" alt="camera icon" /></figure>',
						'<!-- /wp:image --></div>',
						'<!-- /wp:column -->',

						'<!-- wp:column {"width":"66.66%"} -->',
						'<div class="wp-block-column" style="flex-basis:66.66%"><!-- wp:quote {"className":"is-style-large"} -->',
						'<blockquote class="wp-block-quote is-style-large"><p>Inspiring Quote"</p><cite>Citation </cite></blockquote>',
						'<!-- /wp:quote --></div>',
						'<!-- /wp:column --></div>',
						'<!-- /wp:columns -->',
					)
				),

			)
		);

Articles Referenced In The Video

Categories
Tutorial WordPressvideo

Creating smaller buttons for Gutenberg

Often I find WordPress’ default button blocks are too large for some situations. Fortunately, extending Gutenberg blocks isn’t too difficult. Following the Gutenberg Handbook I’ve created short video and code samples to create addtional smaller button options without relying on a plugin.

Categories
Tutorial WordPress

Using is_multisite to loop in a post from another blog

Multisite is a powerful feature that allows us to manage multiple blogs within a single WordPress installation. In this post I briefly describe how to post content from the main site to a sub-site.

// Check if WordPress is using multisite
if ( is_multisite() ) {

global $switched;

// Switch to another blog by ID number 1 for the first site
switch_to_blog( 1 );

// Get a WP_Query that loops in a post from the main site
get_template_part('template-parts/notice-wp-query');

// Switch back to current blog
restore_current_blog();

}

We can use any method you like to query a post from the main site. In this example I’m using WP_Query and Advanced Custom Fields to display a post using the notice category.

<?php
$current_post_ID = get_the_ID(); // the post's id is assigned to $current_post_ID


$args = array(
	'post_type'		=> 'post',
	'orderby'		=> 'date',
	'order'			=> 'DESC',
	'category_name'		=> 'notice',
);

// the query
$the_query = new WP_Query( $args );
?>

<?php if ( $the_query->have_posts() ) : ?>

	<!-- pagination here -->
<div id="notice" class="row">
	<div class="small-12 columns">
	<!-- the loop -->
	<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?> 
		<article>
		<div class="notice">
		<?php
			if ( function_exists( 'get_field' ) ) {  

				echo '<a href="' . get_field( 'redirect_to_url' ) . '">'; 
					echo '<h1 class="entry-title"><span class="dashicons dashicons-warning"></span>' . get_the_title() .'</h1>';
					echo '<div class="notice-content">';
						echo the_content();
					echo '</div>';
				echo '</a>';
			} else {
				echo '<a href="' . get_permalink() . '">'; 
					echo '<h1 class="entry-title"><span class="dashicons dashicons-warning"></span>' . get_the_title() .'</h1>';
					echo '<div class="notice-content">';
						echo the_content();
					echo '</div>';
				echo '</a>';
			}

		?>
		</div>
		</article>

	<?php endwhile; ?>
	<!-- end of the loop -->
	</div>
</div>
	<!-- pagination here -->
<?php endif; ?>

<?php wp_reset_postdata();

Allowing the site to post a custom message that links to another page for additional information. When the post isn’t available the blue box below will simply not appear on the page. I built this feature a long time ago but didn’t really have a practical use of until March when the pandemic required notification banners above everything on my 100+ site multisite.

Categories
Tutorial WordPress

Disable Lazy Loading Images Using the_post_thumbnail() in WordPress

The introduction of lazy-loading of images as of WordPress 5.5 improves site performance by delaying them until the user scrolls into view making our pages feel faster by only loading images as we need to see them.

The Problem

However, I needed a way to disable lazy loading for specific features like this image carousel where the last few slides would not load as they rotated into view. 🙁

Image not loading on reveal in a carousel
A blank space where an image should appear. Lazy Loading somehow prevented the image from displaying on first pass while using Foundation 6’s Orbit Carousel.

The Solution

Disable lazy loading of the carousel images using this template part.

the_post_thumbnail( 'carousel', [ 'class' => 'orbit-image' , 'loading' => false ] );

The code above is inspired by modifying the attr argument using an array.

Adding ‘loading’ => false to the array disables the feature for this homepage image carousel.

The Orbit carousel now loads all images at page load.

Before and After

loading=”lazy” appears within the image HTML tag.
loading=”lazy” no longer displays with the image.

Disabling lazy loading for a specific use of the_post_thumbnail() allows us to benefit from the feature everywhere else. 😀