Skip to content
← Back to Functions
Code

Funnel Conversion Calculator

Calculates step-by-step conversion rates and drop-off percentages.

Function signature

ogCalculateFunnelConversion(steps = array(), options = array())

Categories

  • Analytics and Reports

Parameters

stepsOrdered counts or rows with name/count keys.optionsOptional keys: name_key, count_key. Recognized keys: `count_key`, `name_key`.

Return value

Short public-safe status message.

  • steps

Compatibility

Existing function name and call order preserved; metadata signature corrected to source.

Minimum PHP version: 7.4

Security notes

Validate request method, identity, permissions, and caller-owned allowlists before use; keep secrets and internal paths out of public output.

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.
 */

/**
 * Calculates step-by-step conversion rates and drop-off percentages.
 *
 * @param array $steps Ordered counts or rows with name/count keys.
 * @param array $options Optional keys: name_key, count_key.
 * @return array Funnel report with conversion and drop-off rows.
 */
function ogCalculateFunnelConversion($steps = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	if (!is_array($steps)) {
		$result['message'] = 'Steps must be an array.';
		return $result;
	}

	if (!is_array($options)) {
		$options = array();
	}

	$name_key = 'name';
	$count_key = 'count';
	if (!empty($options['name_key'])) {
		$name_key = (string)$options['name_key'];
	}
	if (!empty($options['count_key'])) {
		$count_key = (string)$options['count_key'];
	}

	$normalized = array();
	foreach ($steps as $index => $step) {
		$name = 'Step ' . ($index + 1);
		$count = null;
		if (is_array($step)) {
			if (!empty($step[$name_key])) {
				$name = trim((string)$step[$name_key]);
			}
			if (isset($step[$count_key]) && is_numeric($step[$count_key])) {
				$count = (float)$step[$count_key];
			}
		} else {
			if (is_numeric($step)) {
				$count = (float)$step;
			}
		}
		if ($count !== null && $count >= 0) {
			$normalized[] = array('name' => $name, 'count' => $count);
		}
	}

	if (count($normalized) < 2) {
		$result['message'] = 'At least two funnel steps are required.';
		return $result;
	}

	$first_count = $normalized[0]['count'];
	$rows = array();
	$previous_count = 0;
	foreach ($normalized as $index => $step) {
		$step_conversion = 100;
		$dropoff = 0;
		if ($index > 0) {
			if ($previous_count > 0) {
				$step_conversion = ($step['count'] / $previous_count) * 100;
				$dropoff = (($previous_count - $step['count']) / $previous_count) * 100;
			} else {
				$step_conversion = 0;
				$dropoff = 0;
			}
		}
		$total_conversion = 0;
		if ($first_count > 0) {
			$total_conversion = ($step['count'] / $first_count) * 100;
		}
		$rows[] = array(
			'name' => $step['name'],
			'count' => $step['count'],
			'step_conversion_percent' => $step_conversion,
			'total_conversion_percent' => $total_conversion,
			'dropoff_percent' => $dropoff
		);
		$previous_count = $step['count'];
	}

	$result['success'] = true;
	$result['message'] = 'Funnel conversion calculated.';
	$result['data'] = array('steps' => $rows);

	return $result;
}