WP Manifestindependent plugin directory
manifest / content / hm-related-posts

HM Related Posts WP Registry grade D+. High-severity findings · 2 findingsWP RegistryHigh-severity findings · 2 findingsOpen the reportD+

Related Posts (from HM Core) + Meta box for manually overriding dynamic selected posts.

★ 12stars
4.2kcomposer installs
1.2.2latest · 7 years ago

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/humanmade/hm-related-posts/archive/refs/heads/master.zip

On Packagist as humanmade/related-posts:

composer require humanmade/related-posts
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Related Posts

This plugin provides a simple related posts function with the following features:

  • ElasticPress integration (uses a "More Like This" query)
  • Admin UI for manually overriding related posts

Installation

composer require humanmade/related-posts

Usage

The plugin exposes a single function that returns a list of post IDs.

HM\Related_Posts\get( int $post_id, array $args = [] )

$post_id is the ID of the post to get related content for.

$args allows you some control over the posts that are returned:

  • int limit: defaults to 10
  • array post_types: array of post types to limit results to. Defaults to [ 'post' ]
  • array taxonomies: array of taxonomies to compare against. Defaults to [ 'category' ]
  • array terms: array of WP_Term objects, results will match these terms
  • array terms_not_in: array of WP_Term objects, results will not match these terms
  • bool ep_integrate: if true then ElasticPress is used to get the results, Defaults to defined( 'EP_VERSION' )

Custom post type support

To add related posts support to your custom post type simply declare the following:

add_post_type_support( 'your-custom-post-type', 'hm-related-posts' );

In addition to fine control the post types that have related posts support you can use the hm_rp_post_types filter.

add_filter( 'hm_rp_post_types', function ( $post_types ) {
    // your code goes in here

    return $post_types;
} );

Made with ❤️ by Human Made

Releases

5 releases.

Tag
Published
1.2.2 latest
Jan 22, 2019 7 years ago
Nov 20, 2018 7 years ago
Nov 20, 2018 7 years ago
Jan 29, 2018 8 years ago
Mar 31, 2014 12 years ago

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.

D+ grade

Security

HM Related Posts 1.2.2 · audited by WP Registry

High-severity findings.

1 high 1 medium
Audited release
1.2.2
Findings
2
Worst severity
high
Content hash
007a5b48416c79f153bc8c34…

Findings

  • high Stored XSS in related-posts metabox via unescaped post title in inline JavaScript

    xss_stored

    override_metabox_script() builds Select2 initSelection with sprintf('{ id: %d, text: "%s" }', $value, html_entity_decode(get_the_title($value))) inside an inline <script> block. The title is not passed through esc_js() or wp_json_encode(). Bare quotes in a title are curled by wptexturize (so foo"};alert(1) does not break out), but users without unfiltered_html still persist kses-allowed tags on title_save_pre (wp_filter_kses default tags include a/code/blockquote/b). Attribute quotes inside those tags are not texturized. Empirically, a Contributor post title of <a href="};alert(document.domain);//">x</a> is stored as-is and renders as var data = { id: N, text: "<a href="};alert(document.domain);//">x</a>" }; which is valid JS: the object closes after href=", then alert() runs. Attack: Contributor creates/saves a post with that title, sets it as a manual related post on a post they can edit (hm_rp_post); any Editor/Admin who opens that post in wp-admin executes the payload (cookie/nonce theft). Select2's AJAX results path is escaped via escapeMarkup and is not this bug.

    inc/admin/namespace.php:169-176

    Recommendation

    Replace the sprintf object with wp_json_encode( array( 'id' => (int) $value, 'text' => wp_strip_all_tags( get_the_title( $value ) ) ) ) (no surrounding quotes). Do not html_entity_decode into a JS string. Optionally strip tags from titles before display.

  • medium Related-posts AJAX search discloses unpublished posts and accepts arbitrary WP_Query args

    information_disclosure

    wp_ajax_hm_rp_ajax_post_select is reachable by any logged-in user who can edit the supplied post_id (Contributor+ on their own post). After the nonce/cap check it does $args = sanitize_query($_GET['query']) then new WP_Query($args) and returns every match's ID and get_the_title() as JSON. The UI only intends to send s and paged, but sanitize_query() allowlists public query vars unsanitized (including post_type) and private vars such as post_status, posts_per_page, post__in, perm, plus meta_query/tax_query. Even the default UI query leaks data: admin-ajax.php defines WP_ADMIN so WP_Query sets is_admin and, when post_status is empty, adds protected statuses that show_in_admin_all_list (draft/pending/future) with no author restriction — other users' unpublished titles appear in search results. Passing query[post_status]=private|trash|any or query[post_type]=page|attachment (and posts_per_page=-1) widens that to trash/private/other types; s is applied to post_content so unpublished bodies can be oracle-searched. Core's post list table does not show others' drafts to Contributors; this endpoint does.

    inc/admin/namespace.php:225-255

    Recommendation

    Force a safe query: post_status=publish (or a capability-aware readable set), post_type limited to types the user can read, posts_per_page capped, s/paged only. Ignore caller-supplied post_status/post_type/meta_query/tax_query/perm. Add 'perm' => 'readable' if unpublished results are ever required. Do not pass the raw $_GET['query'] array into WP_Query.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.