Changeset 3790684
- Timestamp:
- 11/08/2026 08:27:28 AM (5 hours ago)
- Location:
- equalfix
- Files:
-
- 6 edited
- 1 copied
-
tags/1.10.4 (copied) (copied from equalfix/trunk )
-
tags/1.10.4/equalfix-accessibility.php (modified) (2 diffs)
-
tags/1.10.4/includes/class-equalfix-settings.php (modified) (12 diffs)
-
tags/1.10.4/readme.txt (modified) (2 diffs)
-
trunk/equalfix-accessibility.php (modified) (2 diffs)
-
trunk/includes/class-equalfix-settings.php (modified) (12 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
equalfix/tags/1.10.4/equalfix-accessibility.php
r3790639 r3790684 4 4 * Plugin URI: https://equalfix.com 5 5 * Description: Helps improve your site's accessibility by detecting specific issues and applying safe, reversible fixes to the rendered HTML. Includes a full site audit, the free fix set, and per-fix-type preview and toggle controls. 6 * Version: 1.10. 36 * Version: 1.10.4 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 7.4 … … 23 23 } 24 24 25 define( 'EQUALFIX_VERSION', '1.10. 3' );25 define( 'EQUALFIX_VERSION', '1.10.4' ); 26 26 define( 'EQUALFIX_FILE', __FILE__ ); 27 27 define( 'EQUALFIX_DIR', plugin_dir_path( __FILE__ ) ); -
equalfix/tags/1.10.4/includes/class-equalfix-settings.php
r3790639 r3790684 6012 6012 $only = ''; 6013 6013 } 6014 $oneclick_n = $this->issues_oneclick_count( $result, $model, $settings ); 6014 $oneclick_stats = $this->issues_oneclick_stats( $result, $model, $settings ); 6015 $oneclick_n = $oneclick_stats['count']; 6015 6016 6016 6017 if ( 'flagged' === $view || 'aside' === $view || 'fixed' === $view ) { … … 6054 6055 $this->render_issues_heading( $result ); 6055 6056 if ( $model['d_total'] > 0 ) { 6056 $this->render_issues_summary( $result, $model, $settings, $oneclick_ n);6057 $this->render_issues_summary( $result, $model, $settings, $oneclick_stats ); 6057 6058 } 6058 6059 if ( 'all' === $view && ! $all_on ) { … … 6169 6170 // the same predicate, so the chip, the tile and 6170 6171 // this list can never disagree. 6171 $cards_list = array(); 6172 $manual_map = self::manual_matches_map( $result ); 6173 $attr_map = self::attr_matches_map( $result ); 6172 $cards_list = array(); 6173 $manual_map = self::manual_matches_map( $result ); 6174 $attr_map = self::attr_matches_map( $result ); 6175 $oneclick_ctx = $this->oneclick_proposal_ctx( $result ); 6174 6176 foreach ( $list as $oneclick_finding ) { 6175 if ( $this->is_oneclick_finding( $oneclick_finding, $model, $settings, $manual_map, $attr_map ) ) {6177 if ( $this->is_oneclick_finding( $oneclick_finding, $model, $settings, $manual_map, $attr_map, $oneclick_ctx ) ) { 6176 6178 $cards_list[] = $oneclick_finding; 6177 6179 } 6178 6180 } 6179 6181 ?> 6180 <p class="eqf-filter-note"><?php esc_html_e( 'Showing only the problems th e free fix set can fixin one click.', 'equalfix' ); ?> <a href="<?php echo esc_url( $this->tab_url( 'issues', array( 'view' => $view ) ) ); ?>"><?php esc_html_e( 'Show everything', 'equalfix' ); ?></a></p>6182 <p class="eqf-filter-note"><?php esc_html_e( 'Showing only the problems that can be fixed in one click.', 'equalfix' ); ?> <a href="<?php echo esc_url( $this->tab_url( 'issues', array( 'view' => $view ) ) ); ?>"><?php esc_html_e( 'Show everything', 'equalfix' ); ?></a></p> 6181 6183 <?php 6182 6184 } … … 6353 6355 * partition already). 6354 6356 * 6355 * @param array $finding Finding. 6356 * @param array $model Coverage model. 6357 * @param array $settings Settings. 6358 * @param array $manual_map manual_matches_map() result. 6357 * Counter-wording batch (2026-11-08): when the caller 6358 * passes the proposal context, a finding ALSO qualifies 6359 * when a computed proposal is available for it — the 6360 * owner can fix it with one click and no typing (the 6361 * group's own Fix action), which is what the strip and 6362 * the chip promise. Callers that omit the context get 6363 * exactly the shipped press-only semantics (the hero 6364 * button's own count uses that narrower set — its press 6365 * applies the standard set and nothing else). 6366 * 6367 * @param array $finding Finding. 6368 * @param array $model Coverage model. 6369 * @param array $settings Settings. 6370 * @param array $manual_map manual_matches_map() result. 6371 * @param array $attr_map attr_matches_map() result. 6372 * @param array|null $ctx oneclick_proposal_ctx() 6373 * result, or null for the 6374 * press-only predicate. 6359 6375 * @return bool 6360 6376 */ 6361 private function is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map = array() ) {6377 private function is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map = array(), $ctx = null ) { 6362 6378 $fp = self::finding_fingerprint( $finding ); 6363 6379 if ( isset( $model['fixed_fps'][ $fp ] ) || isset( $model['waiting_fps'][ $fp ] ) ) { … … 6370 6386 // same master switch the press turns on. 6371 6387 if ( isset( $attr_map[ $fp ] ) ) { 6388 return true; 6389 } 6390 // A computed proposal (Fix-First) the owner can apply 6391 // with one click and no typing — the same per-row 6392 // availability the bands and row panels use. 6393 if ( null !== $ctx && $this->finding_has_oneclick_proposal( $finding, $ctx ) ) { 6372 6394 return true; 6373 6395 } … … 6387 6409 6388 6410 /** 6389 * The DISTINCT problems one press of Apply Standard Fixes 6390 * would clear — the summary strip's hero number and the 6391 * "One-click fixes" chip count. Same predicate as the 6392 * filtered list (is_oneclick_finding()), counted in the 6393 * model's problem unit, so tile, chip and list agree. 6394 * 6395 * @param array $result Stored audit result. 6396 * @param array $model Coverage model. 6397 * @param array $settings Settings. 6398 * @return int 6399 */ 6400 private function issues_oneclick_count( $result, $model, $settings ) { 6401 if ( ! is_array( $result ) || empty( $result['findings'] ) ) { 6402 return 0; 6403 } 6411 * The Pro-side state the proposal test reads (counter- 6412 * wording batch, 2026-11-08): licence activity, the Pro 6413 * fix set's master/type state, and Pro coverage's 6414 * "would fix if applied" map — the same reads the fix-b 6415 * bands and rows render from, computed once per render 6416 * instead of once per finding. 6417 * 6418 * @param array $result Stored audit result. 6419 * @return array { licence_active: bool, pro_master_on: 6420 * bool, headings_type_on: bool, 6421 * fixed_if_on: array } 6422 */ 6423 private function oneclick_proposal_ctx( $result ) { 6424 $pro = self::pro_state(); 6425 $ctx = array( 6426 'licence_active' => ! empty( $pro['licence_active'] ), 6427 'pro_master_on' => false, 6428 'headings_type_on' => false, 6429 'fixed_if_on' => array(), 6430 ); 6431 if ( ! $ctx['licence_active'] ) { 6432 return $ctx; 6433 } 6434 if ( class_exists( 'EqualFix_Pro_Settings' ) && method_exists( 'EqualFix_Pro_Settings', 'fix_set_state' ) && class_exists( 'EqualFix_Pro_Fixer' ) ) { 6435 $fix_set = EqualFix_Pro_Settings::fix_set_state(); 6436 $ctx['pro_master_on'] = ! empty( $fix_set['master_on'] ); 6437 $ctx['headings_type_on'] = ! empty( $fix_set['types'][ EqualFix_Pro_Fixer::FIX_HEADINGS ] ); 6438 } 6439 $coverage = $this->pro_coverage( $result ); 6440 if ( null !== $coverage ) { 6441 $ctx['fixed_if_on'] = $coverage['fixed_if_on']; 6442 } 6443 return $ctx; 6444 } 6445 6446 /** 6447 * Whether a computed proposal is available for this 6448 * finding — one click, no typing (counter-wording batch, 6449 * 2026-11-08). This mirrors the availability the bands 6450 * and rows already render, group by group: 6451 * - attribute-rule groups: the proposal builder itself 6452 * (a proposal flagged needs-text is the owner's words, 6453 * not a computed fix, and never counts); 6454 * - page titles: the page-title proposal (post title or 6455 * site name, prefilled in the panel); 6456 * - embeds: the band's bulk action saves the provider- 6457 * derived title for every embed — computed, no typing; 6458 * - headings (Pro): only while the licence is active — 6459 * the finding is in Pro coverage's "would fix if 6460 * applied" map (the band's Apply press fixes exactly 6461 * that set), or the set and type are both on, when 6462 * every remaining skip's row offers the per-page 6463 * full-correction approval. 6464 * Everything else — owner-words groups, media captions 6465 * and transcripts the owner must supply, the honest 6466 * exceptions — has no computed proposal by design. 6467 * 6468 * @param array $finding Finding. 6469 * @param array $ctx oneclick_proposal_ctx() result. 6470 * @return bool 6471 */ 6472 private function finding_has_oneclick_proposal( $finding, $ctx ) { 6473 $meta = $this->finding_job_meta( $finding ); 6474 $group = $meta['group']; 6475 if ( in_array( $group, self::attr_groups(), true ) ) { 6476 $proposal = $this->attr_proposal_for_finding( $finding ); 6477 return null !== $proposal && empty( $proposal['needs_text'] ); 6478 } 6479 if ( 'page-title' === $group ) { 6480 return null !== $this->pagetitle_proposal_for_finding( $finding ); 6481 } 6482 if ( 'embed-3p' === $group || 'embed-title' === $group ) { 6483 return true; 6484 } 6485 if ( 'headings' === $group ) { 6486 if ( empty( $ctx['licence_active'] ) ) { 6487 return false; 6488 } 6489 $fp = self::finding_fingerprint( $finding ); 6490 return isset( $ctx['fixed_if_on'][ $fp ] ) || ( ! empty( $ctx['pro_master_on'] ) && ! empty( $ctx['headings_type_on'] ) ); 6491 } 6492 return false; 6493 } 6494 6495 /** 6496 * The DISTINCT-problem identity set behind the one-click 6497 * counts: every problem with at least one qualifying 6498 * finding (is_oneclick_finding()), in the model's problem 6499 * unit, so tile, chip and list agree. With proposals off 6500 * this is exactly the shipped press-only set. 6501 * 6502 * @param array $result Stored audit result. 6503 * @param array $model Coverage model. 6504 * @param array $settings Settings. 6505 * @param bool $with_proposals Include computed-proposal 6506 * problems. 6507 * @return array Identity => true. 6508 */ 6509 private function oneclick_ids( $result, $model, $settings, $with_proposals ) { 6404 6510 $manual_map = self::manual_matches_map( $result ); 6405 6511 $attr_map = self::attr_matches_map( $result ); 6512 $ctx = $with_proposals ? $this->oneclick_proposal_ctx( $result ) : null; 6406 6513 $dismissed = self::dismissed_map(); 6407 6514 $ids = array(); … … 6410 6517 continue; 6411 6518 } 6412 if ( $this->is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map ) ) {6519 if ( $this->is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map, $ctx ) ) { 6413 6520 list( , $identity ) = $this->problem_identity( $finding ); 6414 6521 $ids[ $identity ] = true; 6415 6522 } 6416 6523 } 6417 return count( $ids ); 6524 return $ids; 6525 } 6526 6527 /** 6528 * The DISTINCT problems that can be fixed in one click — 6529 * the summary strip's hero number and the "One-click 6530 * fixes" chip count (counter-wording batch, 2026-11-08): 6531 * the problems one press of Apply Standard Fixes would 6532 * clear PLUS the problems carrying a computed proposal 6533 * (finding_has_oneclick_proposal()). Same predicate as 6534 * the filtered list, counted in the model's problem 6535 * unit, so tile, chip and list agree. 6536 * 6537 * @param array $result Stored audit result. 6538 * @param array $model Coverage model. 6539 * @param array $settings Settings. 6540 * @return int 6541 */ 6542 private function issues_oneclick_count( $result, $model, $settings ) { 6543 if ( ! is_array( $result ) || empty( $result['findings'] ) ) { 6544 return 0; 6545 } 6546 return count( $this->oneclick_ids( $result, $model, $settings, true ) ); 6547 } 6548 6549 /** 6550 * The one-click figures the summary strip renders 6551 * (counter-wording batch, 2026-11-08), computed in one 6552 * pass so the tiles can never disagree: 6553 * - count: the widened one-click set (issues_oneclick_ 6554 * count()); 6555 * - press: the narrower shipped set the hero button's 6556 * own press (apply_standard_fixes) would clear — the 6557 * button is labelled with THIS number only; 6558 * - review_left: review-bucket problems (the model's 6559 * problem_buckets) that are NOT in the widened set — 6560 * the problems that genuinely still need the owner. 6561 * Equals d_review whenever no review problem carries 6562 * a proposal, which is how the strip knows the shipped 6563 * review wording still holds. 6564 * 6565 * @param array $result Stored audit result. 6566 * @param array $model Coverage model. 6567 * @param array $settings Settings. 6568 * @return array { count: int, press: int, review_left: int } 6569 */ 6570 private function issues_oneclick_stats( $result, $model, $settings ) { 6571 $stats = array( 6572 'count' => 0, 6573 'press' => 0, 6574 'review_left' => (int) $model['d_review'], 6575 ); 6576 if ( ! is_array( $result ) || empty( $result['findings'] ) ) { 6577 return $stats; 6578 } 6579 $ids = $this->oneclick_ids( $result, $model, $settings, true ); 6580 $stats['count'] = count( $ids ); 6581 $stats['press'] = count( $this->oneclick_ids( $result, $model, $settings, false ) ); 6582 $left = 0; 6583 foreach ( (array) $model['problem_buckets'] as $identity => $bucket ) { 6584 if ( 'review' === $bucket && ! isset( $ids[ $identity ] ) ) { 6585 $left++; 6586 } 6587 } 6588 $stats['review_left'] = $left; 6589 return $stats; 6418 6590 } 6419 6591 … … 6422 6594 * three tiles over the ONE coverage model — problems 6423 6595 * still to do (d_todo), the one-click count with the real 6424 * Apply Standard Fixes form, and the review count 6425 * (d_review) — over a progress bar, with the fixed note 6426 * and the problems-vs-findings footnote in plain words. 6427 * No number here is computed anywhere else. 6428 * 6429 * @param array $result Stored audit result. 6430 * @param array $model Coverage model. 6431 * @param array $settings Settings. 6432 * @param int $oneclick_n issues_oneclick_count(). 6433 */ 6434 private function render_issues_summary( $result, $model, $settings, $oneclick_n ) { 6596 * Apply Standard Fixes form, and the review count — over 6597 * a progress bar, with the fixed note and the problems- 6598 * vs-findings footnote in plain words. No number here is 6599 * computed anywhere else. 6600 * 6601 * Counter-wording batch (2026-11-08): the hero tile's 6602 * headline is the WIDENED one-click count (press set + 6603 * computed proposals), but its form posts 6604 * apply_standard_fixes, so the button keeps the PRESS 6605 * count and renders only when that count is non-zero — 6606 * the button must never promise the proposal problems. 6607 * The review tile counts the review problems with NO 6608 * proposal (review_left): while that equals d_review the 6609 * shipped wording stands exactly as written; once some 6610 * review problems carry a fix, the tile switches to the 6611 * neutral wording for the remainder only. 6612 * 6613 * @param array $result Stored audit result. 6614 * @param array $model Coverage model. 6615 * @param array $settings Settings. 6616 * @param array $oneclick_stats issues_oneclick_stats(). 6617 */ 6618 private function render_issues_summary( $result, $model, $settings, $oneclick_stats ) { 6619 $oneclick_n = (int) $oneclick_stats['count']; 6620 $press_n = (int) $oneclick_stats['press']; 6621 $review_left = (int) $oneclick_stats['review_left']; 6435 6622 $pct = $model['d_total'] > 0 ? (int) round( 100 * $model['d_fixed'] / $model['d_total'] ) : 0; 6436 6623 ?> … … 6448 6635 <div class="eqf-tile eqf-tile-hero"> 6449 6636 <?php if ( $oneclick_n > 0 ) : ?> 6450 <div class="eqf-tile-big"><?php echo esc_html( sprintf( /* translators: %d: problems one press fixes*/ _n( '%d can be fixed in one click', '%d can be fixed in one click', $oneclick_n, 'equalfix' ), $oneclick_n ) ); ?></div>6637 <div class="eqf-tile-big"><?php echo esc_html( sprintf( /* translators: %d: problems fixable in one click */ _n( '%d can be fixed in one click', '%d can be fixed in one click', $oneclick_n, 'equalfix' ), $oneclick_n ) ); ?></div> 6451 6638 <div class="eqf-tile-lbl"><?php esc_html_e( 'EqualFix already knows how to fix these safely.', 'equalfix' ); ?></div> 6639 <?php if ( $press_n > 0 ) : ?> 6452 6640 <div class="eqf-tile-act"> 6453 6641 <form method="post" action=""> 6454 6642 <?php wp_nonce_field( 'equalfix_settings' ); ?> 6455 6643 <input type="hidden" name="equalfix_action" value="apply_standard_fixes"> 6456 <button type="submit" class="button button-primary"><?php echo esc_html( sprintf( /* translators: %d: problems one press fixes */ _n( 'Fix all %d now', 'Fix all %d now', $ oneclick_n, 'equalfix' ), $oneclick_n ) ); ?></button>6644 <button type="submit" class="button button-primary"><?php echo esc_html( sprintf( /* translators: %d: problems one press fixes */ _n( 'Fix all %d now', 'Fix all %d now', $press_n, 'equalfix' ), $press_n ) ); ?></button> 6457 6645 </form> 6458 6646 </div> 6647 <?php endif; ?> 6459 6648 <?php else : ?> 6460 6649 <div class="eqf-tile-big"><?php esc_html_e( '0 can be fixed in one click', 'equalfix' ); ?></div> … … 6463 6652 </div> 6464 6653 <div class="eqf-tile"> 6465 <div class="eqf-tile-big"><?php echo (int) $model['d_review']; ?></div> 6466 <div class="eqf-tile-lbl"><?php echo esc_html( _n( 'needs a quick look from you — no automatic fix is safe here', 'need a quick look from you — no automatic fix is safe here', (int) $model['d_review'], 'equalfix' ) ); ?></div> 6654 <div class="eqf-tile-big"><?php echo $review_left; ?></div> 6655 <div class="eqf-tile-lbl"><?php echo esc_html( $review_left === (int) $model['d_review'] 6656 ? _n( 'needs a quick look from you — no automatic fix is safe here', 'need a quick look from you — no automatic fix is safe here', $review_left, 'equalfix' ) 6657 : _n( 'needs a quick look from you — this one needs your input', 'need a quick look from you — these need your input', $review_left, 'equalfix' ) ); ?></div> 6467 6658 <div class="eqf-tile-act"><a class="button eqf-btn-ghost" href="<?php echo esc_url( $this->tab_url( 'issues', array( 'view' => 'todo' ) ) ); ?>"><?php esc_html_e( 'Start reviewing', 'equalfix' ); ?></a></div> 6468 6659 </div> … … 7598 7789 $is_review_group = in_array( $group['meta']['group'], self::REVIEW_GROUPS, true ); 7599 7790 if ( $group['d_todo'] > 0 ) { 7791 // Counter-wording batch (2026-11-08): a 7792 // review-bucket group whose problems carry 7793 // a computed fix (has_proposals — the same 7794 // gate as the band's Fix all) is not 7795 // "for your review" any more; the bucket 7796 // itself is unchanged — the problems stay 7797 // in review until the fix is applied. 7600 7798 $count_line = $is_review_group 7601 ? sprintf( _n( '%d problem for your review', '%d problems for your review', $group['d_todo'], 'equalfix' ), $group['d_todo'] ) 7799 ? ( ! empty( $group['has_proposals'] ) 7800 ? sprintf( _n( '%d problem — a fix is ready', '%d problems — a fix is ready', $group['d_todo'], 'equalfix' ), $group['d_todo'] ) 7801 : sprintf( _n( '%d problem for your review', '%d problems for your review', $group['d_todo'], 'equalfix' ), $group['d_todo'] ) ) 7602 7802 : sprintf( _n( '%d problem still to do', '%d problems still to do', $group['d_todo'], 'equalfix' ), $group['d_todo'] ); 7603 7803 } else { … … 7651 7851 ?> 7652 7852 <tr class="eqf-band" id="eqf-group-<?php echo esc_attr( $meta['group'] ); ?>"><td colspan="4"><div class="eqf-band-in"> 7653 <span class="eqf-band-name"><?php echo esc_html( $this->issue_display_title( $meta['group'], $meta['name'] ) ); ?></span><?php if ( 'oneclick' === $card_tag ) : ?><span class="eqf-tag eqf-tag-oneclick"><?php esc_html_e( 'One-click fix', 'equalfix' ); ?></span><?php elseif ( 'pro' === $card_tag ) : ?><span class="eqf-tag eqf-tag-pro"><?php esc_html_e( 'Pro', 'equalfix' ); ?></span><?php endif; ?><?php if ( $is_review_group ) : ?><span class="eqf-badge eqf-badge-review"><?php esc_html_e( 'Needs human review', 'equalfix' ); ?></span><?php endif; ?>7853 <span class="eqf-band-name"><?php echo esc_html( $this->issue_display_title( $meta['group'], $meta['name'] ) ); ?></span><?php if ( 'oneclick' === $card_tag ) : ?><span class="eqf-tag eqf-tag-oneclick"><?php esc_html_e( 'One-click fix', 'equalfix' ); ?></span><?php elseif ( 'pro' === $card_tag ) : ?><span class="eqf-tag eqf-tag-pro"><?php esc_html_e( 'Pro', 'equalfix' ); ?></span><?php endif; ?><?php if ( $is_review_group && empty( $group['has_proposals'] ) ) : ?><span class="eqf-badge eqf-badge-review"><?php esc_html_e( 'Needs human review', 'equalfix' ); ?></span><?php endif; ?> 7654 7854 <span class="eqf-band-count"><?php echo esc_html( $count_line ); ?></span> 7655 7855 <?php $this->render_card_action( $group, $meta, $ctx_group, $skip_map, $open, $pro ); ?> -
equalfix/tags/1.10.4/readme.txt
r3790639 r3790684 5 5 Tested up to: 7.1 6 6 Requires PHP: 7.4 7 Stable tag: 1.10. 37 Stable tag: 1.10.4 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 99 99 == Changelog == 100 100 101 = 1.10.4 = 102 * Fixed: the Issues summary now counts every problem that already has a fix ready (including the computed fixes), so the one-click count matches the Fix all buttons below it. 103 101 104 = 1.10.3 = 102 105 * The Issues tab is now one compact, scrollable table. -
equalfix/trunk/equalfix-accessibility.php
r3790639 r3790684 4 4 * Plugin URI: https://equalfix.com 5 5 * Description: Helps improve your site's accessibility by detecting specific issues and applying safe, reversible fixes to the rendered HTML. Includes a full site audit, the free fix set, and per-fix-type preview and toggle controls. 6 * Version: 1.10. 36 * Version: 1.10.4 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 7.4 … … 23 23 } 24 24 25 define( 'EQUALFIX_VERSION', '1.10. 3' );25 define( 'EQUALFIX_VERSION', '1.10.4' ); 26 26 define( 'EQUALFIX_FILE', __FILE__ ); 27 27 define( 'EQUALFIX_DIR', plugin_dir_path( __FILE__ ) ); -
equalfix/trunk/includes/class-equalfix-settings.php
r3790639 r3790684 6012 6012 $only = ''; 6013 6013 } 6014 $oneclick_n = $this->issues_oneclick_count( $result, $model, $settings ); 6014 $oneclick_stats = $this->issues_oneclick_stats( $result, $model, $settings ); 6015 $oneclick_n = $oneclick_stats['count']; 6015 6016 6016 6017 if ( 'flagged' === $view || 'aside' === $view || 'fixed' === $view ) { … … 6054 6055 $this->render_issues_heading( $result ); 6055 6056 if ( $model['d_total'] > 0 ) { 6056 $this->render_issues_summary( $result, $model, $settings, $oneclick_ n);6057 $this->render_issues_summary( $result, $model, $settings, $oneclick_stats ); 6057 6058 } 6058 6059 if ( 'all' === $view && ! $all_on ) { … … 6169 6170 // the same predicate, so the chip, the tile and 6170 6171 // this list can never disagree. 6171 $cards_list = array(); 6172 $manual_map = self::manual_matches_map( $result ); 6173 $attr_map = self::attr_matches_map( $result ); 6172 $cards_list = array(); 6173 $manual_map = self::manual_matches_map( $result ); 6174 $attr_map = self::attr_matches_map( $result ); 6175 $oneclick_ctx = $this->oneclick_proposal_ctx( $result ); 6174 6176 foreach ( $list as $oneclick_finding ) { 6175 if ( $this->is_oneclick_finding( $oneclick_finding, $model, $settings, $manual_map, $attr_map ) ) {6177 if ( $this->is_oneclick_finding( $oneclick_finding, $model, $settings, $manual_map, $attr_map, $oneclick_ctx ) ) { 6176 6178 $cards_list[] = $oneclick_finding; 6177 6179 } 6178 6180 } 6179 6181 ?> 6180 <p class="eqf-filter-note"><?php esc_html_e( 'Showing only the problems th e free fix set can fixin one click.', 'equalfix' ); ?> <a href="<?php echo esc_url( $this->tab_url( 'issues', array( 'view' => $view ) ) ); ?>"><?php esc_html_e( 'Show everything', 'equalfix' ); ?></a></p>6182 <p class="eqf-filter-note"><?php esc_html_e( 'Showing only the problems that can be fixed in one click.', 'equalfix' ); ?> <a href="<?php echo esc_url( $this->tab_url( 'issues', array( 'view' => $view ) ) ); ?>"><?php esc_html_e( 'Show everything', 'equalfix' ); ?></a></p> 6181 6183 <?php 6182 6184 } … … 6353 6355 * partition already). 6354 6356 * 6355 * @param array $finding Finding. 6356 * @param array $model Coverage model. 6357 * @param array $settings Settings. 6358 * @param array $manual_map manual_matches_map() result. 6357 * Counter-wording batch (2026-11-08): when the caller 6358 * passes the proposal context, a finding ALSO qualifies 6359 * when a computed proposal is available for it — the 6360 * owner can fix it with one click and no typing (the 6361 * group's own Fix action), which is what the strip and 6362 * the chip promise. Callers that omit the context get 6363 * exactly the shipped press-only semantics (the hero 6364 * button's own count uses that narrower set — its press 6365 * applies the standard set and nothing else). 6366 * 6367 * @param array $finding Finding. 6368 * @param array $model Coverage model. 6369 * @param array $settings Settings. 6370 * @param array $manual_map manual_matches_map() result. 6371 * @param array $attr_map attr_matches_map() result. 6372 * @param array|null $ctx oneclick_proposal_ctx() 6373 * result, or null for the 6374 * press-only predicate. 6359 6375 * @return bool 6360 6376 */ 6361 private function is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map = array() ) {6377 private function is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map = array(), $ctx = null ) { 6362 6378 $fp = self::finding_fingerprint( $finding ); 6363 6379 if ( isset( $model['fixed_fps'][ $fp ] ) || isset( $model['waiting_fps'][ $fp ] ) ) { … … 6370 6386 // same master switch the press turns on. 6371 6387 if ( isset( $attr_map[ $fp ] ) ) { 6388 return true; 6389 } 6390 // A computed proposal (Fix-First) the owner can apply 6391 // with one click and no typing — the same per-row 6392 // availability the bands and row panels use. 6393 if ( null !== $ctx && $this->finding_has_oneclick_proposal( $finding, $ctx ) ) { 6372 6394 return true; 6373 6395 } … … 6387 6409 6388 6410 /** 6389 * The DISTINCT problems one press of Apply Standard Fixes 6390 * would clear — the summary strip's hero number and the 6391 * "One-click fixes" chip count. Same predicate as the 6392 * filtered list (is_oneclick_finding()), counted in the 6393 * model's problem unit, so tile, chip and list agree. 6394 * 6395 * @param array $result Stored audit result. 6396 * @param array $model Coverage model. 6397 * @param array $settings Settings. 6398 * @return int 6399 */ 6400 private function issues_oneclick_count( $result, $model, $settings ) { 6401 if ( ! is_array( $result ) || empty( $result['findings'] ) ) { 6402 return 0; 6403 } 6411 * The Pro-side state the proposal test reads (counter- 6412 * wording batch, 2026-11-08): licence activity, the Pro 6413 * fix set's master/type state, and Pro coverage's 6414 * "would fix if applied" map — the same reads the fix-b 6415 * bands and rows render from, computed once per render 6416 * instead of once per finding. 6417 * 6418 * @param array $result Stored audit result. 6419 * @return array { licence_active: bool, pro_master_on: 6420 * bool, headings_type_on: bool, 6421 * fixed_if_on: array } 6422 */ 6423 private function oneclick_proposal_ctx( $result ) { 6424 $pro = self::pro_state(); 6425 $ctx = array( 6426 'licence_active' => ! empty( $pro['licence_active'] ), 6427 'pro_master_on' => false, 6428 'headings_type_on' => false, 6429 'fixed_if_on' => array(), 6430 ); 6431 if ( ! $ctx['licence_active'] ) { 6432 return $ctx; 6433 } 6434 if ( class_exists( 'EqualFix_Pro_Settings' ) && method_exists( 'EqualFix_Pro_Settings', 'fix_set_state' ) && class_exists( 'EqualFix_Pro_Fixer' ) ) { 6435 $fix_set = EqualFix_Pro_Settings::fix_set_state(); 6436 $ctx['pro_master_on'] = ! empty( $fix_set['master_on'] ); 6437 $ctx['headings_type_on'] = ! empty( $fix_set['types'][ EqualFix_Pro_Fixer::FIX_HEADINGS ] ); 6438 } 6439 $coverage = $this->pro_coverage( $result ); 6440 if ( null !== $coverage ) { 6441 $ctx['fixed_if_on'] = $coverage['fixed_if_on']; 6442 } 6443 return $ctx; 6444 } 6445 6446 /** 6447 * Whether a computed proposal is available for this 6448 * finding — one click, no typing (counter-wording batch, 6449 * 2026-11-08). This mirrors the availability the bands 6450 * and rows already render, group by group: 6451 * - attribute-rule groups: the proposal builder itself 6452 * (a proposal flagged needs-text is the owner's words, 6453 * not a computed fix, and never counts); 6454 * - page titles: the page-title proposal (post title or 6455 * site name, prefilled in the panel); 6456 * - embeds: the band's bulk action saves the provider- 6457 * derived title for every embed — computed, no typing; 6458 * - headings (Pro): only while the licence is active — 6459 * the finding is in Pro coverage's "would fix if 6460 * applied" map (the band's Apply press fixes exactly 6461 * that set), or the set and type are both on, when 6462 * every remaining skip's row offers the per-page 6463 * full-correction approval. 6464 * Everything else — owner-words groups, media captions 6465 * and transcripts the owner must supply, the honest 6466 * exceptions — has no computed proposal by design. 6467 * 6468 * @param array $finding Finding. 6469 * @param array $ctx oneclick_proposal_ctx() result. 6470 * @return bool 6471 */ 6472 private function finding_has_oneclick_proposal( $finding, $ctx ) { 6473 $meta = $this->finding_job_meta( $finding ); 6474 $group = $meta['group']; 6475 if ( in_array( $group, self::attr_groups(), true ) ) { 6476 $proposal = $this->attr_proposal_for_finding( $finding ); 6477 return null !== $proposal && empty( $proposal['needs_text'] ); 6478 } 6479 if ( 'page-title' === $group ) { 6480 return null !== $this->pagetitle_proposal_for_finding( $finding ); 6481 } 6482 if ( 'embed-3p' === $group || 'embed-title' === $group ) { 6483 return true; 6484 } 6485 if ( 'headings' === $group ) { 6486 if ( empty( $ctx['licence_active'] ) ) { 6487 return false; 6488 } 6489 $fp = self::finding_fingerprint( $finding ); 6490 return isset( $ctx['fixed_if_on'][ $fp ] ) || ( ! empty( $ctx['pro_master_on'] ) && ! empty( $ctx['headings_type_on'] ) ); 6491 } 6492 return false; 6493 } 6494 6495 /** 6496 * The DISTINCT-problem identity set behind the one-click 6497 * counts: every problem with at least one qualifying 6498 * finding (is_oneclick_finding()), in the model's problem 6499 * unit, so tile, chip and list agree. With proposals off 6500 * this is exactly the shipped press-only set. 6501 * 6502 * @param array $result Stored audit result. 6503 * @param array $model Coverage model. 6504 * @param array $settings Settings. 6505 * @param bool $with_proposals Include computed-proposal 6506 * problems. 6507 * @return array Identity => true. 6508 */ 6509 private function oneclick_ids( $result, $model, $settings, $with_proposals ) { 6404 6510 $manual_map = self::manual_matches_map( $result ); 6405 6511 $attr_map = self::attr_matches_map( $result ); 6512 $ctx = $with_proposals ? $this->oneclick_proposal_ctx( $result ) : null; 6406 6513 $dismissed = self::dismissed_map(); 6407 6514 $ids = array(); … … 6410 6517 continue; 6411 6518 } 6412 if ( $this->is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map ) ) {6519 if ( $this->is_oneclick_finding( $finding, $model, $settings, $manual_map, $attr_map, $ctx ) ) { 6413 6520 list( , $identity ) = $this->problem_identity( $finding ); 6414 6521 $ids[ $identity ] = true; 6415 6522 } 6416 6523 } 6417 return count( $ids ); 6524 return $ids; 6525 } 6526 6527 /** 6528 * The DISTINCT problems that can be fixed in one click — 6529 * the summary strip's hero number and the "One-click 6530 * fixes" chip count (counter-wording batch, 2026-11-08): 6531 * the problems one press of Apply Standard Fixes would 6532 * clear PLUS the problems carrying a computed proposal 6533 * (finding_has_oneclick_proposal()). Same predicate as 6534 * the filtered list, counted in the model's problem 6535 * unit, so tile, chip and list agree. 6536 * 6537 * @param array $result Stored audit result. 6538 * @param array $model Coverage model. 6539 * @param array $settings Settings. 6540 * @return int 6541 */ 6542 private function issues_oneclick_count( $result, $model, $settings ) { 6543 if ( ! is_array( $result ) || empty( $result['findings'] ) ) { 6544 return 0; 6545 } 6546 return count( $this->oneclick_ids( $result, $model, $settings, true ) ); 6547 } 6548 6549 /** 6550 * The one-click figures the summary strip renders 6551 * (counter-wording batch, 2026-11-08), computed in one 6552 * pass so the tiles can never disagree: 6553 * - count: the widened one-click set (issues_oneclick_ 6554 * count()); 6555 * - press: the narrower shipped set the hero button's 6556 * own press (apply_standard_fixes) would clear — the 6557 * button is labelled with THIS number only; 6558 * - review_left: review-bucket problems (the model's 6559 * problem_buckets) that are NOT in the widened set — 6560 * the problems that genuinely still need the owner. 6561 * Equals d_review whenever no review problem carries 6562 * a proposal, which is how the strip knows the shipped 6563 * review wording still holds. 6564 * 6565 * @param array $result Stored audit result. 6566 * @param array $model Coverage model. 6567 * @param array $settings Settings. 6568 * @return array { count: int, press: int, review_left: int } 6569 */ 6570 private function issues_oneclick_stats( $result, $model, $settings ) { 6571 $stats = array( 6572 'count' => 0, 6573 'press' => 0, 6574 'review_left' => (int) $model['d_review'], 6575 ); 6576 if ( ! is_array( $result ) || empty( $result['findings'] ) ) { 6577 return $stats; 6578 } 6579 $ids = $this->oneclick_ids( $result, $model, $settings, true ); 6580 $stats['count'] = count( $ids ); 6581 $stats['press'] = count( $this->oneclick_ids( $result, $model, $settings, false ) ); 6582 $left = 0; 6583 foreach ( (array) $model['problem_buckets'] as $identity => $bucket ) { 6584 if ( 'review' === $bucket && ! isset( $ids[ $identity ] ) ) { 6585 $left++; 6586 } 6587 } 6588 $stats['review_left'] = $left; 6589 return $stats; 6418 6590 } 6419 6591 … … 6422 6594 * three tiles over the ONE coverage model — problems 6423 6595 * still to do (d_todo), the one-click count with the real 6424 * Apply Standard Fixes form, and the review count 6425 * (d_review) — over a progress bar, with the fixed note 6426 * and the problems-vs-findings footnote in plain words. 6427 * No number here is computed anywhere else. 6428 * 6429 * @param array $result Stored audit result. 6430 * @param array $model Coverage model. 6431 * @param array $settings Settings. 6432 * @param int $oneclick_n issues_oneclick_count(). 6433 */ 6434 private function render_issues_summary( $result, $model, $settings, $oneclick_n ) { 6596 * Apply Standard Fixes form, and the review count — over 6597 * a progress bar, with the fixed note and the problems- 6598 * vs-findings footnote in plain words. No number here is 6599 * computed anywhere else. 6600 * 6601 * Counter-wording batch (2026-11-08): the hero tile's 6602 * headline is the WIDENED one-click count (press set + 6603 * computed proposals), but its form posts 6604 * apply_standard_fixes, so the button keeps the PRESS 6605 * count and renders only when that count is non-zero — 6606 * the button must never promise the proposal problems. 6607 * The review tile counts the review problems with NO 6608 * proposal (review_left): while that equals d_review the 6609 * shipped wording stands exactly as written; once some 6610 * review problems carry a fix, the tile switches to the 6611 * neutral wording for the remainder only. 6612 * 6613 * @param array $result Stored audit result. 6614 * @param array $model Coverage model. 6615 * @param array $settings Settings. 6616 * @param array $oneclick_stats issues_oneclick_stats(). 6617 */ 6618 private function render_issues_summary( $result, $model, $settings, $oneclick_stats ) { 6619 $oneclick_n = (int) $oneclick_stats['count']; 6620 $press_n = (int) $oneclick_stats['press']; 6621 $review_left = (int) $oneclick_stats['review_left']; 6435 6622 $pct = $model['d_total'] > 0 ? (int) round( 100 * $model['d_fixed'] / $model['d_total'] ) : 0; 6436 6623 ?> … … 6448 6635 <div class="eqf-tile eqf-tile-hero"> 6449 6636 <?php if ( $oneclick_n > 0 ) : ?> 6450 <div class="eqf-tile-big"><?php echo esc_html( sprintf( /* translators: %d: problems one press fixes*/ _n( '%d can be fixed in one click', '%d can be fixed in one click', $oneclick_n, 'equalfix' ), $oneclick_n ) ); ?></div>6637 <div class="eqf-tile-big"><?php echo esc_html( sprintf( /* translators: %d: problems fixable in one click */ _n( '%d can be fixed in one click', '%d can be fixed in one click', $oneclick_n, 'equalfix' ), $oneclick_n ) ); ?></div> 6451 6638 <div class="eqf-tile-lbl"><?php esc_html_e( 'EqualFix already knows how to fix these safely.', 'equalfix' ); ?></div> 6639 <?php if ( $press_n > 0 ) : ?> 6452 6640 <div class="eqf-tile-act"> 6453 6641 <form method="post" action=""> 6454 6642 <?php wp_nonce_field( 'equalfix_settings' ); ?> 6455 6643 <input type="hidden" name="equalfix_action" value="apply_standard_fixes"> 6456 <button type="submit" class="button button-primary"><?php echo esc_html( sprintf( /* translators: %d: problems one press fixes */ _n( 'Fix all %d now', 'Fix all %d now', $ oneclick_n, 'equalfix' ), $oneclick_n ) ); ?></button>6644 <button type="submit" class="button button-primary"><?php echo esc_html( sprintf( /* translators: %d: problems one press fixes */ _n( 'Fix all %d now', 'Fix all %d now', $press_n, 'equalfix' ), $press_n ) ); ?></button> 6457 6645 </form> 6458 6646 </div> 6647 <?php endif; ?> 6459 6648 <?php else : ?> 6460 6649 <div class="eqf-tile-big"><?php esc_html_e( '0 can be fixed in one click', 'equalfix' ); ?></div> … … 6463 6652 </div> 6464 6653 <div class="eqf-tile"> 6465 <div class="eqf-tile-big"><?php echo (int) $model['d_review']; ?></div> 6466 <div class="eqf-tile-lbl"><?php echo esc_html( _n( 'needs a quick look from you — no automatic fix is safe here', 'need a quick look from you — no automatic fix is safe here', (int) $model['d_review'], 'equalfix' ) ); ?></div> 6654 <div class="eqf-tile-big"><?php echo $review_left; ?></div> 6655 <div class="eqf-tile-lbl"><?php echo esc_html( $review_left === (int) $model['d_review'] 6656 ? _n( 'needs a quick look from you — no automatic fix is safe here', 'need a quick look from you — no automatic fix is safe here', $review_left, 'equalfix' ) 6657 : _n( 'needs a quick look from you — this one needs your input', 'need a quick look from you — these need your input', $review_left, 'equalfix' ) ); ?></div> 6467 6658 <div class="eqf-tile-act"><a class="button eqf-btn-ghost" href="<?php echo esc_url( $this->tab_url( 'issues', array( 'view' => 'todo' ) ) ); ?>"><?php esc_html_e( 'Start reviewing', 'equalfix' ); ?></a></div> 6468 6659 </div> … … 7598 7789 $is_review_group = in_array( $group['meta']['group'], self::REVIEW_GROUPS, true ); 7599 7790 if ( $group['d_todo'] > 0 ) { 7791 // Counter-wording batch (2026-11-08): a 7792 // review-bucket group whose problems carry 7793 // a computed fix (has_proposals — the same 7794 // gate as the band's Fix all) is not 7795 // "for your review" any more; the bucket 7796 // itself is unchanged — the problems stay 7797 // in review until the fix is applied. 7600 7798 $count_line = $is_review_group 7601 ? sprintf( _n( '%d problem for your review', '%d problems for your review', $group['d_todo'], 'equalfix' ), $group['d_todo'] ) 7799 ? ( ! empty( $group['has_proposals'] ) 7800 ? sprintf( _n( '%d problem — a fix is ready', '%d problems — a fix is ready', $group['d_todo'], 'equalfix' ), $group['d_todo'] ) 7801 : sprintf( _n( '%d problem for your review', '%d problems for your review', $group['d_todo'], 'equalfix' ), $group['d_todo'] ) ) 7602 7802 : sprintf( _n( '%d problem still to do', '%d problems still to do', $group['d_todo'], 'equalfix' ), $group['d_todo'] ); 7603 7803 } else { … … 7651 7851 ?> 7652 7852 <tr class="eqf-band" id="eqf-group-<?php echo esc_attr( $meta['group'] ); ?>"><td colspan="4"><div class="eqf-band-in"> 7653 <span class="eqf-band-name"><?php echo esc_html( $this->issue_display_title( $meta['group'], $meta['name'] ) ); ?></span><?php if ( 'oneclick' === $card_tag ) : ?><span class="eqf-tag eqf-tag-oneclick"><?php esc_html_e( 'One-click fix', 'equalfix' ); ?></span><?php elseif ( 'pro' === $card_tag ) : ?><span class="eqf-tag eqf-tag-pro"><?php esc_html_e( 'Pro', 'equalfix' ); ?></span><?php endif; ?><?php if ( $is_review_group ) : ?><span class="eqf-badge eqf-badge-review"><?php esc_html_e( 'Needs human review', 'equalfix' ); ?></span><?php endif; ?>7853 <span class="eqf-band-name"><?php echo esc_html( $this->issue_display_title( $meta['group'], $meta['name'] ) ); ?></span><?php if ( 'oneclick' === $card_tag ) : ?><span class="eqf-tag eqf-tag-oneclick"><?php esc_html_e( 'One-click fix', 'equalfix' ); ?></span><?php elseif ( 'pro' === $card_tag ) : ?><span class="eqf-tag eqf-tag-pro"><?php esc_html_e( 'Pro', 'equalfix' ); ?></span><?php endif; ?><?php if ( $is_review_group && empty( $group['has_proposals'] ) ) : ?><span class="eqf-badge eqf-badge-review"><?php esc_html_e( 'Needs human review', 'equalfix' ); ?></span><?php endif; ?> 7654 7854 <span class="eqf-band-count"><?php echo esc_html( $count_line ); ?></span> 7655 7855 <?php $this->render_card_action( $group, $meta, $ctx_group, $skip_map, $open, $pro ); ?> -
equalfix/trunk/readme.txt
r3790639 r3790684 5 5 Tested up to: 7.1 6 6 Requires PHP: 7.4 7 Stable tag: 1.10. 37 Stable tag: 1.10.4 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 99 99 == Changelog == 100 100 101 = 1.10.4 = 102 * Fixed: the Issues summary now counts every problem that already has a fix ready (including the computed fixes), so the one-click count matches the Fix all buttons below it. 103 101 104 = 1.10.3 = 102 105 * The Issues tab is now one compact, scrollable table.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)