Code without documentation AND with poor naming is:
- Hard to understand - What does this function do?
- Hard to use - What parameters does it need?
- Hard to maintain - What does it return?
- No IDE support - No autocomplete hints
- Difficult for teams - Other developers must read implementation
- Confusing - Generic names like
get(),fetch(),Handlerdon't reveal intent
Both bad.php and good.php contain identical functionality - same logic, same behavior.
The differences:
- bad.php - No PHPDoc comments + Ambiguous naming (
DataManager,Handler,get(),fetch()) - good.php - Complete PHPDoc documentation + Clear naming (
PostRepository,PostService,find_by_id())
class DataManager {
private wpdb $db;
public function get(int $id): ?WP_Post {
$result = get_post($id);
if (!$result instanceof WP_Post) {
return null;
}
return $result;
}
public function fetch(int $user, int $num = 10, string $type = 'publish'): array {
$num = max(1, min(100, $num));
$sql = $this->db->prepare(
"SELECT * FROM {$this->db->posts}
WHERE post_author = %d
AND post_status = %s
ORDER BY post_date DESC
LIMIT %d",
$user,
$type,
$num
);
return $this->db->get_results($sql);
}
}
class Handler {
private DataManager $dm;
private Checker $chk;
public function make(array $input): int|WP_Error {
// ...
}
}
function getSnippet(WP_Post $p, int $len = 100): string {
// ...
}Multiple problems:
-
Generic class names:
DataManager- manages what data? Posts? Users? Comments?Handler- handles what? Requests? Posts? Events?Checker- checks what?
-
Ambiguous method names:
get()- get what? From where?fetch()- what's the difference betweenget()andfetch()?make()- make what?getSimilar()- similar to what? How?
-
Cryptic parameter names:
$user- user ID or user object?$num- number of what?$type- type of what? What values are valid?$p- why abbreviate?$len- length in characters or words?
-
Unclear variable names:
$dm- DataManager? Direct Message? Dungeon Master?$chk- why abbreviate "checker"?$err- errors? error? error code?
Questions developers have:
- What does
DataManager::fetch()return? Posts? Users? Raw results? - What's the difference between
get()andfetch()? - What does
Handler::make()create? - Is
$numinfetch()limited? What's the max? - What values can
$typebe? - What happens if nothing is found?
They must read every line of code to find answers!
/**
* Repository for managing WordPress posts.
*
* Provides methods for retrieving, searching, and managing post data
* with a clean, object-oriented interface.
*
* @package MyPlugin
* @since 1.0.0
*/
class PostRepository {
/**
* WordPress database object.
*
* @var wpdb
*/
private wpdb $wpdb;
/**
* Initialize the repository.
*
* Sets up the repository.
*
* @since 1.0.0
*/
public function __construct() {}
/**
* Find posts by author.
*
* Retrieves posts written by a specific author, ordered by date.
*
* @since 1.0.0
*
* @param int $author_id The author's user ID.
* @param int $limit Maximum number of posts to return. Default 10. Max 100.
* @param string $status Post status to filter by. Default 'publish'.
* @return array Array of post objects.
*/
public function find_by_author(int $author_id, int $limit = 10, string $status = 'publish'): array {
global $wpdb;
$limit = max(1, min(100, $limit));
$query = $wpdb->prepare(
"SELECT * FROM {$wpdb->posts}
WHERE post_author = %d
AND post_status = %s
ORDER BY post_date DESC
LIMIT %d",
$author_id,
$status,
$limit
);
return $wpdb->get_results($query);
}
}Everything is clear:
-
Descriptive class names:
PostRepository- immediately know it manages postsPostService- handles post-related business logicPostValidator- validates post data
-
Explicit method names:
find_by_id()- find post by IDfind_by_author()- find posts by authorcreate()- create a new postupdate()- update existing post
-
Clear parameter names:
$author_id- obviously an author's ID$limit- clearly a limit count$status- post status value$post- the post object
-
Comprehensive documentation:
- Purpose: "Find posts by author"
- Parameters: Each explained with type and purpose
- Return: "Array of post objects"
- Behavior: "ordered by date", "Max 100"
No questions remain!
Poor naming + No documentation = Maximum confusion
// bad.php - Ambiguous naming, no docs
class Handler {
public function make(array $input): int|WP_Error {
// ... 30 lines of code
}
}Developer questions:
- What kind of handler?
- Make what?
- What should
$inputcontain? - Returns int - ID of what?
- When does it return WP_Error?
Must read all 30 lines to understand!
// good.php - Clear naming + documentation
/**
* Service for managing post operations.
*
* @package MyPlugin
* @since 1.0.0
*/
class PostService {
/**
* Create a new post.
*
* Validates the data and creates a new post with the provided information.
*
* @param array $data {
* Post data.
* @type string $title Post title. Required.
* @type string $content Post content. Required.
* @type string $status Post status. Default 'draft'.
* }
* @return int|WP_Error Post ID on success, WP_Error on failure.
*/
public function create(array $data): int|WP_Error {
// ... 30 lines of code
}
}Everything answered immediately!
- It's a post service
- Creates a new post
- Needs title and content
- Returns post ID on success
- Returns WP_Error on failure
- No need to read the implementation!
/**
* Brief description (one line).
*
* Longer description with more details about what
* the class does and how to use it.
*
* @package MyPlugin
* @since 1.0.0
*/
class MyClass {Tags:
@package- Which package/namespace@since- When it was introduced@author- Who wrote it (optional)
/**
* Brief description of what the method does.
*
* Longer description with implementation details,
* usage examples, or important notes.
*
* @since 1.0.0
*
* @param int $param1 Description of first parameter.
* @param string $param2 Description of second parameter. Default 'value'.
* @return bool True on success, false on failure.
*/
public function my_method(int $param1, string $param2 = 'value'): bool {Tags:
@since- Version introduced@param- Each parameter with type, name, description@return- What it returns@throws- Exceptions it might throw
/**
* Description of the property.
*
* @var string
*/
private string $my_property;/**
* Create a new post.
*
* @param array $data {
* Post data.
*
* @type string $title Post title. Required.
* @type string $content Post content. Required.
* @type string $status Post status. Default 'draft'.
* @type int $author_id Author user ID. Default current user.
* @type int[] $categories Array of category IDs. Optional.
* @type string[] $tags Array of tag names. Optional.
* }
* @return int|WP_Error Post ID on success, WP_Error on failure.
*/
public function create(array $data): int|WP_Error {Nested @type tags document array structure!
Without PHPDoc:
$repository->find_by_author( // IDE shows: (int $author_id, int $limit, string $status)With PHPDoc:
$repository->find_by_author(
// IDE shows:
// @param int $author_id The author's user ID
// @param int $limit Maximum number of posts. Default 10. Max 100
// @param string $status Post status to filter by. Default 'publish'
// @return array Array of post objectsWhen you type $repository->, IDE shows:
- All available methods
- Brief description of each
- Parameter hints
- Return type hints
Hover over method name → See full documentation without opening file!
/**
* @return WP_Post[] Array of post objects
*/
public function get_posts(): array {Now IDE knows it's an array OF WP_Post objects, enabling autocomplete on array elements!
Tools like phpDocumentor can generate HTML documentation from PHPDoc:
phpdoc -d src/ -t docs/Creates browsable documentation website!
function get_post_excerpt(WP_Post $post, int $length = 100): string {
$content = strip_tags($post->post_content);
if (strlen($content) <= $length) {
return $content;
}
return substr($content, 0, $length) . '...';
}Developer thinking:
- "What does this return?"
- "Is the length in characters or words?"
- "Does it preserve HTML?"
- "What if post is empty?"
Must read code to answer!
/**
* Get an excerpt from a post.
*
* Generates a truncated version of the post content with
* HTML tags stripped.
*
* @since 1.0.0
*
* @param WP_Post $post The post object.
* @param int $length Maximum length of excerpt in characters. Default 100.
* @return string The post excerpt, truncated with '...' if needed.
*/
function get_post_excerpt(WP_Post $post, int $length = 100): string {
$content = strip_tags($post->post_content);
if (strlen($content) <= $length) {
return $content;
}
return substr($content, 0, $length) . '...';
}All questions answered immediately!
| Tag | Purpose | Example |
|---|---|---|
@param |
Parameter description | @param int $id The user ID |
@return |
Return value | @return bool True on success |
@var |
Variable type | @var string |
@since |
Version introduced | @since 1.0.0 |
@deprecated |
Mark as deprecated | @deprecated 2.0.0 Use new_method() instead |
| Tag | Purpose | Example |
|---|---|---|
@throws |
Exceptions thrown | @throws InvalidArgumentException |
@see |
Related items | @see PostRepository::find_by_id() |
@link |
External link | @link https://developer.wordpress.org/ |
@example |
Usage example | @example $repo->find_by_author(1, 5) |
@package |
Package name | @package MyPlugin\Posts |
@author |
Author | @author John Doe <john@example.com> |
| Tag | Purpose |
|---|---|
@since |
WordPress version introduced |
@global |
Global variable used |
@action |
WordPress action hook |
@filter |
WordPress filter hook |
WordPress has specific standards:
/**
* Retrieve the post title.
*
* If the post is protected and the visitor is not an admin, then "Protected"
* will be prepended to the post title. If the post is private, then "Private"
* will be prepended to the post title.
*
* @since 0.71
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return string The post title.
*/
function get_the_title($post = 0): string {Notice:
- Clear description of behavior
@sincetag (when introduced)@globalfor globals used- Full
@paramdocumentation - Specific
@returndescription
✅ Public classes
✅ Public methods
✅ Public functions
✅ Complex private methods
✅ Non-obvious behavior
✅ Arrays with specific structure
❌ Public API - Users need to know how to use it
❌ Complex logic - Future you will thank you
❌ Team projects - Others need to understand
/**
* Brief class description.
*
* @package MyPlugin
* @since 1.0.0
*/
class MyClass {/**
* Brief method description.
*
* @since 1.0.0
*
* @param type $param Description.
* @return type Description.
*/
public function method($param): type {/**
* Brief function description.
*
* @since 1.0.0
*
* @param type $param Description.
* @return type Description.
*/
function my_function($param): type {/**
* Brief property description.
*
* @var type
*/
private type $property;✅ Document all public APIs
✅ Use descriptive names - not generic ones
✅ Use @param for each parameter
✅ Use @return for return values
✅ Add @since version tags
✅ Document array structures with @type
✅ Name things clearly - PostRepository not DataManager
✅ Write for your future self
✅ Explain WHY, not just WHAT
❌ Don't use generic names like Handler, Manager, Data
❌ Don't abbreviate variable names ($p, $dm, $chk)
❌ Don't skip documentation "because it's obvious"
❌ Don't use vague method names (get(), fetch(), make())
❌ Don't document bad code instead of fixing it
❌ Don't let documentation get out of sync
❌ Don't write useless comments like @param int $id The ID
The code in bad.php and good.php has identical functionality.
The differences:
- bad.php - Generic names (
DataManager,Handler) + No documentation - good.php - Clear names (
PostRepository,PostService) + Complete documentation
// BAD: Generic name, ambiguous method, no docs
class DataManager {
public function fetch(int $user, int $num = 10, string $type = 'publish'): array {
// What does this return? How is it different from get()?
// What's the max for $num? What types are valid?
}
}
// GOOD: Descriptive name, clear method, documented
/**
* Repository for managing WordPress posts.
*/
class PostRepository {
/**
* Find posts by author.
*
* @param int $author_id The author's user ID.
* @param int $limit Maximum posts to return. Default 10. Max 100.
* @param string $status Post status to filter by. Default 'publish'.
* @return array Array of WP_Post objects.
*/
public function find_by_author(int $author_id, int $limit = 10, string $status = 'publish'): array {
// Everything is crystal clear!
}
}Which would you rather work with?
Good naming + Good documentation = Self-documenting code.
Name things clearly. Document thoroughly. Your team (and future you) will thank you.