Custom Archive Pages
Under Settings > Reading, WordPress lets you assign a “Homepage” and a “Posts page” — but that’s the only two roles it knows about. If your theme needs its own assignable page (e.g. “which Page holds the intro content for the Portfolio archive?”, or “which Page should the header’s Contact CTA link to?”), there’s no built-in way to let editors pick one without hard-coding a page ID or slug somewhere.
This class recreates that same pattern — a dropdown of existing Pages, saved as an option, labelled in the admin Pages list — for as many roles as your theme needs.
-
Add the PHP Code
Section titled “Add the PHP Code”Create a new file named
CustomArchivePages.phpinside theinc/folder of your Blocksy child theme and add the following code.<?phpnamespace Best4u\BlocksyChild\Classes;if (!defined('ABSPATH')) {exit;}/*** Class CustomArchivePages** Registers custom page assignments under Settings > Reading and labels those* pages in the admin Pages list, just like WordPress does for the front page* and posts page.** To add a new page type, add an entry to the $pages array:** 'option_key' => __('Label', 'blocksy-child')** The option key is used as both the WP option name (prefixed with "theme_")* and as the state key in the Pages list. Retrieve the saved ID anywhere via:** CustomArchivePages::get_page_id('option_key')*/class CustomArchivePages{private const OPTION_PREFIX = 'theme_';/*** Registered page types. Key = option identifier, value = admin label.** @var array<string, string>*/private array $pages;public function __construct(){add_action('init', [$this, 'init']);add_action('admin_init', [$this, 'register_settings']);add_filter('display_post_states', [$this, 'add_page_states'], 10, 2);}/*** Initialises the pages list. Hooked to 'init' so translations are available.** @return void*/public function init(): void{$this->pages = ['contact_page' => __('Contact Page', 'blocksy-child'),'portfolio_page' => __('Portfolio Page', 'blocksy-child'),];}/*** Registers settings fields in the Reading settings section.** @return void*/public function register_settings(): void{foreach ($this->pages as $key => $label) {$option = self::OPTION_PREFIX . $key;register_setting('reading', $option, ['type' => 'integer','sanitize_callback' => 'absint',]);add_settings_field($option,$label,function () use ($option, $key) {wp_dropdown_pages(['name' => $option,'echo' => 1,'show_option_none' => __('— Select —', 'blocksy-child'),'option_none_value' => '0','selected' => self::get_page_id($key),]);},'reading');}}/*** Appends custom labels to pages in the admin Pages list.** @param array $post_states* @param \WP_Post $post* @return array*/public function add_page_states(array $post_states, \WP_Post $post): array{foreach ($this->pages as $key => $label) {if (self::get_page_id($key) === $post->ID) {$post_states[$key] = $label;}}return $post_states;}/*** Returns the saved page ID for a given option key, or 0 if not set.** @param string $key The option key (without prefix), e.g. 'contact_page'.* @return int*/public static function get_page_id(string $key): int{return (int) get_option(self::OPTION_PREFIX . $key, 0);}}new CustomArchivePages();Once saved, each entry in
$pagesgets its own “— Select —” page dropdown under Settings > Reading, and whichever page you assign there picks up a state label (e.g. “— Portfolio Page”) next to its title in Pages, exactly like WordPress’s own “— Front Page” label. -
Add a shortcut for fetching the ID
Section titled “Add a shortcut for fetching the ID”CustomArchivePages::get_page_id('portfolio_page')works anywhere, but the fully-qualified class name gets tedious in templates. Sinceinc/files are auto-included, a good place for this is a general-purposeinc/helpers.php— if your theme doesn’t have one yet for this kind of small, framework-agnostic helper function, this is a good reason to start one. Add the following so templates can callget_custom_page_id()directly:/*** Returns the saved page ID for a custom archive page, or null if not set.** @param string $key* @return int|null*/function get_custom_page_id(string $key): ?int{$id = \Best4u\BlocksyChild\Classes\CustomArchivePages::get_page_id($key);return $id > 0 ? $id : null;}Returning
nullinstead of0when nothing is assigned makes call sites read naturally, e.g.if ($id = get_custom_page_id('contact_page')) { ... }.
Customization
Section titled “Customization”To add a new assignable role, add an entry to the $pages array in init():
$this->pages = [ 'contact_page' => __('Contact Page', 'blocksy-child'), 'portfolio_page' => __('Portfolio Page', 'blocksy-child'), 'faq_page' => __('FAQ Page', 'blocksy-child'),];That’s it — the settings field, the Pages list label, and get_page_id()/get_custom_page_id() all pick up the new key automatically since they loop over the same array.