if ( ! function_exists( 'kc_recommend_get_similar_manga_v2tax' ) ) {
function kc_recommend_get_similar_manga_v2tax( int $manga_id, array $tax_term_ids_map = array() ): array {
if ( $manga_id <= 0 ) { return array(); }
$cache_key = 'kagari_similar_reco_v2tax_' . (int) $manga_id;
$cached = get_transient( $cache_key );
if ( is_array( $cached ) && ! empty( $cached ) ) { return $cached; }
// tax名
$tax_play = function_exists('kc_tax') ? kc_tax('play') : 'kc_play';
$tax_look = function_exists('kc_tax') ? kc_tax('look') : 'kc_look';
$tax_scenario = function_exists('kc_tax') ? kc_tax('scenario') : 'kc_scenario';
$tax_feature = function_exists('kc_tax') ? kc_tax('feature') : 'kc_feature';
$tax_author = function_exists('kc_tax') ? kc_tax('author') : 'kc_author';
// 入力term map 正規化
$play_ids = isset( $tax_term_ids_map[ $tax_play ] ) && is_array( $tax_term_ids_map[ $tax_play ] ) ? array_values(array_unique(array_filter(array_map('intval',$tax_term_ids_map[$tax_play])))) : array();
$look_ids = isset( $tax_term_ids_map[ $tax_look ] ) && is_array( $tax_term_ids_map[ $tax_look ] ) ? array_values(array_unique(array_filter(array_map('intval',$tax_term_ids_map[$tax_look])))) : array();
$scenario_ids = isset( $tax_term_ids_map[ $tax_scenario ] ) && is_array( $tax_term_ids_map[ $tax_scenario ] ) ? array_values(array_unique(array_filter(array_map('intval',$tax_term_ids_map[$tax_scenario])))) : array();
$feature_ids = isset( $tax_term_ids_map[ $tax_feature ] ) && is_array( $tax_term_ids_map[ $tax_feature ] ) ? array_values(array_unique(array_filter(array_map('intval',$tax_term_ids_map[$tax_feature])))) : array();
// 4タクソが全部空なら検索不能
if ( empty($play_ids) && empty($look_ids) && empty($scenario_ids) && empty($feature_ids) ) {
return array();
}
// 同一作者を除外(Similar枠から排除)
$exclude_author_ids = array();
$cur_author_terms = get_the_terms( $manga_id, $tax_author );
if ( $cur_author_terms && ! is_wp_error( $cur_author_terms ) ) {
$exclude_author_ids = array_values(array_unique(array_filter(array_map('intval', wp_list_pluck($cur_author_terms,'term_id')))));
}
$post_types = function_exists('kc_manga_post_types') ? kc_manga_post_types() : array('kc_manga');
// 候補取得:OR(どれか一致)→ 後段で「2カテゴリ以上一致」にフィルタ
$or_group = array( 'relation' => 'OR' );
if ( !empty($play_ids) ) { $or_group[] = array('taxonomy'=>$tax_play, 'field'=>'term_id','terms'=>$play_ids); }
if ( !empty($look_ids) ) { $or_group[] = array('taxonomy'=>$tax_look, 'field'=>'term_id','terms'=>$look_ids); }
if ( !empty($scenario_ids) ) { $or_group[] = array('taxonomy'=>$tax_scenario, 'field'=>'term_id','terms'=>$scenario_ids); }
if ( !empty($feature_ids) ) { $or_group[] = array('taxonomy'=>$tax_feature, 'field'=>'term_id','terms'=>$feature_ids); }
$tax_query = array( 'relation' => 'AND', $or_group );
if ( !empty($exclude_author_ids) ) {
$tax_query[] = array(
'taxonomy' => $tax_author,
'field' => 'term_id',
'terms' => $exclude_author_ids,
'operator' => 'NOT IN',
);
}
// ✅ 取りこぼし対策:20 → 200(増やしすぎたくなければ100でもOK)
$candidate_query = new WP_Query(array(
'post_type' => $post_types,
'post_status' => 'publish',
'posts_per_page' => 200,
'post__not_in' => array($manga_id),
'tax_query' => $tax_query,
'no_found_rows' => true,
));
$items = array();
// ✅ “似てる”定義:最低「2カテゴリ以上一致」
$MIN_CATEGORY_HITS = 2; // 強めたいなら 3 にする
if ( $candidate_query->have_posts() ) {
while ( $candidate_query->have_posts() ) {
$candidate_query->the_post();
$pid = get_the_ID();
$c_play = get_the_terms( $pid, $tax_play );
$c_look = get_the_terms( $pid, $tax_look );
$c_scenario = get_the_terms( $pid, $tax_scenario );
$c_feature = get_the_terms( $pid, $tax_feature );
$c_play_ids = ($c_play && !is_wp_error($c_play)) ? wp_list_pluck($c_play,'term_id') : array();
$c_look_ids = ($c_look && !is_wp_error($c_look)) ? wp_list_pluck($c_look,'term_id') : array();
$c_scenario_ids = ($c_scenario && !is_wp_error($c_scenario)) ? wp_list_pluck($c_scenario,'term_id') : array();
$c_feature_ids = ($c_feature && !is_wp_error($c_feature)) ? wp_list_pluck($c_feature,'term_id') : array();
$shared_play = (!empty($play_ids) && !empty($c_play_ids)) ? array_intersect($play_ids, $c_play_ids) : array();
$shared_look = (!empty($look_ids) && !empty($c_look_ids)) ? array_intersect($look_ids, $c_look_ids) : array();
$shared_scenario = (!empty($scenario_ids) && !empty($c_scenario_ids)) ? array_intersect($scenario_ids, $c_scenario_ids) : array();
$shared_feature = (!empty($feature_ids) && !empty($c_feature_ids)) ? array_intersect($feature_ids, $c_feature_ids) : array();
$category_hits = 0;
if (!empty($shared_play)) $category_hits++;
if (!empty($shared_look)) $category_hits++;
if (!empty($shared_scenario)) $category_hits++;
if (!empty($shared_feature)) $category_hits++;
// ❌ 1カテゴリ一致は“似てる”扱いにしない
if ( $category_hits < $MIN_CATEGORY_HITS ) { continue; }
$similarity = count($shared_play) + count($shared_look) + count($shared_scenario) + count($shared_feature);
// 人気スコア
$pop = 0;
if ( function_exists('kagari_status_get_views') ) {
$v = (int) kagari_status_get_views($pid);
if ($v > 0) $pop += (int) floor(log(1 + $v));
}
$likes = function_exists('kc_get_manga_like_count')
? (int) kc_get_manga_like_count($pid)
: (int) get_post_meta($pid, '_kc_like_count', true);
if ($likes > 0) $pop += min(10, $likes);
$items[] = array(
'post' => get_post($pid),
'category_hits' => (int) $category_hits,
'similarity' => (int) $similarity,
'popularity' => (int) $pop,
'date' => (int) get_post_time('U', true, $pid),
);
}
wp_reset_postdata();
}
// 並び:一致カテゴリ数 → 一致term総数 → 品質 → 新しさ
usort($items, function($a,$b){
if ($a['category_hits'] !== $b['category_hits']) return $b['category_hits'] - $a['category_hits'];
if ($a['similarity'] !== $b['similarity']) return $b['similarity'] - $a['similarity'];
if ($a['popularity'] !== $b['popularity']) return $b['popularity'] - $a['popularity'];
return $b['date'] - $a['date'];
});
// ✅ 埋めない:似てるものだけ最大10件(足りなければ少ないまま)
$top = array_slice($items, 0, 10);
if ( !empty($top) ) {
set_transient($cache_key, $top, 20 * MINUTE_IN_SECONDS);
}
// 返却形式を既存に合わせる(viewer側が similarity_score を見てる可能性があるため)
$out = array();
foreach ($top as $x) {
$out[] = array(
'post' => $x['post'],
'similarity_score' => $x['similarity'],
'popularity_score' => $x['popularity'],
'date' => $x['date'],
);
}
return $out;
}
}
Warning: Cannot modify header information - headers already sent by (output started at /var/www/kagari/wp-content/themes/blocksy-child/inc/core/viewer/kc-recommend-helpers.php:1) in /var/www/kagari/wp-content/plugins/paid-memberships-pro/adminpages/reports/logins.php on line 458
Warning: Cannot modify header information - headers already sent by (output started at /var/www/kagari/wp-content/themes/blocksy-child/inc/core/viewer/kc-recommend-helpers.php:1) in /var/www/kagari/wp-includes/pluggable.php on line 1531
Warning: Cannot modify header information - headers already sent by (output started at /var/www/kagari/wp-content/themes/blocksy-child/inc/core/viewer/kc-recommend-helpers.php:1) in /var/www/kagari/wp-includes/pluggable.php on line 1534