# Intro Text for Custom Post Type Archives

> Adds an "Archive intros" section to Settings > Reading where you can write an introduction for each custom post type archive, such as Portfolio or Recipes, shown at the top of that archive.

- Type: PHP
- Runs: Run everywhere
- Category: [Archives](https://wpide.com/library/category/archive/)
- Tags: archives, post-types, descriptions
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/post-type-archive-intro-text/

## Code

```php
// Adds an "Archive intros" section to Settings > Reading with a text box for every custom post type that has an archive.
$wpide_archive_intro_types = function () {
    return array_filter( get_post_types( array( 'public' => true, '_builtin' => false ), 'objects' ), function ( $type ) {
        return ! empty( $type->has_archive );
    } );
};

add_action( 'admin_init', function () use ( $wpide_archive_intro_types ) {
    $types = $wpide_archive_intro_types();

    if ( ! $types ) {
        return;
    }

    register_setting( 'reading', 'wpide_archive_intros', array(
        'type'              => 'array',
        'default'           => array(),
        'sanitize_callback' => function ( $value ) {
            $clean = array();

            foreach ( (array) $value as $type => $html ) {
                if ( post_type_exists( $type ) && '' !== trim( (string) $html ) ) {
                    $clean[ sanitize_key( $type ) ] = wp_kses_post( $html );
                }
            }

            return $clean;
        },
    ) );

    add_settings_section( 'wpide_archive_intros', 'Archive intros', function () {
        echo '<p>Text shown at the top of each content type\'s archive page. Basic HTML is allowed.</p>';
    }, 'reading' );

    $saved = (array) get_option( 'wpide_archive_intros', array() );

    foreach ( $types as $type ) {
        add_settings_field( 'wpide_archive_intro_' . $type->name, esc_html( $type->labels->name ), function () use ( $type, $saved ) {
            printf(
                '<textarea name="wpide_archive_intros[%1$s]" id="wpide_archive_intro_%1$s" rows="4" class="large-text">%2$s</textarea><p class="description"><a href="%3$s">%3$s</a></p>',
                esc_attr( $type->name ),
                esc_textarea( isset( $saved[ $type->name ] ) ? $saved[ $type->name ] : '' ),
                esc_url( get_post_type_archive_link( $type->name ) )
            );
        }, 'reading', 'wpide_archive_intros', array( 'label_for' => 'wpide_archive_intro_' . $type->name ) );
    }
} );

// The saved intro for the post type archive being viewed (first page only).
$wpide_archive_intro_text = function () {
    if ( ! is_post_type_archive() || is_paged() ) {
        return '';
    }

    $type   = get_query_var( 'post_type' );
    $type   = is_array( $type ) ? reset( $type ) : $type;
    $intros = (array) get_option( 'wpide_archive_intros', array() );

    return ! empty( $intros[ $type ] ) ? wpautop( wp_kses_post( $intros[ $type ] ) ) : '';
};

// Classic themes that print the archive description.
add_filter( 'get_the_archive_description', function ( $description ) use ( $wpide_archive_intro_text ) {
    $intro = $wpide_archive_intro_text();

    return '' !== $intro ? $intro : $description;
} );

// Block themes: after the archive title.
add_filter( 'render_block_core/query-title', function ( $content ) use ( $wpide_archive_intro_text ) {
    $intro = wp_is_block_theme() ? $wpide_archive_intro_text() : '';

    return '' !== $intro ? $content . '<div class="wpide-archive-intro">' . $intro . '</div>' : $content;
} );
```

## Notes

Only post types with an archive are listed. Classic themes need to show the archive description; block themes get it after the archive title.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Intro Text for Custom Post Type Archives" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
