Skip to content
← Back to Functions
Code

Admin Table State Builder

Builds filter, search, pagination, and sort state for admin tables.

Function signature

ogBuildAdminTableState(request = array(), options = array())

Categories

  • Admin Tools

Parameters

requestRead-only request/filter data selected by the caller for table-state normalization.optionsOptional documented policy controls for this helper.

Return value

Public-safe status string returned by the function for explicit 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 admin actions, export fields, privacy plans, cache keys, templates, settings, routes, and ecommerce policies 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.
 */

/**
 * Builds filter, search, pagination, and sort state for admin tables.
 *
 * Sort fields are allowlisted. Search text is normalized but must still be escaped
 * for its final output context or bound as a query parameter by the caller.
 *
 * @param array $request Read-only request/filter values.
 * @param array $options Allowed sort fields, defaults, and pagination limits.
 * @return array Admin table state.
 */
function ogBuildAdminTableState($request = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

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

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

	$allowed_sort_fields = array('id', 'title', 'created_at', 'updated_at');
	if (!empty($options['allowed_sort_fields']) && is_array($options['allowed_sort_fields'])) {
		$allowed_sort_fields = $options['allowed_sort_fields'];
	}

	$default_sort = 'id';
	if (!empty($options['default_sort']) && in_array($options['default_sort'], $allowed_sort_fields, true)) {
		$default_sort = (string)$options['default_sort'];
	}

	$page = 1;
	if (!empty($request['page'])) {
		$page = (int)$request['page'];
	}
	if ($page < 1) {
		$page = 1;
	}

	$per_page = 25;
	if (!empty($request['per_page'])) {
		$per_page = (int)$request['per_page'];
	} elseif (!empty($options['default_per_page'])) {
		$per_page = (int)$options['default_per_page'];
	}
	if ($per_page < 1) {
		$per_page = 25;
	}
	if ($per_page > 100) {
		$per_page = 100;
	}

	$sort = $default_sort;
	if (!empty($request['sort']) && in_array($request['sort'], $allowed_sort_fields, true)) {
		$sort = (string)$request['sort'];
	}

	$direction = 'ASC';
	if (!empty($request['direction'])) {
		$direction_candidate = strtoupper(trim((string)$request['direction']));
		if ($direction_candidate == 'DESC') {
			$direction = 'DESC';
		}
	}

	$search = '';
	if (!empty($request['search'])) {
		$search = trim(strip_tags((string)$request['search']));
		$search = preg_replace('/\s+/', ' ', $search);
		if (strlen($search) > 120) {
			$search = substr($search, 0, 120);
		}
	}

	$filters = array();
	if (!empty($request['filters']) && is_array($request['filters'])) {
		foreach ($request['filters'] as $key => $value) {
			$key = preg_replace('/[^a-zA-Z0-9_]/', '', (string)$key);
			if (!empty($key) && is_scalar($value)) {
				$filters[$key] = trim((string)$value);
			}
		}
	}

	$offset = ($page - 1) * $per_page;

	$result['success'] = true;
	$result['message'] = 'Admin table state built.';
	$result['data'] = array(
		'page' => $page,
		'per_page' => $per_page,
		'offset' => $offset,
		'sort' => $sort,
		'direction' => $direction,
		'search' => $search,
		'filters' => $filters
	);

	return $result;
}