Initial public release of BreznFlow, an n8n workflow renderer for WordPress. Fully PHPCS-compliant (WordPress Coding Standards), security-hardened, and ready for WordPress.org plugin review. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
106 lines
2.6 KiB
PHP
106 lines
2.6 KiB
PHP
<?php
|
|
/**
|
|
* Finds related workflows by shared node types.
|
|
*
|
|
* @package BreznFlow
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
namespace BreznFlow\Features;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Finds and displays workflows related by shared node types.
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
class RelatedWorkflows {
|
|
/**
|
|
* Registers related workflows hooks.
|
|
*
|
|
* @since 1.0.0
|
|
* @return void
|
|
*/
|
|
public function register(): void {
|
|
// Can be extended to add hooks for related workflow display.
|
|
}
|
|
|
|
/**
|
|
* Gets related workflows by shared node types.
|
|
* Results are cached in a transient for 1 hour.
|
|
*
|
|
* @param int $post_id Workflow post ID.
|
|
* @param int $limit Max number of related workflows to return.
|
|
* @return array Array of WP_Post objects.
|
|
*/
|
|
public static function get( int $post_id, int $limit = 5 ): array {
|
|
$settings = get_option( 'breznflow_settings', array() );
|
|
if ( isset( $settings['related_workflows'] ) && ! $settings['related_workflows'] ) {
|
|
return array();
|
|
}
|
|
|
|
$cache_key = 'breznflow_related_' . $post_id;
|
|
$cached = get_transient( $cache_key );
|
|
if ( false !== $cached ) {
|
|
return $cached;
|
|
}
|
|
|
|
$summary = get_post_meta( $post_id, '_breznflow_node_summary', true );
|
|
if ( ! $summary ) {
|
|
return array();
|
|
}
|
|
|
|
$node_types = array_keys( (array) json_decode( $summary, true ) );
|
|
if ( empty( $node_types ) ) {
|
|
return array();
|
|
}
|
|
|
|
// Search other workflows with overlapping node types.
|
|
$related = get_posts(
|
|
array(
|
|
'post_type' => 'breznflow_workflow',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => $limit,
|
|
'post__not_in' => array( $post_id ), // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in
|
|
'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
|
|
array(
|
|
'key' => '_breznflow_node_summary',
|
|
'compare' => 'EXISTS',
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
// Filter by shared node types.
|
|
$scored = array();
|
|
foreach ( $related as $post ) {
|
|
$other_summary = get_post_meta( $post->ID, '_breznflow_node_summary', true );
|
|
if ( ! $other_summary ) {
|
|
continue;
|
|
}
|
|
$other_types = array_keys( (array) json_decode( $other_summary, true ) );
|
|
$shared = count( array_intersect( $node_types, $other_types ) );
|
|
if ( $shared > 0 ) {
|
|
$scored[] = array(
|
|
'post' => $post,
|
|
'shared' => $shared,
|
|
);
|
|
}
|
|
}
|
|
|
|
usort(
|
|
$scored,
|
|
static function ( $a, $b ) {
|
|
return $b['shared'] - $a['shared'];
|
|
}
|
|
);
|
|
|
|
$result = array_column( array_slice( $scored, 0, $limit ), 'post' );
|
|
|
|
set_transient( $cache_key, $result, HOUR_IN_SECONDS );
|
|
return $result;
|
|
}
|
|
}
|