Skip to content
← Back to Functions
Code

Internal Link Suggestion Builder

Suggests related internal links using item type, category, tags, and content similarity.

Function signature

ogSuggestInternalLinks(current_item = array(), candidate_items = array(), max_links = 6)

Categories

  • Search and Discovery

Parameters

current_itemCurrent item record used as the internal-link anchor context.candidate_itemsCandidate item rows scored for internal-link suggestions.max_linksMaximum number of related links to return.

Return value

Public-safe status string returned by the function for controller branching or logging.

  • success
  • message
  • data

Compatibility

Existing function name, slug, path, and call order preserved; advertised metadata corrected to the actual source behavior.

Minimum PHP version: 7.4

Security notes

Use caller-owned allowlists and context-specific escaping; validate file paths, routes, email tokens, cart totals, discount rules, and tax-region rules before production use.

Code

<?php

/*
 * Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
 * Free for personal and internal use. Paid project use requires visible credit
 * to Jeffery L. Paris. Corporate use requires a paid license fee unless a
 * separate written license states otherwise.
 */

/**
 * Suggests related internal links using item type, category, tags, and content similarity.
 *
 * Primary use case: SEO and user navigation.
 * Typical inputs: current item, item index, max links.
 * Typical output: link suggestions.
 *
 * Implementation note: Avoid circular repetitive link blocks.
 *
 * @param array $current_item Current item record with id, type, category, and tags.
 * @param array $candidate_items Candidate item records.
 * @param int $max_links Maximum number of links to return.
 * @return array Suggested internal links.
 */
function ogSuggestInternalLinks($current_item = array(), $candidate_items = array(), $max_links = 6) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	if (!is_array($current_item) || !is_array($candidate_items)) {
		$result['message'] = 'Current item and candidates must be arrays.';
		return $result;
	}
	$max_links = (int)$max_links;
	if ($max_links < 1) {
		$max_links = 1;
	}

	$current_id = 0;
	if (!empty($current_item['id'])) {
		$current_id = (int)$current_item['id'];
	}
	$current_tags = array();
	if (!empty($current_item['tags']) && is_array($current_item['tags'])) {
		$current_tags = $current_item['tags'];
	}

	$scores = array();
	foreach ($candidate_items as $candidate) {
		if (!is_array($candidate)) {
			continue;
		}
		if (!empty($candidate['id']) && (int)$candidate['id'] == $current_id) {
			continue;
		}
		$score = 0;
		if (!empty($candidate['item_type']) && !empty($current_item['item_type']) && $candidate['item_type'] == $current_item['item_type']) {
			$score += 3;
		}
		if (!empty($candidate['category_slug']) && !empty($current_item['category_slug']) && $candidate['category_slug'] == $current_item['category_slug']) {
			$score += 4;
		}
		if (!empty($candidate['tags']) && is_array($candidate['tags'])) {
			foreach ($candidate['tags'] as $tag) {
				if (in_array($tag, $current_tags, true)) {
					$score++;
				}
			}
		}
		if ($score > 0) {
			$candidate['score'] = $score;
			$scores[] = $candidate;
		}
	}

	usort($scores, function($left, $right) {
		if ($left['score'] == $right['score']) {
			return 0;
		}
		if ($left['score'] > $right['score']) {
			return -1;
		}
		return 1;
	});

	$result['success'] = true;
	$result['message'] = 'Internal links suggested.';
	$result['data'] = array(
		'links' => array_slice($scores, 0, $max_links),
		'candidate_count' => count($candidate_items)
	);

	return $result;
}