ACPT Pro 2.1.6: what Rateo prints
The Rateo engine, run on ACPT Pro, a custom post type and fields plugin. Every number below comes from the engine's output, which is linked in full at the end.
ACPT Pro is made by the team behind Rateo. We ran it on our own code first.
- License
- GPL-2.0-or-later
- Source
- ACPT Pro release zip, available to customers
- Engine
2026.10.12- Rules
2026.10.7-provisional- Ran on
- 2026-10-16
- Zip SHA-256
613dd8ffa9c8f04ca05438a95105c4d021febd707559e14c2d0c73073ae4c1b3- Command
build/rateo advanced-custom-post-type --cache=none
from the folder the zip was extracted into
At a glance
- Files analysed
- 1,062
- Findings
- 3,480
- Errors
- 452
- Warnings
- 3,028
platform PHP: WordPress (plugin header in advanced-custom-post-type.php)
not analysed: 550 files (binary 271, JavaScript 215, CSS 35, Gettext Catalog 16, JSON 4, SVG 3, Markdown 2, INI 1, Ignore List 1, YAML 1, dist 1)
Folders and files not analysed, by reason: Dependency 2.
What it checks
Checked today
- Size: long files, classes and functions
- Complexity: functions and file level code with too many paths
- Naming: mixed styles in a file, generic, one letter and very long names
- Duplication: blocks repeated inside a file, even with renamed variables
- Security:
eval, shell commands, unserialize and includes built from data, SQL with values pasted in, request input never sanitized, output never escaped
Not checked yet
- WordPress rules: nonces and capability checks
The security checks read one call or statement at a time and never follow a value through variables, so they show where to look, not proof of a hole. A long or branchy function is common in a large, mature plugin; each finding is a place worth a closer look, not a judgement of the code as a whole.
Findings by check
A value equal to a limit is no finding.
Where they concentrate
The 10 files with the most findings
Findings per top level folder
Grades
BOverall: 82 out of 100
3 of 5 metrics graded
round((3 × 87Complexity+2 × 66Duplication+1 × 96Naming) ÷ 6) = 82
Weights: Complexity 3, Duplication 2, Naming 1. Size and Security are not graded, so they are left out and the other weights are rescaled.
A summary of the grades below, which you can recompute. Not a pass mark, and not a hiring decision.
The table shows how many files got each letter. A file with nothing to judge for a metric gets no grade for it. The whole plugin column pools every file's grade, so a file with more code to judge counts for more. The overall above weights those whole plugin grades. In the full engine output these are CodeLength, CyclomaticComplexity, Duplication, NamingConvention and Security.
Security
Findings only, never a grade: a wrong security grade would hurt more than none. A finding the author already silenced with a phpcs comment counts as suppressed, apart from Errors and Warnings, so you can tell reviewed code from unreviewed code.
Where to look first
Up to 10 places, Errors first, then Warnings, then by path and line. An Error means request input reaches the call or the output directly.
#1 advanced-custom-post-type/admin/templates/app.php:31
Warning security.unescaped_output
echo of `strtoupper(ACPT_SKIN)` is not escaped at output; escape where you print (esc_html, esc_attr, htmlspecialchars)
| 31 | <!-- ACPT <?php echo strtoupper(ACPT_SKIN); ?> SKIN --> |
| 32 | <style> |
| 33 | #wpfooter, #wpcontent { |
| 34 | background: <?php echo $footerBg; ?>; |
| 35 | color: <?php echo $footerColor; ?>; |
| 36 | } |
| 37 | |
| 38 | #wpfooter a { |
| 39 | color: <?php echo $footerLinkColor; ?>; |
| 40 | } |
#2 advanced-custom-post-type/admin/templates/app.php:34
Warning security.unescaped_output
echo of `$footerBg` is not escaped at output; escape where you print (esc_html, esc_attr, htmlspecialchars)
| 34 | background: <?php echo $footerBg; ?>; |
| 35 | color: <?php echo $footerColor; ?>; |
| 36 | } |
| 37 | |
| 38 | #wpfooter a { |
| 39 | color: <?php echo $footerLinkColor; ?>; |
| 40 | } |
| 41 | |
| 42 | #wpfooter a:hover, |
| 43 | #wpfooter a:focus { |
#3 advanced-custom-post-type/admin/templates/app.php:35
Warning security.unescaped_output
echo of `$footerColor` is not escaped at output; escape where you print (esc_html, esc_attr, htmlspecialchars)
| 35 | color: <?php echo $footerColor; ?>; |
| 36 | } |
| 37 | |
| 38 | #wpfooter a { |
| 39 | color: <?php echo $footerLinkColor; ?>; |
| 40 | } |
| 41 | |
| 42 | #wpfooter a:hover, |
| 43 | #wpfooter a:focus { |
| 44 | color: <?php echo $footerLinkHoverColor; ?>; |
#4 advanced-custom-post-type/admin/templates/app.php:39
Warning security.unescaped_output
echo of `$footerLinkColor` is not escaped at output; escape where you print (esc_html, esc_attr, htmlspecialchars)
| 39 | color: <?php echo $footerLinkColor; ?>; |
| 40 | } |
| 41 | |
| 42 | #wpfooter a:hover, |
| 43 | #wpfooter a:focus { |
| 44 | color: <?php echo $footerLinkHoverColor; ?>; |
| 45 | } |
| 46 | |
| 47 | ul#adminmenu a.wp-has-current-submenu:after { |
| 48 | border-right-color: <?php echo $footerBg; ?>; |
#5 advanced-custom-post-type/admin/templates/app.php:44
Warning security.unescaped_output
echo of `$footerLinkHoverColor` is not escaped at output; escape where you print (esc_html, esc_attr, htmlspecialchars)
| 44 | color: <?php echo $footerLinkHoverColor; ?>; |
| 45 | } |
| 46 | |
| 47 | ul#adminmenu a.wp-has-current-submenu:after { |
| 48 | border-right-color: <?php echo $footerBg; ?>; |
| 49 | } |
| 50 | </style> |
| 51 | <?php endif; ?> |
#6 advanced-custom-post-type/admin/templates/app.php:48
Warning security.unescaped_output
echo of `$footerBg` is not escaped at output; escape where you print (esc_html, esc_attr, htmlspecialchars)
| 48 | border-right-color: <?php echo $footerBg; ?>; |
| 49 | } |
| 50 | </style> |
| 51 | <?php endif; ?> |
#7 advanced-custom-post-type/migrations/202604010001_migrate_location_data_to_junction.php:76
| 76 | $columns = $wpdb->get_results("SHOW COLUMNS FROM `{$prefixedName}` LIKE 'location_rule'"); |
| 77 | |
| 78 | if (empty($columns)) { |
| 79 | continue; |
| 80 | } |
| 81 | |
| 82 | // Copy existing data to junction table |
| 83 | ACPT_DB::executeQueryOrThrowException( |
| 84 | "INSERT IGNORE INTO `{$junctionTable}` (table_name, record_id, location_rule, location_value) |
| 85 | SELECT %s, id, location_rule, location_value |
#8 advanced-custom-post-type/migrations/202604010001_migrate_location_data_to_junction.php:92
| 92 | $wpdb->query("ALTER TABLE `{$prefixedName}` DROP INDEX `idx_location`"); |
| 93 | $wpdb->query("ALTER TABLE `{$prefixedName}` DROP COLUMN `location_rule`, DROP COLUMN `location_value`"); |
| 94 | } |
| 95 | } |
| 96 | } |
#9 advanced-custom-post-type/migrations/202604010001_migrate_location_data_to_junction.php:93
| 93 | $wpdb->query("ALTER TABLE `{$prefixedName}` DROP COLUMN `location_rule`, DROP COLUMN `location_value`"); |
| 94 | } |
| 95 | } |
| 96 | } |
#10 advanced-custom-post-type/src/Admin/ACPT_Admin.php:379
| 379 | require_once plugin_dir_path(dirname(__FILE__)) . '../admin/templates/'.$template.'.php'; |
| 380 | }, |
| 381 | $position |
| 382 | ); |
| 383 | } else { |
| 384 | add_menu_page( |
| 385 | $pageTitle, |
| 386 | $menuTitle, |
| 387 | $capability, |
| 388 | $menuSlug, |
The 10 worst places
Security findings are listed in their own section above. A place is a file and a line, so a function that is both too long and too complex shows once, with both findings. Places rank by their worst finding: errors first, then by how far the measured value goes beyond its limit. Each message is the engine's own, word for word.
2 places are left out of this list because the engine flags them by mistake: advanced-custom-post-type/src/Includes/ACPT_Schema.php:19, the plugin's database tables written as one array of data, not logic; advanced-custom-post-type/src/Core/API/V1/Controllers/SchemaController.php:189, the plugin's API description written as one array of data, not logic. Their findings still count in the grades, the tables above and the full output.
#1 advanced-custom-post-type/src/Integrations/Bricks/providers/provider-acpt.php:699
Error complexity.function
Provider_ACPT::get_tag_value has a cyclomatic complexity of 298, untestable risk (above 10): each of its 298 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
Provider_ACPT::get_tag_value has 1104 lines in its body, above 100
| 699 | public function get_tag_value($tag, $post, $args, $context) |
| 700 | { |
| 701 | try { |
| 702 | // A Toggle without a value must not reuse the previous loop item's (#1419) |
| 703 | unset(self::$condition_toggle_values[$tag]); |
| 704 | |
| 705 | if (!isset($this->tags[$tag])) { |
| 706 | return null; |
| 707 | } |
| 708 | |
#2 advanced-custom-post-type/src/Integrations/Gutenberg/Generators/ACPTBlocks/Blocks/RepeaterLoopBlockRenderer.php:282
Error complexity.function
RepeaterLoopBlockRenderer::realValue has a cyclomatic complexity of 264, untestable risk (above 10): each of its 264 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
RepeaterLoopBlockRenderer::realValue has 751 lines in its body, above 100
| 282 | private function realValue(string $fieldType, $rawValue, array $parsed = [], $before = null, $after = null) |
| 283 | { |
| 284 | $raw = $parsed['raw'] ?? false; |
| 285 | $subKey = $parsed['subKey'] ?? null; |
| 286 | $args = $parsed['args'] ?? []; |
| 287 | |
| 288 | // Legacy: if $parsed is a plain array of args (old callers), keep working |
| 289 | if (isset($parsed[0])) { |
| 290 | $args = $parsed; |
| 291 | $raw = false; |
#3 advanced-custom-post-type/src/Integrations/Gutenberg/Generators/ACPTBlocks/Blocks/BasicBlockRenderer.php:65
Error complexity.function
BasicBlockRenderer::getRawData has a cyclomatic complexity of 260, untestable risk (above 10): each of its 260 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
BasicBlockRenderer::getRawData has 877 lines in its body, above 100
| 65 | private function getRawData(array $field, array $attributes = []) |
| 66 | { |
| 67 | $findValue = null; |
| 68 | |
| 69 | // try to calculate $find and $findValue |
| 70 | if (isset($field['belongsTo']) && $field['belongsTo'] === MetaTypes::OPTION_PAGE) { |
| 71 | $findValue = $field['find']; |
| 72 | $find = 'option_page'; |
| 73 | } elseif (isset($field['belongsTo']) && $field['belongsTo'] === MetaTypes::TAXONOMY) { |
| 74 | $find = 'term_id'; |
#4 advanced-custom-post-type/src/Core/CQRS/Command/SaveMetaFieldValueCommand.php:73
Error complexity.function
SaveMetaFieldValueCommand::execute has a cyclomatic complexity of 210, untestable risk (above 10): each of its 210 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
SaveMetaFieldValueCommand::execute has 977 lines in its body, above 100
| 73 | public function execute(): bool |
| 74 | { |
| 75 | $metaFieldModelType = $this->fieldModel->getType(); |
| 76 | $savedFieldValue = $this->get($this->fieldModel->getDbName()); |
| 77 | $savedFieldType = $this->get($this->fieldModel->getDbName().'_type'); |
| 78 | $savedFieldId = $this->get($this->fieldModel->getDbName().'_id'); |
| 79 | $value = self::objectsToIds($this->args['value'] ?? null); |
| 80 | |
| 81 | // check is value is changed, if not, do nothing and return true |
| 82 | if ($savedFieldValue == $value) { |
#5 advanced-custom-post-type/src/Integrations/Divi/includes/ACPT_Divi_Dynamic_Content_Tags.php:284
Error complexity.function
ACPT_Divi_Dynamic_Content_Tags::renderField has a cyclomatic complexity of 178, untestable risk (above 10): each of its 178 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
ACPT_Divi_Dynamic_Content_Tags::renderField has 626 lines in its body, above 100
Warning naming.inconsistent_style
method `renderField` is camelCase, while most methods in this file are snake_case (5 of 9 names); mixed styles make code harder to scan
| 284 | private function renderField( |
| 285 | string $fieldType, |
| 286 | $val, |
| 287 | ?string $pfx, |
| 288 | ?string $sfx, |
| 289 | string $display_as, |
| 290 | string $list_style, |
| 291 | string $enable_html, |
| 292 | ?string $date_format, |
| 293 | ?string $custom_date_format, |
#6 advanced-custom-post-type/src/Core/Generators/Table/TableRecordPageGenerator.php:1174
Error complexity.function
TableRecordPageGenerator::locationRuleOptions has a cyclomatic complexity of 152, untestable risk (above 10): each of its 152 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
TableRecordPageGenerator::locationRuleOptions has 446 lines in its body, above 100
| 1174 | protected function locationRuleOptions(array $location = [], string $ruleKey = ''): string |
| 1175 | { |
| 1176 | $selectedKey = $ruleKey; |
| 1177 | |
| 1178 | $postTypes = []; |
| 1179 | $taxonomies = []; |
| 1180 | $optionPages = []; |
| 1181 | $mediaFormats = []; |
| 1182 | $userIds = []; |
| 1183 | $valueless = []; |
#7 advanced-custom-post-type/src/Core/CQRS/Query/FetchMetaFieldValueQuery.php:30
Error complexity.function
FetchMetaFieldValueQuery::execute has a cyclomatic complexity of 141, untestable risk (above 10): each of its 141 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
FetchMetaFieldValueQuery::execute has 699 lines in its body, above 100
| 30 | public function execute() |
| 31 | { |
| 32 | // Prevent any error if one of those functions is undefined: |
| 33 | if (!function_exists('get_user_by')) { |
| 34 | include_once(ABSPATH . 'wp-includes/pluggable.php'); |
| 35 | } |
| 36 | |
| 37 | if (!function_exists('get_term')) { |
| 38 | include_once(ABSPATH . 'wp-includes/taxonomy.php'); |
| 39 | } |
#8 advanced-custom-post-type/src/Utils/Checker/FieldVisibilityChecker.php:99
Error complexity.function
FieldVisibilityChecker::returnTrueOrFalseForALogicBlock has a cyclomatic complexity of 137, untestable risk (above 10): each of its 137 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
FieldVisibilityChecker::returnTrueOrFalseForALogicBlock has 477 lines in its body, above 100
Warning naming.too_long
method `returnTrueOrFalseForALogicBlock` is 31 characters (limit 30); very long names make code hard to read
| 99 | private static function returnTrueOrFalseForALogicBlock( |
| 100 | $elementId, |
| 101 | string $belongsTo, |
| 102 | MetaFieldModel $metaBoxFieldModel, |
| 103 | array $conditions, |
| 104 | array $liveData = [], |
| 105 | ?int $fieldIndex = null, |
| 106 | ?string $blockName = null, |
| 107 | ?int $blockIndex = null |
| 108 | ): bool { |
#9 advanced-custom-post-type/src/Core/Generators/CustomPostType/CustomPostTypeAdminColumnsGenerator.php:37
Error complexity.function
CustomPostTypeAdminColumnsGenerator::addColumns has a cyclomatic complexity of 131, untestable risk (above 10): each of its 131 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
CustomPostTypeAdminColumnsGenerator::addColumns has 523 lines in its body, above 100
| 37 | public static function addColumns($postTypeModel): void |
| 38 | { |
| 39 | $postTypeName = ($postTypeModel instanceof CustomPostTypeModel) ? $postTypeModel->getName() : $postTypeModel; |
| 40 | |
| 41 | $manageEditAction = 'manage_edit-'.$postTypeName.'_columns'; |
| 42 | $manageEditSortAction = 'manage_edit-'.$postTypeName.'_sortable_columns'; |
| 43 | $customColumnsAction = 'manage_'.$postTypeName.'_posts_custom_column'; |
| 44 | $bulkActionsAction = 'bulk_actions-edit-'.$postTypeName; |
| 45 | |
| 46 | // Specific fix for Media attachments |
#10 advanced-custom-post-type/src/Core/Helper/CCTFieldShape.php:263
Error complexity.function
CCTFieldShape::coerce has a cyclomatic complexity of 130, untestable risk (above 10): each of its 130 paths needs its own test, which makes it hard to follow and to change safely
Error length.function
CCTFieldShape::coerce has 281 lines in its body, above 100
| 263 | public static function coerce($oldValue, string $targetUiType) |
| 264 | { |
| 265 | if ($oldValue === null || $oldValue === '') { |
| 266 | return null; |
| 267 | } |
| 268 | |
| 269 | // Decode JSON strings |
| 270 | if (is_string($oldValue) && self::looksLikeJson($oldValue)) { |
| 271 | $oldValue = json_decode($oldValue, true); |
| 272 | } |
Full engine output
All 3,480 findings, plus 8 suppressed by a phpcs comment, exactly as the engine printed them: wordpress-acpt.txt (plain text).