Overview
Web Stories provides flexible archive page options, allowing you to use the default WordPress archive, disable archives entirely, or create a custom archive page.
Archive Configuration
The archive behavior is controlled through plugin settings:
public function get_has_archive () {
$archive_page_option = $this -> settings -> get_setting ( $this -> settings :: SETTING_NAME_ARCHIVE );
$has_archive = true ;
if ( 'disabled' === $archive_page_option ) {
$has_archive = false ;
} elseif ( 'custom' === $archive_page_option ) {
$custom_archive_page_id = ( int ) $this -> settings -> get_setting ( $this -> settings :: SETTING_NAME_ARCHIVE_PAGE_ID );
if ( $custom_archive_page_id && 'publish' === get_post_status ( $custom_archive_page_id ) ) {
$uri = get_page_uri ( $custom_archive_page_id );
if ( $uri ) {
$has_archive = urldecode ( $uri );
}
}
}
return $has_archive ;
}
Archive Options
There are three archive display modes:
Default Archive
Custom Archive
Disabled
Standard WordPress Archive Uses the built-in WordPress post type archive functionality. URL Structure: https://example.com/web-stories/
Template Hierarchy:
archive-web-story.php
archive.php
index.php
The default archive shows all published stories using your theme’s archive template. Custom WordPress Page Designate any WordPress page as your stories archive. Benefits:
Full page builder support
Custom layouts and content
Page-specific templates
Additional widgets and blocks
The custom page’s slug becomes the archive URL. No Archive Page Completely disables the archive functionality.
No /web-stories/ page
Archive links won’t display in widgets/blocks
Stories still accessible via direct URLs
Useful for curated-only story displays
Custom Archive Implementation
When a custom archive page is set, the plugin modifies the main query:
public function pre_get_posts ( WP_Query $query ) : void {
if ( ! \ is_string ( $this -> story_post_type -> get_has_archive () ) ) {
return ;
}
if ( $query -> is_admin || ! $query -> is_main_query () ) {
return ;
}
if ( ! $query -> is_post_type_archive ( $this -> story_post_type -> get_slug () ) ) {
return ;
}
$custom_archive_page_id = ( int ) $this -> settings -> get_setting ( $this -> settings :: SETTING_NAME_ARCHIVE_PAGE_ID );
$query -> set ( 'page_id' , $custom_archive_page_id );
$query -> set ( 'post_type' , 'page' );
$query -> is_post_type_archive = false ;
$query -> is_archive = false ;
$query -> is_singular = true ;
$query -> is_page = true ;
}
The query is transformed from a post type archive to a singular page query, allowing full page template support.
Archive Page Redirects
The plugin handles redirects for the default /web-stories/ URL:
public function redirect_post_type_archive_urls ( $bypass , WP_Query $query ) {
global $wp_rewrite ;
if ( $bypass || ! \ is_string ( $this -> story_post_type -> get_has_archive () ) || ( ! $wp_rewrite instanceof WP_Rewrite || ! $wp_rewrite -> using_permalinks () ) ) {
return $bypass ;
}
// 'pagename' is for most permalink types, 'name' is for when %postname% is used as top-level.
if ( $this -> story_post_type :: REWRITE_SLUG === $query -> get ( 'pagename' ) || $this -> story_post_type :: REWRITE_SLUG === $query -> get ( 'name' ) ) {
$redirect_url = get_post_type_archive_link ( $this -> story_post_type -> get_slug () );
if ( $redirect_url && wp_safe_redirect ( $redirect_url , 301 ) ) {
exit ;
}
}
return $bypass ;
}
Archive Page States
Custom archive pages show a special indicator in the WordPress admin:
public function filter_display_post_states ( $post_states , ? WP_Post $post ) {
if ( ! \ is_array ( $post_states ) || ! $post ) {
return $post_states ;
}
if ( ! \ is_string ( $this -> story_post_type -> get_has_archive () ) ) {
return $post_states ;
}
$custom_archive_page_id = ( int ) $this -> settings -> get_setting ( $this -> settings :: SETTING_NAME_ARCHIVE_PAGE_ID );
if ( $post -> ID === $custom_archive_page_id ) {
$post_states [ 'web_stories_archive_page' ] = __ ( 'Web Stories Archive Page' , 'web-stories' );
}
return $post_states ;
}
This adds a “Web Stories Archive Page” label in the pages list.
Archive Page Deletion
When a custom archive page is trashed or deleted, settings reset automatically:
public function on_remove_archive_page ( int $postid ) : void {
if ( 'page' !== get_post_type ( $postid ) ) {
return ;
}
$custom_archive_page_id = ( int ) $this -> settings -> get_setting ( $this -> settings :: SETTING_NAME_ARCHIVE_PAGE_ID );
if ( $custom_archive_page_id !== $postid ) {
return ;
}
$this -> settings -> update_setting ( $this -> settings :: SETTING_NAME_ARCHIVE , 'default' );
$this -> settings -> update_setting ( $this -> settings :: SETTING_NAME_ARCHIVE_PAGE_ID , 0 );
}
Rewrite Rules
Changing archive settings triggers a rewrite flush:
public function update_archive_setting () : void {
$this -> story_post_type -> unregister_post_type ();
$this -> story_post_type -> register_post_type ();
if ( ! \ defined ( '\WPCOM_IS_VIP_ENV' ) || false === \ WPCOM_IS_VIP_ENV ) {
flush_rewrite_rules ( false );
}
}
Rewrite rules are not flushed on VIP environments. Use the WP-CLI command wp rewrite flush instead.
Creating a Custom Archive Template
Create a custom archive template in your theme:
Create Template File
Create archive-web-story.php in your theme directory.
Add Template Header
<? php
/**
* Template Name: Web Stories Archive
* Description: Custom archive for Web Stories
*/
get_header ();
?>
Query Stories
< div class = "web-stories-archive" >
< h1 ><? php post_type_archive_title (); ?></ h1 >
<? php
$args = [
'post_type' => 'web-story' ,
'posts_per_page' => 12 ,
'paged' => get_query_var ( 'paged' ) ?: 1 ,
];
$stories_query = new WP_Query ( $args );
if ( $stories_query -> have_posts () ) :
while ( $stories_query -> have_posts () ) :
$stories_query -> the_post ();
// Display story
endwhile ;
// Pagination
the_posts_pagination ();
endif ;
wp_reset_postdata ();
?>
</ div >
Using Story_Query in Templates
Use the Story_Query class for advanced story displays:
Grid View
Carousel View
Filtered by Category
$story_attrs = [
'view_type' => 'grid' ,
'number_of_columns' => 3 ,
'show_title' => true ,
'show_author' => true ,
'show_date' => true ,
];
$story_args = [
'posts_per_page' => 12 ,
'orderby' => 'post_date' ,
'order' => 'DESC' ,
];
$story_query = new Google\Web_Stories\ Story_Query ( $story_attrs , $story_args );
echo $story_query -> render ();
Archive Link Display
Get the archive link programmatically:
$archive_url = get_post_type_archive_link ( 'web-story' );
if ( $archive_url ) {
echo '<a href="' . esc_url ( $archive_url ) . '">View All Stories</a>' ;
}
The function returns false if archives are disabled.
Implement pagination in custom archive templates:
the_posts_pagination ([
'mid_size' => 2 ,
'prev_text' => __ ( 'Previous Stories' , 'textdomain' ),
'next_text' => __ ( 'More Stories' , 'textdomain' ),
]);
Archive Page Hooks
The archive system uses WordPress hooks:
// Fires when archive setting is added
add_action ( 'add_option_web_stories_archive' , 'my_archive_callback' );
// Fires when archive setting is updated
add_action ( 'update_option_web_stories_archive' , 'my_archive_callback' );
// Fires when archive page ID is updated
add_action ( 'update_option_web_stories_archive_page_id' , 'my_archive_callback' );
// Modify archive query
add_filter ( 'pre_get_posts' , function ( $query ) {
if ( ! is_admin () && $query -> is_main_query () && $query -> is_post_type_archive ( 'web-story' ) ) {
$query -> set ( 'posts_per_page' , 20 );
}
});
// Handle 404 redirects
add_filter ( 'pre_handle_404' , 'my_404_handler' , 10 , 2 );
SEO Considerations
Customize the archive page title using SEO plugins or the document_title_parts filter: add_filter ( 'document_title_parts' , function ( $title ) {
if ( is_post_type_archive ( 'web-story' ) ) {
$title [ 'title' ] = 'Our Web Stories' ;
}
return $title ;
});
The plugin automatically adds structured data for stories. You can extend it for the archive page using the web_stories_schema filter.
Best Practices
Performance
Limit stories per page (12-20 recommended)
Use lazy loading for images
Enable caching for archive pages
Use no_found_rows when pagination isn’t needed
User Experience
Provide filtering/sorting options
Show clear pagination
Include search functionality
Display story metadata (author, date)
Content Strategy
Feature latest/popular stories
Organize by categories
Add featured story sections
Include related content
Mobile Design
Use responsive grid layouts
Optimize touch targets
Test swipe gestures
Ensure fast load times
Next Steps
WordPress Integration Learn about the custom post type
Gutenberg Blocks Embed stories with blocks