Last active
March 13, 2024 12:57
-
-
Save mor10/23a4ca617e39ed82520de1420a9c85dc to your computer and use it in GitHub Desktop.
Extend WP Rig to display related posts using the REST API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Template part for displaying a post | |
* | |
* @package wp_rig | |
* | |
* To be placed in template-parts/content/entry.php | |
*/ | |
namespace WP_Rig\WP_Rig; | |
?> | |
<article id="post-<?php the_ID(); ?>" <?php post_class( 'entry' ); ?>> | |
<?php | |
get_template_part( 'template-parts/content/entry_header', get_post_type() ); | |
if ( is_search() ) { | |
get_template_part( 'template-parts/content/entry_summary', get_post_type() ); | |
} else { | |
get_template_part( 'template-parts/content/entry_content', get_post_type() ); | |
} | |
get_template_part( 'template-parts/content/entry_footer', get_post_type() ); | |
?> | |
</article><!-- #post-<?php the_ID(); ?> --> | |
<?php | |
if ( is_single() ) { | |
get_template_part( 'template-parts/content/entry_related' ); | |
} | |
if ( is_singular( get_post_type() ) ) { | |
// Show post navigation only when the post type is 'post' or has an archive. | |
if ( 'post' === get_post_type() || get_post_type_object( get_post_type() )->has_archive ) { | |
the_post_navigation( | |
array( | |
'prev_text' => '<div class="post-navigation-sub"><span>' . esc_html__( 'Previous:', 'wp-rig' ) . '</span></div>%title', | |
'next_text' => '<div class="post-navigation-sub"><span>' . esc_html__( 'Next:', 'wp-rig' ) . '</span></div>%title', | |
) | |
); | |
} | |
// Show comments only when the post type supports it and when comments are open or at least one comment exists. | |
if ( post_type_supports( get_post_type(), 'comments' ) && ( comments_open() || get_comments_number() ) ) { | |
comments_template(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* WP_Rig\WP_Rig\Styles\Component class | |
* | |
* @package wp_rig | |
* | |
* To be placed in inc/Styles/Component.php | |
*/ | |
namespace WP_Rig\WP_Rig\Styles; | |
use WP_Rig\WP_Rig\Component_Interface; | |
use WP_Rig\WP_Rig\Templating_Component_Interface; | |
use function WP_Rig\WP_Rig\wp_rig; | |
use function add_action; | |
use function add_filter; | |
use function wp_enqueue_style; | |
use function wp_register_style; | |
use function wp_style_add_data; | |
use function get_theme_file_uri; | |
use function get_theme_file_path; | |
use function wp_styles; | |
use function esc_attr; | |
use function esc_url; | |
use function wp_style_is; | |
use function _doing_it_wrong; | |
use function wp_print_styles; | |
use function post_password_required; | |
use function is_singular; | |
use function comments_open; | |
use function get_comments_number; | |
use function apply_filters; | |
use function add_query_arg; | |
/** | |
* Class for managing stylesheets. | |
* | |
* Exposes template tags: | |
* * `wp_rig()->print_styles()` | |
*/ | |
class Component implements Component_Interface, Templating_Component_Interface { | |
/** | |
* Associative array of CSS files, as $handle => $data pairs. | |
* $data must be an array with keys 'file' (file path relative to 'assets/css' directory), and optionally 'global' | |
* (whether the file should immediately be enqueued instead of just being registered) and 'preload_callback' | |
* (callback function determining whether the file should be preloaded for the current request). | |
* | |
* Do not access this property directly, instead use the `get_css_files()` method. | |
* | |
* @var array | |
*/ | |
protected $css_files; | |
/** | |
* Associative array of Google Fonts to load, as $font_name => $font_variants pairs. | |
* | |
* Do not access this property directly, instead use the `get_google_fonts()` method. | |
* | |
* @var array | |
*/ | |
protected $google_fonts; | |
/** | |
* Gets the unique identifier for the theme component. | |
* | |
* @return string Component slug. | |
*/ | |
public function get_slug() : string { | |
return 'styles'; | |
} | |
/** | |
* Adds the action and filter hooks to integrate with WordPress. | |
*/ | |
public function initialize() { | |
add_action( 'wp_enqueue_scripts', array( $this, 'action_enqueue_styles' ) ); | |
add_action( 'wp_head', array( $this, 'action_preload_styles' ) ); | |
add_action( 'after_setup_theme', array( $this, 'action_add_editor_styles' ) ); | |
add_filter( 'wp_resource_hints', array( $this, 'filter_resource_hints' ), 10, 2 ); | |
} | |
/** | |
* Gets template tags to expose as methods on the Template_Tags class instance, accessible through `wp_rig()`. | |
* | |
* @return array Associative array of $method_name => $callback_info pairs. Each $callback_info must either be | |
* a callable or an array with key 'callable'. This approach is used to reserve the possibility of | |
* adding support for further arguments in the future. | |
*/ | |
public function template_tags() : array { | |
return array( | |
'print_styles' => array( $this, 'print_styles' ), | |
); | |
} | |
/** | |
* Registers or enqueues stylesheets. | |
* | |
* Stylesheets that are global are enqueued. All other stylesheets are only registered, to be enqueued later. | |
*/ | |
public function action_enqueue_styles() { | |
// Enqueue Google Fonts. | |
$google_fonts_url = $this->get_google_fonts_url(); | |
if ( ! empty( $google_fonts_url ) ) { | |
wp_enqueue_style( 'wp-rig-fonts', $google_fonts_url, array(), null ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion | |
} | |
$css_uri = get_theme_file_uri( '/assets/css/' ); | |
$css_dir = get_theme_file_path( '/assets/css/' ); | |
$preloading_styles_enabled = $this->preloading_styles_enabled(); | |
$css_files = $this->get_css_files(); | |
foreach ( $css_files as $handle => $data ) { | |
$src = $css_uri . $data['file']; | |
$version = wp_rig()->get_asset_version( $css_dir . $data['file'] ); | |
/* | |
* Enqueue global stylesheets immediately and register the other ones for later use | |
* (unless preloading stylesheets is disabled, in which case stylesheets should be immediately | |
* enqueued based on whether they are necessary for the page content). | |
*/ | |
if ( $data['global'] || ! $preloading_styles_enabled && is_callable( $data['preload_callback'] ) && call_user_func( $data['preload_callback'] ) ) { | |
wp_enqueue_style( $handle, $src, array(), $version, $data['media'] ); | |
} else { | |
wp_register_style( $handle, $src, array(), $version, $data['media'] ); | |
} | |
wp_style_add_data( $handle, 'precache', true ); | |
} | |
} | |
/** | |
* Preloads in-body stylesheets depending on what templates are being used. | |
* | |
* Only stylesheets that have a 'preload_callback' provided will be considered. If that callback evaluates to true | |
* for the current request, the stylesheet will be preloaded. | |
* | |
* Preloading is disabled when AMP is active, as AMP injects the stylesheets inline. | |
* | |
* @link https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content | |
*/ | |
public function action_preload_styles() { | |
// If preloading styles is disabled, return early. | |
if ( ! $this->preloading_styles_enabled() ) { | |
return; | |
} | |
$wp_styles = wp_styles(); | |
$css_files = $this->get_css_files(); | |
foreach ( $css_files as $handle => $data ) { | |
// Skip if stylesheet not registered. | |
if ( ! isset( $wp_styles->registered[ $handle ] ) ) { | |
continue; | |
} | |
// Skip if no preload callback provided. | |
if ( ! is_callable( $data['preload_callback'] ) ) { | |
continue; | |
} | |
// Skip if preloading is not necessary for this request. | |
if ( ! call_user_func( $data['preload_callback'] ) ) { | |
continue; | |
} | |
$preload_uri = $wp_styles->registered[ $handle ]->src . '?ver=' . $wp_styles->registered[ $handle ]->ver; | |
echo '<link rel="preload" id="' . esc_attr( $handle ) . '-preload" href="' . esc_url( $preload_uri ) . '" as="style">'; | |
echo "\n"; | |
} | |
} | |
/** | |
* Enqueues WordPress theme styles for the editor. | |
*/ | |
public function action_add_editor_styles() { | |
// Enqueue Google Fonts. | |
$google_fonts_url = $this->get_google_fonts_url(); | |
if ( ! empty( $google_fonts_url ) ) { | |
add_editor_style( $this->get_google_fonts_url() ); | |
} | |
// Enqueue block editor stylesheet. | |
add_editor_style( 'assets/css/editor/editor-styles.min.css' ); | |
} | |
/** | |
* Adds preconnect resource hint for Google Fonts. | |
* | |
* @param array $urls URLs to print for resource hints. | |
* @param string $relation_type The relation type the URLs are printed. | |
* @return array URLs to print for resource hints. | |
*/ | |
public function filter_resource_hints( array $urls, string $relation_type ) : array { | |
if ( 'preconnect' === $relation_type && wp_style_is( 'wp-rig-fonts', 'queue' ) ) { | |
$urls[] = array( | |
'href' => 'https://fonts.gstatic.com', | |
'crossorigin', | |
); | |
} | |
return $urls; | |
} | |
/** | |
* Prints stylesheet link tags directly. | |
* | |
* This should be used for stylesheets that aren't global and thus should only be loaded if the HTML markup | |
* they are responsible for is actually present. Template parts should use this method when the related markup | |
* requires a specific stylesheet to be loaded. If preloading stylesheets is disabled, this method will not do | |
* anything. | |
* | |
* If the `<link>` tag for a given stylesheet has already been printed, it will be skipped. | |
* | |
* @param string ...$handles One or more stylesheet handles. | |
*/ | |
public function print_styles( string ...$handles ) { | |
// If preloading styles is disabled (and thus they have already been enqueued), return early. | |
if ( ! $this->preloading_styles_enabled() ) { | |
return; | |
} | |
$css_files = $this->get_css_files(); | |
$handles = array_filter( | |
$handles, | |
function( $handle ) use ( $css_files ) { | |
$is_valid = isset( $css_files[ $handle ] ) && ! $css_files[ $handle ]['global']; | |
if ( ! $is_valid ) { | |
/* translators: %s: stylesheet handle */ | |
_doing_it_wrong( __CLASS__ . '::print_styles()', esc_html( sprintf( __( 'Invalid theme stylesheet handle: %s', 'wp-rig' ), $handle ) ), 'WP Rig 2.0.0' ); | |
} | |
return $is_valid; | |
} | |
); | |
if ( empty( $handles ) ) { | |
return; | |
} | |
wp_print_styles( $handles ); | |
} | |
/** | |
* Determines whether to preload stylesheets and inject their link tags directly within the page content. | |
* | |
* Using this technique generally improves performance, however may not be preferred under certain circumstances. | |
* For example, since AMP will include all style rules directly in the head, it must not be used in that context. | |
* By default, this method returns true unless the page is being served in AMP. The | |
* {@see 'wp_rig_preloading_styles_enabled'} filter can be used to tweak the return value. | |
* | |
* @return bool True if preloading stylesheets and injecting them is enabled, false otherwise. | |
*/ | |
protected function preloading_styles_enabled() { | |
$preloading_styles_enabled = ! wp_rig()->is_amp(); | |
/** | |
* Filters whether to preload stylesheets and inject their link tags within the page content. | |
* | |
* @param bool $preloading_styles_enabled Whether preloading stylesheets and injecting them is enabled. | |
*/ | |
return apply_filters( 'wp_rig_preloading_styles_enabled', $preloading_styles_enabled ); | |
} | |
/** | |
* Gets all CSS files. | |
* | |
* @return array Associative array of $handle => $data pairs. | |
*/ | |
protected function get_css_files() : array { | |
if ( is_array( $this->css_files ) ) { | |
return $this->css_files; | |
} | |
$css_files = array( | |
'wp-rig-global' => array( | |
'file' => 'global.min.css', | |
'global' => true, | |
), | |
'wp-rig-comments' => array( | |
'file' => 'comments.min.css', | |
'preload_callback' => function() { | |
return ! post_password_required() && is_singular() && ( comments_open() || get_comments_number() ); | |
}, | |
), | |
'wp-rig-content' => array( | |
'file' => 'content.min.css', | |
'preload_callback' => '__return_true', | |
), | |
'wp-rig-sidebar' => array( | |
'file' => 'sidebar.min.css', | |
'preload_callback' => function() { | |
return wp_rig()->is_primary_sidebar_active(); | |
}, | |
), | |
'wp-rig-widgets' => array( | |
'file' => 'widgets.min.css', | |
'preload_callback' => function() { | |
return wp_rig()->is_primary_sidebar_active(); | |
}, | |
), | |
'wp-rig-front-page' => array( | |
'file' => 'front-page.min.css', | |
'preload_callback' => function() { | |
global $template; | |
return 'front-page.php' === basename( $template ); | |
}, | |
), | |
'wp-rig-related' => array( | |
'file' => 'related.min.css', | |
'preload_callback' => '__return_false', | |
), | |
); | |
/** | |
* Filters default CSS files. | |
* | |
* @param array $css_files Associative array of CSS files, as $handle => $data pairs. | |
* $data must be an array with keys 'file' (file path relative to 'assets/css' | |
* directory), and optionally 'global' (whether the file should immediately be | |
* enqueued instead of just being registered) and 'preload_callback' (callback) | |
* function determining whether the file should be preloaded for the current request). | |
*/ | |
$css_files = apply_filters( 'wp_rig_css_files', $css_files ); | |
$this->css_files = array(); | |
foreach ( $css_files as $handle => $data ) { | |
if ( is_string( $data ) ) { | |
$data = array( 'file' => $data ); | |
} | |
if ( empty( $data['file'] ) ) { | |
continue; | |
} | |
$this->css_files[ $handle ] = array_merge( | |
array( | |
'global' => false, | |
'preload_callback' => null, | |
'media' => 'all', | |
), | |
$data | |
); | |
} | |
return $this->css_files; | |
} | |
/** | |
* Returns Google Fonts used in theme. | |
* | |
* @return array Associative array of $font_name => $font_variants pairs. | |
*/ | |
protected function get_google_fonts() : array { | |
if ( is_array( $this->google_fonts ) ) { | |
return $this->google_fonts; | |
} | |
$google_fonts = array( | |
'Roboto Condensed' => array( '400', '400i', '700', '700i' ), | |
'Crimson Text' => array( '400', '400i', '600', '600i' ), | |
); | |
/** | |
* Filters default Google Fonts. | |
* | |
* @param array $google_fonts Associative array of $font_name => $font_variants pairs. | |
*/ | |
$this->google_fonts = (array) apply_filters( 'wp_rig_google_fonts', $google_fonts ); | |
return $this->google_fonts; | |
} | |
/** | |
* Returns the Google Fonts URL to use for enqueuing Google Fonts CSS. | |
* | |
* Uses `latin` subset by default. To use other subsets, add a `subset` key to $query_args and the desired value. | |
* | |
* @return string Google Fonts URL, or empty string if no Google Fonts should be used. | |
*/ | |
protected function get_google_fonts_url() : string { | |
$google_fonts = $this->get_google_fonts(); | |
if ( empty( $google_fonts ) ) { | |
return ''; | |
} | |
$font_families = array(); | |
foreach ( $google_fonts as $font_name => $font_variants ) { | |
if ( ! empty( $font_variants ) ) { | |
if ( ! is_array( $font_variants ) ) { | |
$font_variants = explode( ',', str_replace( ' ', '', $font_variants ) ); | |
} | |
$font_families[] = $font_name . ':' . implode( ',', $font_variants ); | |
continue; | |
} | |
$font_families[] = $font_name; | |
} | |
$query_args = array( | |
'family' => implode( '|', $font_families ), | |
); | |
return add_query_arg( $query_args, 'https://fonts.googleapis.com/css' ); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* WP_Rig\WP_Rig\Theme class | |
* | |
* @package wp_rig | |
*/ | |
namespace WP_Rig\WP_Rig; | |
use InvalidArgumentException; | |
/** | |
* Main class for the theme. | |
* | |
* This class takes care of initializing theme features and available template tags. | |
*/ | |
class Theme { | |
/** | |
* Associative array of theme components, keyed by their slug. | |
* | |
* @var array | |
*/ | |
protected $components = []; | |
/** | |
* The template tags instance, providing access to all available template tags. | |
* | |
* @var Template_Tags | |
*/ | |
protected $template_tags; | |
/** | |
* Constructor. | |
* | |
* Sets the theme components. | |
* | |
* @param array $components Optional. List of theme components. Only intended for custom initialization, typically | |
* the theme components are declared by the theme itself. Each theme component must | |
* implement the Component_Interface interface. | |
* | |
* @throws InvalidArgumentException Thrown if one of the $components does not implement Component_Interface. | |
*/ | |
public function __construct( array $components = [] ) { | |
if ( empty( $components ) ) { | |
$components = $this->get_default_components(); | |
} | |
// Set the components. | |
foreach ( $components as $component ) { | |
// Bail if a component is invalid. | |
if ( ! $component instanceof Component_Interface ) { | |
throw new InvalidArgumentException( | |
sprintf( | |
/* translators: 1: classname/type of the variable, 2: interface name */ | |
__( 'The theme component %1$s does not implement the %2$s interface.', 'wp-rig' ), | |
gettype( $component ), | |
Component_Interface::class | |
) | |
); | |
} | |
$this->components[ $component->get_slug() ] = $component; | |
} | |
// Instantiate the template tags instance for all theme templating components. | |
$this->template_tags = new Template_Tags( | |
array_filter( | |
$this->components, | |
function( Component_Interface $component ) { | |
return $component instanceof Templating_Component_Interface; | |
} | |
) | |
); | |
} | |
/** | |
* Adds the action and filter hooks to integrate with WordPress. | |
* | |
* This method must only be called once in the request lifecycle. | |
*/ | |
public function initialize() { | |
array_walk( | |
$this->components, | |
function( Component_Interface $component ) { | |
$component->initialize(); | |
} | |
); | |
} | |
/** | |
* Retrieves the template tags instance, the entry point exposing template tag methods. | |
* | |
* Calling `wp_rig()` is a short-hand for calling this method on the main theme instance. The instance then allows | |
* for actual template tag methods to be called. For example, if there is a template tag called `posted_on`, it can | |
* be accessed via `wp_rig()->posted_on()`. | |
* | |
* @return Template_Tags Template tags instance. | |
*/ | |
public function template_tags() : Template_Tags { | |
return $this->template_tags; | |
} | |
/** | |
* Retrieves the component for a given slug. | |
* | |
* This should typically not be used from outside of the theme classes infrastructure. | |
* | |
* @param string $slug Slug identifying the component. | |
* @return Component_Interface Component for the slug. | |
* | |
* @throws InvalidArgumentException Thrown when no theme component with the given slug exists. | |
*/ | |
public function component( string $slug ) : Component_Interface { | |
if ( ! isset( $this->components[ $slug ] ) ) { | |
throw new InvalidArgumentException( | |
sprintf( | |
/* translators: %s: slug */ | |
__( 'No theme component with the slug %s exists.', 'wp-rig' ), | |
$slug | |
) | |
); | |
} | |
return $this->components[ $slug ]; | |
} | |
/** | |
* Gets the default theme components. | |
* | |
* This method is called if no components are passed to the constructor, which is the common scenario. | |
* | |
* @return array List of theme components to use by default. | |
*/ | |
protected function get_default_components() : array { | |
$components = [ | |
new Localization\Component(), | |
new Base_Support\Component(), | |
new Editor\Component(), | |
new Accessibility\Component(), | |
new Image_Sizes\Component(), | |
new Lazyload\Component(), | |
new AMP\Component(), | |
new PWA\Component(), | |
new Comments\Component(), | |
new Nav_Menus\Component(), | |
new Sidebars\Component(), | |
new Custom_Background\Component(), | |
new Custom_Header\Component(), | |
new Custom_Logo\Component(), | |
new Post_Thumbnails\Component(), | |
new Customizer\Component(), | |
new Styles\Component(), | |
new Related_Posts\Component(), | |
]; | |
if ( defined( 'JETPACK__VERSION' ) ) { | |
$components[] = new Jetpack\Component(); | |
} | |
return $components; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment