Changeset 3672480
- Timestamp:
- 08/30/2026 11:51:52 AM (7 weeks ago)
- Location:
- sitehale/trunk
- Files:
-
- 4 edited
-
admin/class-sitehale-checkup.php (modified) (15 diffs)
-
includes/class-sitehale-health.php (modified) (1 diff)
-
readme.txt (modified) (3 diffs)
-
sitehale.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
sitehale/trunk/admin/class-sitehale-checkup.php
r3655352 r3672480 334 334 'plain_permalinks' => ( '' === (string) get_option( 'permalink_structure' ) ), 335 335 'seo_plugin' => self::active_seo_plugin(), 336 'sitehale_seo' => self::sitehale_renders(), 336 337 'core_sitemaps' => (bool) $sitemaps, 337 338 // Block themes never declare title-tag support — core renders their … … 375 376 } 376 377 378 /** 379 * Whether THIS plugin's SEO module is the one rendering here. 380 * 381 * ⚠️ Not "is SiteHale installed" — on this page it always is. The module 382 * ships dormant, and stays dormant on a site it was never switched over 383 * for: a wordpress.org install gets an admin-only plugin that renders 384 * nothing on the front end. Installed and rendering are different facts 385 * and only the second one belongs in a report about search results. 386 * 387 * Asking the renderer's own gate keeps one owner for that answer rather 388 * than a second copy of it here — the gate is not a plugin census either 389 * (it turns on the guard's "who is actually rendering" measurement), and a 390 * reimplementation would drift from it in exactly the cases it exists for. 391 * 392 * The bug this fixes: the SEO card shipped in 0.6.0 knowing only the five 393 * rivals above, so every client switched over to our own module read back 394 * as "No SEO plugin detected" — and graded `warn` for it — while SiteHale 395 * was writing its titles and descriptions. 396 * 397 * @return bool 398 */ 399 public static function sitehale_renders() { 400 return class_exists( 'SiteHale_SEO_Head' ) && SiteHale_SEO_Head::should_render(); 401 } 402 377 403 public static function grade_seo( $data ) { 378 404 $status = 'ok'; … … 388 414 $status = self::worst_of( $status, 'warn' ); 389 415 } 390 if ( empty( $data['seo_plugin'] ) ) { 416 // Who owns meta rendering, for the reader. Our own module answers this 417 // first: when it renders, the guard is clear, so no rival is rendering 418 // even on the clients that still carry one installed. 419 $engine = ! empty( $data['sitehale_seo'] ) ? 'SiteHale' : (string) $data['seo_plugin']; 420 if ( '' === $engine ) { 391 421 $status = self::worst_of( $status, 'warn' ); 392 422 } … … 396 426 397 427 // Who serves the sitemap, and where. Every major SEO plugin replaces 398 // core's /wp-sitemap.xml with its own /sitemap.xml. 428 // core's /wp-sitemap.xml with its own /sitemap.xml. ⚠️ Keyed on the 429 // RIVAL, deliberately, not on $engine: our own module keeps core's 430 // sitemap and filters it (SiteHale_SEO_Sitemap), so a switched-over 431 // site serves /wp-sitemap.xml and reporting /sitemap.xml would send 432 // the reader to a redirect at best. 399 433 $sitemap_url = ''; 400 434 if ( ! empty( $data['seo_plugin'] ) ) { … … 411 445 'noindex' => $noindex, 412 446 'plain_permalinks' => ! empty( $data['plain_permalinks'] ), 413 'seo_plugin' => (string) $data['seo_plugin'],447 'seo_plugin' => $engine, 414 448 'sitemap_url' => $sitemap_url, 415 449 'title_tag' => ! empty( $data['title_tag'] ), … … 745 779 } 746 780 747 protected static function card_close( $pitch ) { 748 if ( $pitch && ! SiteHale_Connect::is_connected() ) { 749 echo '<p style="margin:12px 0 0;padding-top:10px;border-top:1px solid #f0f0f1;color:#646970;font-size:12px;"><span class="dashicons dashicons-heart" style="font-size:14px;width:14px;height:14px;color:#2563EB;"></span> ' . esc_html( $pitch ) . '</p>'; 781 /** 782 * Who ACTS on each card's findings, by plan. Not who reports them — this 783 * page reports all of it to everyone, free included. 784 * 785 * 'fix' SiteHale does the work. Nothing for the owner to do. 786 * 'watch' SiteHale watches and alerts a human. The fix is still someone's, 787 * and saying otherwise on a client's own dashboard would be the 788 * false all-clear this plugin exists to prevent. 789 * 790 * `upsell` is the line a CARE client sees on a card only Managed acts on. 791 * It is the one place a paying client is sold anything, and it is honest: 792 * those two cards really are the Managed labor, not a feature gate. 793 * 794 * ⚠️ Environment EOL is deliberately absent. A PHP or database version 795 * lives in the hosting account and no plan of ours changes it — see the 796 * note the Updates card prints for itself. 797 * 798 * @return array 799 */ 800 protected static function coverage() { 801 return array( 802 'cron' => array( 'care' => 'watch', 'managed' => 'watch' ), 803 'errors' => array( 'care' => 'watch', 'managed' => 'watch' ), 804 'db' => array( 805 'care' => 'watch', 806 'managed' => 'fix', 807 'upsell' => __( 'Managed adds database optimization and verified weekly backups, applied for you.', 'sitehale' ), 808 ), 809 'updates' => array( 810 'care' => 'watch', 811 'managed' => 'fix', 812 'upsell' => __( 'Managed applies these updates for you, staging-tested first when they are risky.', 'sitehale' ), 813 ), 814 'seo' => array( 'care' => 'fix', 'managed' => 'fix' ), 815 'admins' => array( 'care' => 'watch', 'managed' => 'watch' ), 816 'mail' => array( 'care' => 'watch', 'managed' => 'watch' ), 817 'history' => array( 'care' => 'watch', 'managed' => 'watch' ), 818 ); 819 } 820 821 /** 822 * The footer line: on a free site the pitch, on a paying one the answer to 823 * "so is somebody dealing with this?". 824 * 825 * ⚠️ Gated on the PLAN, never on the connection. Connecting is free and 826 * provisions nothing, so a connected-but-unactivated site is not being 827 * watched by anyone — it needs the pitch like any other free site. This 828 * line used to check `SiteHale_Connect::is_connected()` and those sites 829 * silently got no footer at all, which is the mistake 830 * `SiteHale_Reports::active_plan()` documents in its own docblock. 831 * 832 * @param string $pitch Free-tier line for this card. 833 * @param string $key Coverage key, '' for a card nobody acts on. 834 * @return string 835 */ 836 protected static function coverage_line( $pitch, $key ) { 837 $plan = class_exists( 'SiteHale_Reports' ) ? SiteHale_Reports::active_plan() : ''; 838 if ( '' === $plan ) { 839 return (string) $pitch; 840 } 841 $cov = self::coverage(); 842 if ( '' === $key || ! isset( $cov[ $key ][ $plan ] ) ) { 843 return ''; 844 } 845 $label = class_exists( 'SiteHale_Health' ) ? SiteHale_Health::plan_label() : $plan; 846 847 // A Care client on a Managed-only card: tell them who acts, which is 848 // nobody yet, rather than implying we already do. 849 if ( 'care' === $plan && ! empty( $cov[ $key ]['upsell'] ) && 'fix' === $cov[ $key ]['managed'] ) { 850 /* translators: 1: what Managed adds, 2: the site's current plan */ 851 return sprintf( __( '%1$s Your plan: %2$s.', 'sitehale' ), $cov[ $key ]['upsell'], $label ); 852 } 853 854 if ( 'fix' === $cov[ $key ][ $plan ] ) { 855 /* translators: %s: the site's plan */ 856 return sprintf( __( 'SiteHale is handling this for you — nothing to do here. Your plan: %s.', 'sitehale' ), $label ); 857 } 858 /* translators: %s: the site's plan */ 859 return sprintf( __( 'SiteHale is watching this and alerts a human if it changes. Your plan: %s.', 'sitehale' ), $label ); 860 } 861 862 protected static function card_close( $pitch, $key = '' ) { 863 $line = self::coverage_line( $pitch, $key ); 864 if ( '' !== $line ) { 865 echo '<p style="margin:12px 0 0;padding-top:10px;border-top:1px solid #f0f0f1;color:#646970;font-size:12px;"><span class="dashicons dashicons-heart" style="font-size:14px;width:14px;height:14px;color:#2563EB;"></span> ' . esc_html( $line ) . '</p>'; 750 866 } 751 867 echo '</div>'; … … 877 993 ); 878 994 } 879 self::card_close( __( 'SiteHale watches cron health on your site every day, automatically — and alerts a human when it dies.', 'sitehale' ) );995 self::card_close( __( 'SiteHale watches cron health on your site every day, automatically — and alerts a human when it dies.', 'sitehale' ), 'cron' ); 880 996 881 997 /* ---- PHP errors ---- */ … … 971 1087 } 972 1088 } 973 self::card_close( __( 'Fatal errors often never email anyone. SiteHale reads these logs weekly and reports the signatures that repeat.', 'sitehale' ) );1089 self::card_close( __( 'Fatal errors often never email anyone. SiteHale reads these logs weekly and reports the signatures that repeat.', 'sitehale' ), 'errors' ); 974 1090 975 1091 /* ---- Database health ---- */ … … 1006 1122 ) 1007 1123 ); 1008 self::card_close( __( 'SiteHale runs this exact report monthly on every client site, plus weekly verified database backups.', 'sitehale' ) );1124 self::card_close( __( 'SiteHale runs this exact report monthly on every client site, plus weekly verified database backups.', 'sitehale' ), 'db' ); 1009 1125 1010 1126 /* ---- Updates + environment EOL ---- */ … … 1037 1153 echo '<p style="font-weight:600;">' . esc_html( $row['label'] ) . '</p>'; 1038 1154 } 1155 if ( $updates['eol'] && class_exists( 'SiteHale_Reports' ) && SiteHale_Reports::is_watched() ) { 1156 // ⚠️ Said out loud on purpose. Everything else on this card is 1157 // something a plan acts on, so silence here reads as "they have 1158 // it" — and a PHP or database version lives in the hosting 1159 // account, where no automation of ours reaches. g2computers has 1160 // sat on an EOL database for exactly this reason: it needs the 1161 // client and their host, not us. 1162 echo '<p style="color:#646970;font-size:13px;">' . esc_html__( 'PHP and database versions are set in your hosting account. SiteHale reports them, but changing one is a job for your host — ask them to move you to a supported version.', 'sitehale' ) . '</p>'; 1163 } 1039 1164 if ( ! $updates['eol'] ) { 1040 1165 printf( … … 1050 1175 ); 1051 1176 } 1052 self::card_close( __( 'SiteHale tracks updates weekly and stages risky plugin updates on a copy of the site before they ever touch production.', 'sitehale' ) );1177 self::card_close( __( 'SiteHale tracks updates weekly and stages risky plugin updates on a copy of the site before they ever touch production.', 'sitehale' ), 'updates' ); 1053 1178 1054 1179 /* ---- SEO basics (v0.6) ---- */ … … 1092 1217 echo '<p style="color:#646970;font-size:13px;">' . esc_html__( 'The site tagline is empty or still the WordPress default — on many themes it shows in the browser title and in search results.', 'sitehale' ) . '</p>'; 1093 1218 } 1094 self::card_close( __( 'SiteHale runs full SEO audits monthly — titles, descriptions, keywords, broken links, and rankings from Google Search Console — and fixes what it finds.', 'sitehale' ) );1219 self::card_close( __( 'SiteHale runs full SEO audits monthly — titles, descriptions, keywords, broken links, and rankings from Google Search Console — and fixes what it finds.', 'sitehale' ), 'seo' ); 1095 1220 1096 1221 /* ---- Administrators ---- */ … … 1110 1235 echo '</p>'; 1111 1236 echo '<p>' . esc_html__( 'If any of these names surprises you, investigate now — a new administrator you did not create is the classic sign of a compromise.', 'sitehale' ) . '</p>'; 1112 self::card_close( __( 'SiteHale keeps a baseline of this list and alerts the moment a new administrator appears.', 'sitehale' ) );1237 self::card_close( __( 'SiteHale keeps a baseline of this list and alerts the moment a new administrator appears.', 'sitehale' ), 'admins' ); 1113 1238 1114 1239 /* ---- Mail test ---- */ … … 1122 1247 </form> 1123 1248 <?php 1124 self::card_close( __( 'SiteHale probes deliverability weekly and confirms actual arrival in a real inbox — not just that WordPress accepted the message.', 'sitehale' ) );1249 self::card_close( __( 'SiteHale probes deliverability weekly and confirms actual arrival in a real inbox — not just that WordPress accepted the message.', 'sitehale' ), 'mail' ); 1125 1250 1126 1251 /* ---- Email this checkup (v0.4) ---- */ … … 1178 1303 </table> 1179 1304 <?php 1180 self::card_close( __( 'SiteHale clients get this watching continuously — with a human on the alerts, not a table you have to remember to read.', 'sitehale' ) );1305 self::card_close( __( 'SiteHale clients get this watching continuously — with a human on the alerts, not a table you have to remember to read.', 'sitehale' ), 'history' ); 1181 1306 endif; 1182 1307 -
sitehale/trunk/includes/class-sitehale-health.php
r3655308 r3672480 280 280 } 281 281 282 protected static function plan_label() { 283 $plan = get_option( 'sitehale_plan', '' ); 282 /** 283 * The site's plan, for a human. 284 * 285 * ⚠️ Derives from `SiteHale_Reports::active_plan()` rather than reading 286 * the option itself. It used to carry its own copy of the two-signal rule 287 * (option, else "a stored report proves Care"), which is the same 288 * procedure written twice — and the Site Checkup footer now names this 289 * plan to a client, so a label that drifted from the plan the rest of the 290 * plugin acts on would be worse than a wrong word. 291 * 292 * Public because the Checkup prints it; behaviour is unchanged. 293 * 294 * @return string 295 */ 296 public static function plan_label() { 297 $plan = class_exists( 'SiteHale_Reports' ) ? SiteHale_Reports::active_plan() : ''; 284 298 if ( 'managed' === $plan ) { 285 299 return __( 'Managed', 'sitehale' ); 286 300 } 287 if ( 'care' === $plan || ( class_exists( 'SiteHale_Reports' ) && SiteHale_Reports::index() )) {301 if ( 'care' === $plan ) { 288 302 return __( 'Care', 'sitehale' ); 289 303 } -
sitehale/trunk/readme.txt
r3670714 r3672480 5 5 Tested up to: 7.1 6 6 Requires PHP: 7.4 7 Stable tag: 0.7.5 27 Stable tag: 0.7.53 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 130 130 == Upgrade Notice == 131 131 132 = 0.7.53 = 133 Fixes Site Checkup reporting "No SEO plugin detected" on sites whose SEO is managed by SiteHale itself, and each section now says who acts on what it finds. Sites using another SEO plugin, or none, read exactly as before. 134 132 135 = 0.7.51 = 133 136 Housekeeping only: no change to how the plugin behaves. Shops keep their review stars in search results when SiteHale manages their SEO, and a product with no reviews publishes no rating rather than a zero-star one. … … 172 175 173 176 == Changelog == 177 178 = 0.7.53 = 179 * Site Checkup now recognises SiteHale itself as the SEO plugin on a site whose SEO it manages. Sites switched over to SiteHale were told "No SEO plugin detected" — and had the SEO section marked as needing attention for it — while SiteHale was writing their titles and descriptions. Sites using another SEO plugin, or none, are unaffected and read exactly as before. 180 * Site Checkup now tells you who acts on each finding. On a Care or Managed site each section says whether SiteHale is handling it for you or watching it and alerting a human, so a section marked "Needs attention" no longer reads as a job waiting on you when it isn't. The status itself is unchanged — it still describes your site, not your plan. 181 * An end-of-life PHP or database version now says plainly that it is set in your hosting account and your host has to change it. No plan of ours can. 182 * Fixes the free-plan footer disappearing on a site that had connected to SiteHale but was never activated. Connecting is free and provisions nothing, so those sites are on the free plan and should read like it. 174 183 175 184 = 0.7.52 = -
sitehale/trunk/sitehale.php
r3670714 r3672480 4 4 * Plugin URI: https://sitehale.com/how-it-works/ 5 5 * Description: Free Site Checkup (cron, PHP errors, database, updates, admins, SEO basics, disk, mail) plus the companion to the SiteHale managed care service. Sends nothing anywhere until you click Connect. 6 * Version: 0.7.5 26 * Version: 0.7.53 7 7 * Requires at least: 5.7 8 8 * Requires PHP: 7.4 … … 30 30 } 31 31 32 define( 'SITEHALE_VERSION', '0.7.5 2' );32 define( 'SITEHALE_VERSION', '0.7.53' ); 33 33 define( 'SITEHALE_PLUGIN_FILE', __FILE__ ); 34 34 define( 'SITEHALE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
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)