Cloudflare APO: document the WordPress plugin cache invalidation logic

Hi folks,
I needed a deeper understanding of how the Cloudflare APO WordPress plugin decides what URLs to invalidate from the Cloudflare cache when we publish content changes. It’d be great if you could add a section on this to the docs.

I read through the plugin source code to figure it out. I was pleased to find a cloudflare_purge_by_url hook which makes adjusting the behavior straightforward.

At the time of writing, code for the key function I was hoping to find written up in the docs is below:

public function getPostRelatedLinks($postId) {

    $listofurls = array();
    $postType = get_post_type($postId);

    //Purge taxonomies terms and feeds URLs
    $postTypeTaxonomies = get_object_taxonomies($postType);

    foreach ($postTypeTaxonomies as $taxonomy) {
        $terms = get_the_terms($postId, $taxonomy);

        if (empty($terms) || is_wp_error($terms)) {
            continue;
        }

        foreach ($terms as $term) {
            $termLink = get_term_link($term);
            $termFeedLink = get_term_feed_link($term->term_id, $term->taxonomy);
            if (!is_wp_error($termLink) && !is_wp_error($termFeedLink)) {
                array_push($listofurls, $termLink);
                array_push($listofurls, $termFeedLink);
            }
        }
    }

    // Author URL
    array_push(
        $listofurls,
        get_author_posts_url(get_post_field('post_author', $postId)),
        get_author_feed_link(get_post_field('post_author', $postId))
    );

    // Archives and their feeds
    if (get_post_type_archive_link($postType) == true) {
        array_push(
            $listofurls,
            get_post_type_archive_link($postType),
            get_post_type_archive_feed_link($postType)
        );
    }

    // Post URL
    array_push($listofurls, get_permalink($postId));

    // Also clean URL for trashed post.
    if (get_post_status($postId) == 'trash') {
        $trashPost = get_permalink($postId);
        $trashPost = str_replace('__trashed', '', $trashPost);
        array_push($listofurls, $trashPost, $trashPost.'feed/');
    }

    // Feeds
    array_push(
        $listofurls,
        get_bloginfo_rss('rdf_url'),
        get_bloginfo_rss('rss_url'),
        get_bloginfo_rss('rss2_url'),
        get_bloginfo_rss('atom_url'),
        get_bloginfo_rss('comments_rss2_url'),
        get_post_comments_feed_link($postId)
    );

    // Home Page and (if used) posts page
    array_push($listofurls, home_url('/'));
    $pageLink = get_permalink(get_option('page_for_posts'));
    if (is_string($pageLink) && !empty($pageLink) && get_option('show_on_front') == 'page') {
        array_push($listofurls, $pageLink);
    }

    // Refresh pagination
    $total_posts_count = wp_count_posts()->publish;
    $posts_per_page = get_option('posts_per_page');
    // Limit to up to 3 pages
    $page_number_max = min(3, ceil($total_posts_count / $posts_per_page));

    $this->logger->debug("total_posts_count $total_posts_count");
    $this->logger->debug("posts_per_page  $posts_per_page");
    $this->logger->debug("page_number_max $page_number_max");

    foreach (range(1, $page_number_max) as $page_number) {
        array_push($listofurls, home_url(sprintf('/page/%s/', $page_number)));
    }

    // Attachments
    if ('attachment' == $postType) {
        $attachmentUrls = array();
        foreach (get_intermediate_image_sizes() as $size) {
            $attachmentSrc = wp_get_attachment_image_src($postId, $size);
            $attachmentUrls[] = $attachmentSrc[0];
        }
        $listofurls = array_merge(
            $listofurls,
            array_unique(array_filter($attachmentUrls))
        );
    }

    // Purge https and http URLs
    if (function_exists('force_ssl_admin') && force_ssl_admin()) {
        $listofurls = array_merge($listofurls, str_replace('https://', 'http://', $listofurls));
    } elseif (!is_ssl() && function_exists('force_ssl_content') && force_ssl_content()) {
        $listofurls = array_merge($listofurls, str_replace('http://', 'https://', $listofurls));
    }

    return $listofurls;
}