350 && 0 === $heading_count ) {
$seo['long_content_without_headings'] = 1;
$score -= 8;
}
$long_paragraphs = 0;
if ( preg_match_all( '/]*>(.*?)<\/p>/is', $content, $paragraphs ) ) {
foreach ( $paragraphs[1] as $paragraph ) {
if ( str_word_count( wp_strip_all_tags( $paragraph ) ) > 130 ) {
$long_paragraphs++;
}
}
}
if ( $long_paragraphs > 0 ) {
$seo['long_paragraphs'] = $long_paragraphs;
$score -= min( 8, $long_paragraphs * 2 );
}
$empty_blocks = $this->count_pattern( '/<(p|div|span)\b[^>]*>\s*(?: |
)?\s*<\/\1>/i', $content );
if ( $empty_blocks > 0 ) {
$html['empty_blocks'] = $empty_blocks;
$score -= min( 10, $empty_blocks * 2 );
}
$div_span_count = $this->count_pattern( '/<(div|span)\b/i', $content );
$semantic_count = max( 1, $this->count_pattern( '/<(p|h[1-6]|ul|ol|li|blockquote|figure|table)\b/i', $content ) );
if ( $div_span_count > ( $semantic_count * 3 ) ) {
$html['too_many_wrappers'] = $div_span_count;
$score -= 8;
}
$markdown_artifacts = $this->count_pattern( '/(^|\s)(?:#{2,6}\s|\*\*[^*]+\*\*|```)/m', $content );
if ( $markdown_artifacts > 0 ) {
$seo['markdown_artifacts'] = $markdown_artifacts;
$html['markdown_artifacts'] = $markdown_artifacts;
$score -= min( 10, $markdown_artifacts * 3 );
}
if ( $words > 0 && $words < 120 ) {
$seo['very_short_content'] = 1;
$score -= 4;
}
$quality_level = 'excellent';
if ( $score < 60 ) {
$quality_level = 'poor';
} elseif ( $score < 75 ) {
$quality_level = 'needs_review';
} elseif ( $score < 90 ) {
$quality_level = 'good';
}
return array(
'score' => max( 0, min( 100, absint( $score ) ) ),
'level' => $quality_level,
'wordCount' => absint( $words ),
'accessibility' => array_filter( $accessibility ),
'seo' => array_filter( $seo ),
'html' => array_filter( $html ),
'warningCount' => count( array_filter( $accessibility ) ) + count( array_filter( $seo ) ) + count( array_filter( $html ) ),
);
}
/**
* Count regex matches safely.
*
* @param string $pattern Regular expression.
* @param string $subject Content to scan.
* @return int
*/
private function count_pattern( $pattern, $subject ) {
$count = preg_match_all( $pattern, $subject, $matches );
return false === $count ? 0 : absint( $count );
}
/**
* Enqueue admin assets only on settings and supported editor screens.
*
* @param string $hook Current admin page hook.
* @return void
*/
public function enqueue_admin_assets( $hook ) {
$plugin_admin_hooks = array_filter( array( $this->dashboard_hook, $this->settings_hook, $this->scan_hook ) );
if ( in_array( $hook, $plugin_admin_hooks, true ) ) {
wp_enqueue_style(
'agizohacu-admin',
AGIZOHACU_URL . 'assets/css/agizohacu-admin.css',
array(),
AGIZOHACU_VERSION
);
}
if ( $hook === $this->dashboard_hook || $hook === $this->settings_hook ) {
return;
}
if ( $hook === $this->scan_hook ) {
wp_enqueue_script(
'agizohacu-tools',
AGIZOHACU_URL . 'assets/js/agizohacu-tools.js',
array(),
AGIZOHACU_VERSION,
true
);
wp_localize_script(
'agizohacu-tools',
'agizohacuSiteScan',
array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'agizohacu_site_scan' ),
'action' => 'agizohacu_scan_posts',
'bulkAction' => 'agizohacu_bulk_clean_posts',
'bulkNonce' => wp_create_nonce( 'agizohacu_bulk_clean' ),
'modeLabels' => array_map( 'esc_html', $this->get_mode_labels() ),
'reportLabels' => array(
'comments' => esc_html__( 'HTML comments', 'agizoai-html-ai-clean-up' ),
'inlineSvg' => esc_html__( 'inline SVG blocks', 'agizoai-html-ai-clean-up' ),
'scriptStyleBlocks' => esc_html__( 'script, style or noscript blocks', 'agizoai-html-ai-clean-up' ),
'hiddenInputs' => esc_html__( 'hidden input fields', 'agizoai-html-ai-clean-up' ),
'hiddenElements' => esc_html__( 'hidden or invisible elements', 'agizoai-html-ai-clean-up' ),
'dataAttrs' => esc_html__( 'data-* attributes', 'agizoai-html-ai-clean-up' ),
'ariaAttrs' => esc_html__( 'aria-* attributes', 'agizoai-html-ai-clean-up' ),
'roleAttrs' => esc_html__( 'role attributes', 'agizoai-html-ai-clean-up' ),
'styleAttrs' => esc_html__( 'style attributes', 'agizoai-html-ai-clean-up' ),
'classOnDivs' => esc_html__( 'class attributes on div wrappers', 'agizoai-html-ai-clean-up' ),
'idOnDivs' => esc_html__( 'id attributes on div wrappers', 'agizoai-html-ai-clean-up' ),
'emptyAttrs' => esc_html__( 'empty attributes', 'agizoai-html-ai-clean-up' ),
'eventHandlerAttrs' => esc_html__( 'JavaScript event attributes', 'agizoai-html-ai-clean-up' ),
'xmlAttrs' => esc_html__( 'XML or namespace attributes', 'agizoai-html-ai-clean-up' ),
'msOfficeAttrs' => esc_html__( 'Microsoft Office formatting attributes/classes', 'agizoai-html-ai-clean-up' ),
),
'riskLabels' => array(
'clean' => esc_html__( 'Clean', 'agizoai-html-ai-clean-up' ),
'low' => esc_html__( 'Low', 'agizoai-html-ai-clean-up' ),
'medium' => esc_html__( 'Medium', 'agizoai-html-ai-clean-up' ),
'high' => esc_html__( 'High', 'agizoai-html-ai-clean-up' ),
),
'qualityLabels' => array(
'excellent' => esc_html__( 'Excellent', 'agizoai-html-ai-clean-up' ),
'good' => esc_html__( 'Good', 'agizoai-html-ai-clean-up' ),
'needs_review' => esc_html__( 'Needs review', 'agizoai-html-ai-clean-up' ),
'poor' => esc_html__( 'Poor', 'agizoai-html-ai-clean-up' ),
),
'messages' => array(
'scanning' => esc_html__( 'Scanning content. Please wait...', 'agizoai-html-ai-clean-up' ),
'complete' => esc_html__( 'Site-wide scan complete.', 'agizoai-html-ai-clean-up' ),
'failed' => esc_html__( 'Scan failed. Please refresh the page and try again.', 'agizoai-html-ai-clean-up' ),
'none' => esc_html__( 'No posts were found for this scan.', 'agizoai-html-ai-clean-up' ),
'openEditor' => esc_html__( 'Open editor', 'agizoai-html-ai-clean-up' ),
'itemsDetected' => esc_html__( 'items detected', 'agizoai-html-ai-clean-up' ),
'selectLabel' => esc_html__( 'Select', 'agizoai-html-ai-clean-up' ),
'selectAll' => esc_html__( 'Select all flagged posts', 'agizoai-html-ai-clean-up' ),
'cleaning' => esc_html__( 'Cleaning selected posts. Please wait...', 'agizoai-html-ai-clean-up' ),
'cleanComplete' => esc_html__( 'Selected post clean-up complete.', 'agizoai-html-ai-clean-up' ),
'cleanFailed' => esc_html__( 'Selected post clean-up failed. Please refresh the page and try again.', 'agizoai-html-ai-clean-up' ),
'noSelection' => esc_html__( 'Select at least one scanned post to clean.', 'agizoai-html-ai-clean-up' ),
'confirmBulk' => esc_html__( 'Clean the selected posts now? A revision backup will be created before each changed post is saved where revisions are supported.', 'agizoai-html-ai-clean-up' ),
'updatedLabel' => esc_html__( 'Updated', 'agizoai-html-ai-clean-up' ),
'skippedLabel' => esc_html__( 'Skipped', 'agizoai-html-ai-clean-up' ),
'failedLabel' => esc_html__( 'Failed', 'agizoai-html-ai-clean-up' ),
'revisionLabel' => esc_html__( 'Revision backup', 'agizoai-html-ai-clean-up' ),
'yesLabel' => esc_html__( 'Yes', 'agizoai-html-ai-clean-up' ),
'noLabel' => esc_html__( 'No', 'agizoai-html-ai-clean-up' ),
'beforeLabel' => esc_html__( 'Before', 'agizoai-html-ai-clean-up' ),
'afterLabel' => esc_html__( 'After', 'agizoai-html-ai-clean-up' ),
'scannedLabel' => esc_html__( 'Scanned', 'agizoai-html-ai-clean-up' ),
'flaggedLabel' => esc_html__( 'Needs review', 'agizoai-html-ai-clean-up' ),
'riskLabel' => esc_html__( 'Risk', 'agizoai-html-ai-clean-up' ),
'presetLabel' => esc_html__( 'Recommended preset', 'agizoai-html-ai-clean-up' ),
'qualityLabel' => esc_html__( 'HTML quality', 'agizoai-html-ai-clean-up' ),
'warningLabel' => esc_html__( 'Quality warnings', 'agizoai-html-ai-clean-up' ),
),
)
);
return;
}
if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ), true ) ) {
return;
}
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
if ( ! $screen || ! isset( $screen->post_type ) || ! in_array( $screen->post_type, $this->get_supported_post_types(), true ) ) {
return;
}
$post_type_object = get_post_type_object( $screen->post_type );
if ( $post_type_object && isset( $post_type_object->cap->edit_posts ) && ! current_user_can( $post_type_object->cap->edit_posts ) ) {
return;
}
$settings = $this->get_settings();
wp_enqueue_style(
'agizohacu-admin',
AGIZOHACU_URL . 'assets/css/agizohacu-admin.css',
array(),
AGIZOHACU_VERSION
);
wp_enqueue_script(
'agizohacu-admin',
AGIZOHACU_URL . 'assets/js/agizohacu-admin.js',
array(),
AGIZOHACU_VERSION,
true
);
$default_settings = $this->get_default_settings();
wp_localize_script(
'agizohacu-admin',
'agizohacuCleanHtml',
array(
'nonceFieldId' => 'agizohacu_clean_html_nonce',
'modeSelectId' => 'agizohacu-clean-mode',
'scanButtonId' => 'agizohacu-scan-html-button',
'previewButtonId' => 'agizohacu-preview-html-button',
'cleanSelectedButtonId' => 'agizohacu-clean-selected-button',
'qualityButtonId' => 'agizohacu-quality-check-button',
'cleanButtonId' => 'agizohacu-clean-html-button',
'undoButtonId' => 'agizohacu-undo-html-button',
'previewBoxId' => 'agizohacu-preview-box',
'previewRiskId' => 'agizohacu-preview-risk',
'previewListId' => 'agizohacu-preview-list',
'applyPreviewId' => 'agizohacu-apply-preview-button',
'copyCleanedId' => 'agizohacu-copy-cleaned-button',
'closePreviewId' => 'agizohacu-close-preview-button',
'qualityBoxId' => 'agizohacu-quality-box',
'qualityScoreId' => 'agizohacu-quality-score',
'qualityListId' => 'agizohacu-quality-list',
'statusId' => 'agizohacu-clean-html-status',
'defaultMode' => isset( $settings['default_mode'] ) ? sanitize_key( $settings['default_mode'] ) : 'auto',
'customRules' => isset( $settings['custom_rules'] ) && is_array( $settings['custom_rules'] ) ? array_map( 'rest_sanitize_boolean', $settings['custom_rules'] ) : $default_settings['custom_rules'],
'protectedRules' => isset( $settings['protected_rules'] ) && is_array( $settings['protected_rules'] ) ? array_map( 'rest_sanitize_boolean', $settings['protected_rules'] ) : $default_settings['protected_rules'],
'messages' => array(
'missingNonce' => esc_html__( 'Security token missing. Please refresh the editor page.', 'agizoai-html-ai-clean-up' ),
'cleaned' => esc_html__( 'HTML cleaned. Please review the content before saving.', 'agizoai-html-ai-clean-up' ),
'empty' => esc_html__( 'No editor content found to clean.', 'agizoai-html-ai-clean-up' ),
'nothingFound' => esc_html__( 'No removable AI/tool markup was found with the selected preset.', 'agizoai-html-ai-clean-up' ),
'scanComplete' => esc_html__( 'AI Paste Scan Report complete. No changes were applied.', 'agizoai-html-ai-clean-up' ),
'previewReady' => esc_html__( 'Preview ready. Review the report before applying the clean-up.', 'agizoai-html-ai-clean-up' ),
'undoReady' => esc_html__( 'Previous editor content restored. Review before saving.', 'agizoai-html-ai-clean-up' ),
'copyDone' => esc_html__( 'Cleaned HTML copied to clipboard.', 'agizoai-html-ai-clean-up' ),
'copyFailed' => esc_html__( 'Clipboard copy failed. You can still apply the previewed clean-up.', 'agizoai-html-ai-clean-up' ),
'selectedUnsupported'=> esc_html__( 'No selected block was found. Select a block in the block editor first.', 'agizoai-html-ai-clean-up' ),
'selectedCleaned' => esc_html__( 'Selected block cleaned. Please review the content before saving.', 'agizoai-html-ai-clean-up' ),
'autoDetected' => esc_html__( 'Auto Detect selected preset:', 'agizoai-html-ai-clean-up' ),
'riskLabel' => esc_html__( 'Risk level:', 'agizoai-html-ai-clean-up' ),
'recommendedLabel' => esc_html__( 'Recommended preset:', 'agizoai-html-ai-clean-up' ),
'protectedLabel' => esc_html__( 'Protected items kept intact:', 'agizoai-html-ai-clean-up' ),
'qualityComplete' => esc_html__( 'HTML quality check complete. No changes were applied.', 'agizoai-html-ai-clean-up' ),
'qualityScoreLabel' => esc_html__( 'HTML quality score:', 'agizoai-html-ai-clean-up' ),
'accessibilityLabel' => esc_html__( 'Accessibility warning:', 'agizoai-html-ai-clean-up' ),
'seoSafeLabel' => esc_html__( 'SEO-safe HTML check:', 'agizoai-html-ai-clean-up' ),
'htmlQualityLabel' => esc_html__( 'HTML structure check:', 'agizoai-html-ai-clean-up' ),
'noQualityIssues' => esc_html__( 'No major accessibility, SEO-safe HTML or structure issues were detected.', 'agizoai-html-ai-clean-up' ),
),
'reportLabels' => array(
'comments' => esc_html__( 'HTML comments', 'agizoai-html-ai-clean-up' ),
'inlineSvg' => esc_html__( 'inline SVG blocks', 'agizoai-html-ai-clean-up' ),
'scriptStyleBlocks' => esc_html__( 'script, style or noscript blocks', 'agizoai-html-ai-clean-up' ),
'hiddenInputs' => esc_html__( 'hidden input fields', 'agizoai-html-ai-clean-up' ),
'hiddenElements' => esc_html__( 'hidden or invisible elements', 'agizoai-html-ai-clean-up' ),
'dataAttrs' => esc_html__( 'data-* attributes', 'agizoai-html-ai-clean-up' ),
'ariaAttrs' => esc_html__( 'aria-* attributes', 'agizoai-html-ai-clean-up' ),
'roleAttrs' => esc_html__( 'role attributes', 'agizoai-html-ai-clean-up' ),
'styleAttrs' => esc_html__( 'style attributes', 'agizoai-html-ai-clean-up' ),
'classOnDivs' => esc_html__( 'class attributes on div wrappers', 'agizoai-html-ai-clean-up' ),
'idOnDivs' => esc_html__( 'id attributes on div wrappers', 'agizoai-html-ai-clean-up' ),
'emptyAttrs' => esc_html__( 'empty attributes', 'agizoai-html-ai-clean-up' ),
'eventHandlerAttrs' => esc_html__( 'JavaScript event attributes', 'agizoai-html-ai-clean-up' ),
'xmlAttrs' => esc_html__( 'XML or namespace attributes', 'agizoai-html-ai-clean-up' ),
'msOfficeAttrs' => esc_html__( 'Microsoft Office formatting attributes/classes', 'agizoai-html-ai-clean-up' ),
'disallowedTags' => esc_html__( 'disallowed tags removed by Strict Article Clean', 'agizoai-html-ai-clean-up' ),
'disallowedAttrs' => esc_html__( 'disallowed attributes removed by Strict Article Clean', 'agizoai-html-ai-clean-up' ),
),
'modeLabels' => array_map( 'esc_html', $this->get_mode_labels() ),
'riskLabels' => array(
'clean' => esc_html__( 'Clean', 'agizoai-html-ai-clean-up' ),
'low' => esc_html__( 'Low', 'agizoai-html-ai-clean-up' ),
'medium' => esc_html__( 'Medium', 'agizoai-html-ai-clean-up' ),
'high' => esc_html__( 'High', 'agizoai-html-ai-clean-up' ),
),
'qualityLabels' => array(
'excellent' => esc_html__( 'Excellent', 'agizoai-html-ai-clean-up' ),
'good' => esc_html__( 'Good', 'agizoai-html-ai-clean-up' ),
'needs_review' => esc_html__( 'Needs review', 'agizoai-html-ai-clean-up' ),
'poor' => esc_html__( 'Poor', 'agizoai-html-ai-clean-up' ),
),
'qualityIssueLabels' => array(
'imagesMissingAlt' => esc_html__( 'Images without alt text', 'agizoai-html-ai-clean-up' ),
'imagesEmptyAlt' => esc_html__( 'Images with empty alt text', 'agizoai-html-ai-clean-up' ),
'iframesMissingTitle' => esc_html__( 'Embeds or iframes without title attributes', 'agizoai-html-ai-clean-up' ),
'emptyLinks' => esc_html__( 'Links without visible text', 'agizoai-html-ai-clean-up' ),
'weakLinkText' => esc_html__( 'Weak link text such as click here or read more', 'agizoai-html-ai-clean-up' ),
'tablesWithoutHeaders' => esc_html__( 'Tables without header cells', 'agizoai-html-ai-clean-up' ),
'duplicateIds' => esc_html__( 'Duplicate HTML id attributes', 'agizoai-html-ai-clean-up' ),
'headingLevelJumps' => esc_html__( 'Skipped heading levels', 'agizoai-html-ai-clean-up' ),
'h1InPostContent' => esc_html__( 'H1 tags inside post content', 'agizoai-html-ai-clean-up' ),
'longContentWithoutHeadings'=> esc_html__( 'Long content without subheadings', 'agizoai-html-ai-clean-up' ),
'longParagraphs' => esc_html__( 'Long paragraphs that may hurt readability', 'agizoai-html-ai-clean-up' ),
'unsafeOrEmptyLinks' => esc_html__( 'Unsafe or empty links', 'agizoai-html-ai-clean-up' ),
'emptyBlocks' => esc_html__( 'Empty paragraphs or wrapper blocks', 'agizoai-html-ai-clean-up' ),
'tooManyWrappers' => esc_html__( 'Too many div or span wrappers', 'agizoai-html-ai-clean-up' ),
'markdownArtifacts' => esc_html__( 'Markdown artefacts left in HTML', 'agizoai-html-ai-clean-up' ),
'veryShortContent' => esc_html__( 'Very short content', 'agizoai-html-ai-clean-up' ),
'parserIssue' => esc_html__( 'HTML parser issue', 'agizoai-html-ai-clean-up' ),
),
)
);
}
}
AGIZOHACU_Plugin::instance();