Skip to main content

Arrays, Functions, and WordPress Naming

Arrays

WordPress APIs frequently accept associative arrays for arguments.

$query_args = [
'post_type' => 'post',
'posts_per_page' => 5,
'post_status' => 'publish',
];

Use one key per line for readability when arrays configure behavior.

Reading Array Values Safely

User input and API responses may not contain every key. Check before reading.

$sort = isset($_GET['sort']) ? sanitize_key(wp_unslash($_GET['sort'])) : 'date';

For nested arrays, use defensive defaults.

$settings = get_option('my_plugin_settings', []);
$limit = isset($settings['limit']) ? absint($settings['limit']) : 10;

Functions

Functions group reusable behavior.

function myplugin_get_featured_post_ids(): array {
$ids = get_option('myplugin_featured_posts', []);

return array_map('absint', (array) $ids);
}

Prefix Function Names

WordPress loads many plugins into the same PHP process. Global function names can collide.

function myplugin_register_settings(): void {
register_setting('myplugin', 'myplugin_settings');
}

Avoid generic names like register_settings() or save_form().

Callbacks

Hooks receive callbacks. A callback can be a function name, object method, static method, or closure.

add_action('init', 'myplugin_register_post_type');

function myplugin_register_post_type(): void {
register_post_type('book', [
'label' => __('Books', 'my-plugin'),
'public' => true,
]);
}

Type Hints

Modern PHP supports parameter and return types. Use them where they clarify your code, but remember many WordPress callbacks pass dynamic values.

function myplugin_format_price(float $amount): string {
return '$' . number_format($amount, 2);
}

WordPress Naming Conventions

ItemRecommended Pattern
Functionmyplugin_do_something()
Optionmyplugin_setting_name
Actionmyplugin_before_render
Filtermyplugin_output_html
Text domainmy-plugin
CSS classmyplugin-component

Practical Pattern

Use a small function to normalize data before rendering.

function myplugin_get_card_data(int $post_id): array {
return [
'title' => get_the_title($post_id),
'url' => get_permalink($post_id),
'image' => get_the_post_thumbnail_url($post_id, 'medium'),
];
}

Render later with escaping at the output boundary.

$card = myplugin_get_card_data(get_the_ID());
?>
<a href="<?php echo esc_url($card['url']); ?>">
<?php echo esc_html($card['title']); ?>
</a>
<?php

Common Pitfalls

  • Creating global functions without a project prefix
  • Trusting $_GET, $_POST, or option values without validation
  • Escaping too early, then reusing already escaped values in non-HTML contexts
  • Putting complex array configuration inline inside templates

Deep WordPress Application

This lesson is most useful when applied to real WordPress code rather than isolated PHP examples. Arrays, Functions, and WordPress Naming affects how a site behaves under plugins, themes, editors, logged-in users, guests, cached pages, REST requests, and production traffic.

PHP fundamentals become useful in WordPress when they are tied to template rendering, hook callbacks, request data, and option values.

A practical implementation should answer four questions before code is written:

  • Which WordPress request context will run this code?
  • Which API or hook owns the behavior?
  • Which data is trusted, and which data must be normalized?
  • What should happen when the expected data, permission, or dependency is missing?

WordPress API Anchor

For this topic, a common API or integration point is get_option(). The exact function may vary by feature, but the design principle is stable: use WordPress APIs before inventing custom plumbing.

A common hook or lifecycle point for this topic is init. Confirm the hook runs in the request type you care about before attaching expensive or state-changing logic.

Focused Code Pattern

function myplugin_normalize_limit($raw_limit): int {
$limit = absint($raw_limit);

if ($limit < 1) {
return 10;
}

return min($limit, 50);
}

This pattern should still be adapted to the exact feature. Add capability checks for private data, nonces for browser-submitted state changes, and output escaping when rendering values.

Data Flow Walkthrough

StageWhat To DecideWordPress Example
SourceWhere the value comes fromRequest data, option, post meta, user meta, REST parameter, remote API
TrustWhether the value can be used directlyTreat external, request, and old saved values as untrusted
NormalizeHow PHP converts the value into a safe shapeabsint(), sanitize_text_field(), sanitize_key(), custom allow-list
AuthorizeWho can read or change itcurrent_user_can() with a specific capability
PersistWhere the value belongsOption, post meta, user meta, taxonomy term, custom table
RenderHow the value leaves PHPesc_html(), esc_attr(), esc_url(), wp_kses_post()

Applied Practice

Create a small helper function, call it from a hook callback, and confirm that bad input falls back to a safe default.

When practicing, do not stop when the happy path works. WordPress code becomes reliable when the failure paths are equally deliberate.

Expanded Decision Guide

DecisionPrefer ThisAvoid This
Where code livesA plugin for durable behavior, a theme for presentationEditing WordPress core or vendor plugin files
How data entersA named request handler with validationReading superglobals deep inside templates
How data is storedWordPress APIs with clear keys and typesUnstructured arrays with undocumented meanings
How output is printedEscape at the final output contextTrusting saved data because it came from the database
How failures behaveReturn early, log safely, show useful messagesFatal errors, blank pages, or exposed stack details
How changes shipSmall reviewed changes with rollback notesLarge untested edits directly on production

Implementation Checklist

Use this checklist when applying the lesson in a real WordPress codebase.

  • Identify whether the code belongs in a plugin, child theme, block, mu-plugin, or deployment script.
  • Name functions, classes, options, actions, filters, and CSS hooks with a project-specific prefix.
  • Confirm which hook should run the code and whether that hook fires in admin, front end, AJAX, REST, cron, or CLI contexts.
  • Validate every value that comes from a request, database option, custom field, remote API, cookie, or file.
  • Sanitize before storing data and escape at the exact output boundary.
  • Check the narrowest useful capability before reading private data or changing state.
  • Add nonces or signed requests for state-changing browser actions.
  • Keep database queries narrow by requesting only the fields and post types needed.
  • Reset global WordPress state after custom queries, site switching, or temporary filters.
  • Add a short manual test note for the main success path and at least one failure path.

Extended Example Pattern

The following pattern is intentionally small. It demonstrates how to keep request handling, normalization, and output separate enough to review.

add_action('admin_post_myplugin_example_action', 'myplugin_handle_example_action');

function myplugin_handle_example_action(): void {
if (! current_user_can('manage_options')) {
wp_die(esc_html__('You are not allowed to do that.', 'my-plugin'));
}

check_admin_referer('myplugin_example_action', 'myplugin_nonce');

$label = isset($_POST['label'])
? sanitize_text_field(wp_unslash($_POST['label']))
: '';

if ('' === $label) {
wp_safe_redirect(add_query_arg('status', 'missing-label', wp_get_referer() ?: admin_url()));
exit;
}

update_option('myplugin_example_label', $label, false);

wp_safe_redirect(add_query_arg('status', 'saved', wp_get_referer() ?: admin_url()));
exit;
}

Troubleshooting Matrix

SymptomLikely CauseFirst Check
Callback never runsWrong hook name, priority, or load contextConfirm the hook fires in this request type
Data saves incorrectlyMissing unslash, sanitization, or type normalizationLog sanitized values in development only
Output looks brokenEscaped for the wrong context or escaped too earlyCheck whether the output is text, HTML, URL, or attribute
Permission bugRole check is too broad or capability is missing an object IDUse current_user_can() with the specific operation
Slow pageQuery, HTTP request, or loop work runs on every requestProfile with Query Monitor and add caching or batching
Works locally onlyPHP version, plugin dependency, rewrite rule, or environment setting differsCompare environment versions and enabled plugins

Practice Exercise

  1. Recreate the smallest practical example from this lesson in a local WordPress site.
  2. Add one valid input and one invalid input.
  3. Confirm the invalid input fails safely without changing stored data.
  4. Confirm the valid input is sanitized before storage.
  5. Render the stored value in at least two contexts, such as text and attribute output.
  6. Add a capability check and verify a lower-privilege user cannot perform the action.
  7. Temporarily enable debug logging and confirm no PHP warnings appear.
  8. Remove temporary logs before treating the example as complete.

Review Questions

  • What WordPress hook or API makes this lesson reliable in the right request context?
  • Which values in the example are untrusted at the moment they enter PHP?
  • Where should validation happen, and where should output escaping happen?
  • What user capability is required for the action, and why is that the narrowest useful choice?
  • What is the expected behavior when the required data is missing or malformed?
  • What would need to change before this code runs safely on a large production site?

Production Notes

Production WordPress PHP should be easy to audit under pressure. Keep the control flow direct, keep side effects visible, and prefer small functions that name the business rule they enforce. If a future maintainer cannot identify the request source, permission check, data normalization, and output boundary in a few minutes, the code is too implicit.