Plugin Directory

Changeset 3771047


Ignore:
Timestamp:
10/28/2026 04:14:21 PM (21 hours ago)
Author:
wordpromise
Message:

Crawlsure 0.8.5: leave page-builder templates out of the checks

Location:
crawlsure
Files:
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • crawlsure/tags/0.8.5/crawlsure.php

    r3771007 r3771047  
    44 * Plugin URI:        https://www.wordpromise.com/crawlsure/
    55 * Description:       Technical SEO and AI search for WordPress. Finds what holds your site back, explains it in plain English and fixes it.
    6  * Version:           0.8.4
     6 * Version:           0.8.5
    77 * Requires at least: 6.5
    88 * Requires PHP:      7.4
    … …  
    1818defined( 'ABSPATH' ) || exit;
    1919
    20 define( 'CRAWLSURE_VERSION', '0.8.4' );
     20define( 'CRAWLSURE_VERSION', '0.8.5' );
    2121define( 'CRAWLSURE_FILE', __FILE__ );
    2222define( 'CRAWLSURE_DIR', plugin_dir_path( __FILE__ ) );
  • crawlsure/tags/0.8.5/includes/class-crawlsure-admin-links.php

    r3771007 r3771047  
    186186                                . esc_html( sprintf( _n( 'Remove %d dead link', 'Remove all %d dead links', $dead, 'crawlsure' ), $dead ) ) . '</a> <span class="description">'
    187187                                . esc_html__( 'Only links to other websites whose page or whole website is gone, seen on two checks a day apart. Server errors and links to your own site are left for you to decide.', 'crawlsure' ) . '</span></p>';
     188                } elseif ( $on && $problems ) {
     189                        echo '<p class="description cs-bulk">' . esc_html__( 'Nothing to remove in one go right now. "Remove all dead links" appears when links to other websites are certainly dead (the page or whole website is gone, seen on two checks a day apart). The links below are on your own site (better redirected), may be down only for now, or were found once so far: remove them one by one with "Remove link", or check them again later.', 'crawlsure' ) . '</p>';
    188190                }
    189191                if ( ! $on ) {
  • crawlsure/tags/0.8.5/includes/class-crawlsure-indexing.php

    r3768686 r3771047  
    104104         */
    105105        public static function post_types() {
    106                 return array_values( array_diff( get_post_types( array( 'public' => true ) ), array( 'attachment' ) ) );
     106                return Crawlsure_Plugin::content_types();
    107107        }
    108108
    … …  
    326326        public static function stats() {
    327327                global $wpdb;
     328                self::prune();
    328329                $table = Crawlsure_DB::table( 'gsc_index' );
    329330                $row   = $wpdb->get_row( $wpdb->prepare( "SELECT COUNT(*) AS checked, SUM(verdict = 'pass') AS indexed, SUM(verdict <> 'pass' AND error = '') AS nots, SUM(error <> '') AS errors FROM %i", $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
    … …  
    348349                        'total'   => $total,
    349350                );
     351        }
     352
     353        /**
     354         * Forget results for posts that are gone or are not real pages (for example page-builder templates
     355         * checked by earlier versions).
     356         */
     357        public static function prune() {
     358                Crawlsure_Plugin::prune_rows( Crawlsure_DB::table( 'gsc_index' ) );
    350359        }
    351360
  • crawlsure/tags/0.8.5/includes/class-crawlsure-links.php

    r3771007 r3771047  
    6161         */
    6262        public static function post_types() {
    63                 return array_values( array_diff( get_post_types( array( 'public' => true ) ), array( 'attachment' ) ) );
     63                return Crawlsure_Plugin::content_types();
    6464        }
    6565
    … …  
    235235
    236236        /**
     237         * Forget the links of posts that are gone or are not real pages (for example page-builder templates
     238         * indexed by earlier versions), and the links no page uses any more.
     239         */
     240        public static function prune_refs() {
     241                global $wpdb;
     242                Crawlsure_Plugin::prune_rows( self::link_refs_table() );
     243                $wpdb->query( $wpdb->prepare( 'DELETE l FROM %i l LEFT JOIN %i r ON r.link_id = l.id WHERE r.link_id IS NULL', Crawlsure_DB::table( 'links' ), self::link_refs_table() ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
     244        }
     245
     246        /**
     247         * The table of which page uses which link.
     248         *
     249         * @return string
     250         */
     251        private static function link_refs_table() {
     252                return Crawlsure_DB::table( 'link_refs' );
     253        }
     254
     255        /**
    237256         * Remove a post's links from the index.
    238257         *
    … …  
    294313                $links = Crawlsure_DB::table( 'links' );
    295314                $refs  = Crawlsure_DB::table( 'link_refs' );
     315                self::prune_refs();
    296316                // Links no longer used anywhere are dropped.
    297317                $wpdb->query( $wpdb->prepare( 'DELETE l FROM %i l LEFT JOIN %i r ON r.link_id = l.id WHERE r.link_id IS NULL', $links, $refs ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
    … …  
    470490        public static function stats() {
    471491                global $wpdb;
     492                self::prune_refs();
    472493                $t     = Crawlsure_DB::table( 'links' );
    473494                $row   = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
  • crawlsure/tags/0.8.5/includes/class-crawlsure-pages.php

    r3768686 r3771047  
    121121                $limit = is_numeric( $limit ) && (int) $limit > 0 ? (int) $limit : self::BATCH;
    122122                $table = Crawlsure_DB::table( 'page_checks' );
     123                Crawlsure_Plugin::prune_rows( $table );
    123124                self::sync();
    124125                $site = get_option( self::SITE_OPTION );
    … …  
    732733                global $wpdb;
    733734                $table   = Crawlsure_DB::table( 'page_checks' );
     735                Crawlsure_Plugin::prune_rows( $table );
    734736                $pages   = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
    735737                $checked = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i WHERE checked IS NOT NULL AND status > 0', $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
  • crawlsure/tags/0.8.5/includes/class-crawlsure-plugin.php

    r3768686 r3771047  
    169169
    170170        /**
     171         * Content types with real public pages: the ones WordPress lists for its own sitemap (public and
     172         * viewable, minus what plugins take out through wp_sitemaps_post_types, as Elementor does with its
     173         * template library), without page-builder template types that slip through. Used by the link
     174         * checker, page checks and the "In Google" check, so templates and saved layouts are never checked.
     175         *
     176         * @return string[]
     177         */
     178        public static function content_types() {
     179                $objects = array();
     180                foreach ( get_post_types( array( 'public' => true ), 'objects' ) as $name => $object ) {
     181                        if ( 'attachment' !== $name && is_post_type_viewable( $object ) ) {
     182                                $objects[ $name ] = $object;
     183                        }
     184                }
     185                $objects = (array) apply_filters( 'wp_sitemaps_post_types', $objects ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- core hook, read the way WordPress's sitemap reads it.
     186                $types   = array_diff(
     187                        array_keys( $objects ),
     188                        array( 'elementor_library', 'e-floating-buttons', 'elementor-hf', 'et_pb_layout', 'fl-builder-template', 'ct_template', 'oxy_user_library', 'bricks_template', 'brizy_template', 'kadence_element', 'astra-advanced-hook', 'wp_block', 'wp_template', 'wp_template_part', 'wp_navigation' )
     189                );
     190                /**
     191                 * Filter the content types Crawlsure checks (links, page checks, "In Google").
     192                 *
     193                 * @param string[] $types Post type names.
     194                 */
     195                return array_values( (array) apply_filters( 'crawlsure_content_types', array_values( $types ) ) );
     196        }
     197
     198        /**
     199         * Delete a Crawlsure table's rows (keyed by post_id) for posts that are gone or are not real pages.
     200         *
     201         * @param string $table Full table name.
     202         */
     203        public static function prune_rows( $table ) {
     204                global $wpdb;
     205                $types = self::content_types();
     206                if ( ! $types ) {
     207                        return;
     208                }
     209                $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
     210                        $wpdb->prepare(
     211                                'DELETE t FROM %i t LEFT JOIN %i p ON p.ID = t.post_id WHERE p.ID IS NULL OR p.post_type NOT IN (' . implode( ',', array_fill( 0, count( $types ), '%s' ) ) . ')', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQL.NotPrepared -- one placeholder per type.
     212                                array_merge( array( $table, $wpdb->posts ), $types )
     213                        )
     214                );
     215        }
     216
     217        /**
    171218         * Main category of a post: the one chosen in Crawlsure if the post is still in it,
    172219         * otherwise WordPress's first category. Null for posts without categories.
  • crawlsure/tags/0.8.5/readme.txt

    r3771007 r3771047  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 0.8.4
     7Stable tag: 0.8.5
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    108108== Changelog ==
    109109
     110= 0.8.5 =
     111* Page-builder templates (Elementor templates, saved layouts, headers and footers and the like) are no longer treated as pages: they are left out of the link checker, the page checks and the "In Google" check, and old results for them are cleared. Crawlsure now checks the same content types WordPress puts in its sitemap.
     112* Links and 404s: when nothing can be removed in one go, a short note explains why and what to do instead.
     113
    110114= 0.8.4 =
    111115* Simpler menu: the WordPress sidebar now shows one line per section (Overview, Checks, Search and AI, Your site, Tools, Settings) instead of every page; the Crawlsure header leads to the pages of each section. Setup and Import moved to the new Settings section.
  • crawlsure/trunk/crawlsure.php

    r3771007 r3771047  
    44 * Plugin URI:        https://www.wordpromise.com/crawlsure/
    55 * Description:       Technical SEO and AI search for WordPress. Finds what holds your site back, explains it in plain English and fixes it.
    6  * Version:           0.8.4
     6 * Version:           0.8.5
    77 * Requires at least: 6.5
    88 * Requires PHP:      7.4
    … …  
    1818defined( 'ABSPATH' ) || exit;
    1919
    20 define( 'CRAWLSURE_VERSION', '0.8.4' );
     20define( 'CRAWLSURE_VERSION', '0.8.5' );
    2121define( 'CRAWLSURE_FILE', __FILE__ );
    2222define( 'CRAWLSURE_DIR', plugin_dir_path( __FILE__ ) );
  • crawlsure/trunk/includes/class-crawlsure-admin-links.php

    r3771007 r3771047  
    186186                                . esc_html( sprintf( _n( 'Remove %d dead link', 'Remove all %d dead links', $dead, 'crawlsure' ), $dead ) ) . '</a> <span class="description">'
    187187                                . esc_html__( 'Only links to other websites whose page or whole website is gone, seen on two checks a day apart. Server errors and links to your own site are left for you to decide.', 'crawlsure' ) . '</span></p>';
     188                } elseif ( $on && $problems ) {
     189                        echo '<p class="description cs-bulk">' . esc_html__( 'Nothing to remove in one go right now. "Remove all dead links" appears when links to other websites are certainly dead (the page or whole website is gone, seen on two checks a day apart). The links below are on your own site (better redirected), may be down only for now, or were found once so far: remove them one by one with "Remove link", or check them again later.', 'crawlsure' ) . '</p>';
    188190                }
    189191                if ( ! $on ) {
  • crawlsure/trunk/includes/class-crawlsure-indexing.php

    r3768686 r3771047  
    104104         */
    105105        public static function post_types() {
    106                 return array_values( array_diff( get_post_types( array( 'public' => true ) ), array( 'attachment' ) ) );
     106                return Crawlsure_Plugin::content_types();
    107107        }
    108108
    … …  
    326326        public static function stats() {
    327327                global $wpdb;
     328                self::prune();
    328329                $table = Crawlsure_DB::table( 'gsc_index' );
    329330                $row   = $wpdb->get_row( $wpdb->prepare( "SELECT COUNT(*) AS checked, SUM(verdict = 'pass') AS indexed, SUM(verdict <> 'pass' AND error = '') AS nots, SUM(error <> '') AS errors FROM %i", $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
    … …  
    348349                        'total'   => $total,
    349350                );
     351        }
     352
     353        /**
     354         * Forget results for posts that are gone or are not real pages (for example page-builder templates
     355         * checked by earlier versions).
     356         */
     357        public static function prune() {
     358                Crawlsure_Plugin::prune_rows( Crawlsure_DB::table( 'gsc_index' ) );
    350359        }
    351360
  • crawlsure/trunk/includes/class-crawlsure-links.php

    r3771007 r3771047  
    6161         */
    6262        public static function post_types() {
    63                 return array_values( array_diff( get_post_types( array( 'public' => true ) ), array( 'attachment' ) ) );
     63                return Crawlsure_Plugin::content_types();
    6464        }
    6565
    … …  
    235235
    236236        /**
     237         * Forget the links of posts that are gone or are not real pages (for example page-builder templates
     238         * indexed by earlier versions), and the links no page uses any more.
     239         */
     240        public static function prune_refs() {
     241                global $wpdb;
     242                Crawlsure_Plugin::prune_rows( self::link_refs_table() );
     243                $wpdb->query( $wpdb->prepare( 'DELETE l FROM %i l LEFT JOIN %i r ON r.link_id = l.id WHERE r.link_id IS NULL', Crawlsure_DB::table( 'links' ), self::link_refs_table() ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
     244        }
     245
     246        /**
     247         * The table of which page uses which link.
     248         *
     249         * @return string
     250         */
     251        private static function link_refs_table() {
     252                return Crawlsure_DB::table( 'link_refs' );
     253        }
     254
     255        /**
    237256         * Remove a post's links from the index.
    238257         *
    … …  
    294313                $links = Crawlsure_DB::table( 'links' );
    295314                $refs  = Crawlsure_DB::table( 'link_refs' );
     315                self::prune_refs();
    296316                // Links no longer used anywhere are dropped.
    297317                $wpdb->query( $wpdb->prepare( 'DELETE l FROM %i l LEFT JOIN %i r ON r.link_id = l.id WHERE r.link_id IS NULL', $links, $refs ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
    … …  
    470490        public static function stats() {
    471491                global $wpdb;
     492                self::prune_refs();
    472493                $t     = Crawlsure_DB::table( 'links' );
    473494                $row   = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
  • crawlsure/trunk/includes/class-crawlsure-pages.php

    r3768686 r3771047  
    121121                $limit = is_numeric( $limit ) && (int) $limit > 0 ? (int) $limit : self::BATCH;
    122122                $table = Crawlsure_DB::table( 'page_checks' );
     123                Crawlsure_Plugin::prune_rows( $table );
    123124                self::sync();
    124125                $site = get_option( self::SITE_OPTION );
    … …  
    732733                global $wpdb;
    733734                $table   = Crawlsure_DB::table( 'page_checks' );
     735                Crawlsure_Plugin::prune_rows( $table );
    734736                $pages   = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
    735737                $checked = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i WHERE checked IS NOT NULL AND status > 0', $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
  • crawlsure/trunk/includes/class-crawlsure-plugin.php

    r3768686 r3771047  
    169169
    170170        /**
     171         * Content types with real public pages: the ones WordPress lists for its own sitemap (public and
     172         * viewable, minus what plugins take out through wp_sitemaps_post_types, as Elementor does with its
     173         * template library), without page-builder template types that slip through. Used by the link
     174         * checker, page checks and the "In Google" check, so templates and saved layouts are never checked.
     175         *
     176         * @return string[]
     177         */
     178        public static function content_types() {
     179                $objects = array();
     180                foreach ( get_post_types( array( 'public' => true ), 'objects' ) as $name => $object ) {
     181                        if ( 'attachment' !== $name && is_post_type_viewable( $object ) ) {
     182                                $objects[ $name ] = $object;
     183                        }
     184                }
     185                $objects = (array) apply_filters( 'wp_sitemaps_post_types', $objects ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- core hook, read the way WordPress's sitemap reads it.
     186                $types   = array_diff(
     187                        array_keys( $objects ),
     188                        array( 'elementor_library', 'e-floating-buttons', 'elementor-hf', 'et_pb_layout', 'fl-builder-template', 'ct_template', 'oxy_user_library', 'bricks_template', 'brizy_template', 'kadence_element', 'astra-advanced-hook', 'wp_block', 'wp_template', 'wp_template_part', 'wp_navigation' )
     189                );
     190                /**
     191                 * Filter the content types Crawlsure checks (links, page checks, "In Google").
     192                 *
     193                 * @param string[] $types Post type names.
     194                 */
     195                return array_values( (array) apply_filters( 'crawlsure_content_types', array_values( $types ) ) );
     196        }
     197
     198        /**
     199         * Delete a Crawlsure table's rows (keyed by post_id) for posts that are gone or are not real pages.
     200         *
     201         * @param string $table Full table name.
     202         */
     203        public static function prune_rows( $table ) {
     204                global $wpdb;
     205                $types = self::content_types();
     206                if ( ! $types ) {
     207                        return;
     208                }
     209                $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
     210                        $wpdb->prepare(
     211                                'DELETE t FROM %i t LEFT JOIN %i p ON p.ID = t.post_id WHERE p.ID IS NULL OR p.post_type NOT IN (' . implode( ',', array_fill( 0, count( $types ), '%s' ) ) . ')', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQL.NotPrepared -- one placeholder per type.
     212                                array_merge( array( $table, $wpdb->posts ), $types )
     213                        )
     214                );
     215        }
     216
     217        /**
    171218         * Main category of a post: the one chosen in Crawlsure if the post is still in it,
    172219         * otherwise WordPress's first category. Null for posts without categories.
  • crawlsure/trunk/readme.txt

    r3771007 r3771047  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 0.8.4
     7Stable tag: 0.8.5
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    108108== Changelog ==
    109109
     110= 0.8.5 =
     111* Page-builder templates (Elementor templates, saved layouts, headers and footers and the like) are no longer treated as pages: they are left out of the link checker, the page checks and the "In Google" check, and old results for them are cleared. Crawlsure now checks the same content types WordPress puts in its sitemap.
     112* Links and 404s: when nothing can be removed in one go, a short note explains why and what to do instead.
     113
    110114= 0.8.4 =
    111115* Simpler menu: the WordPress sidebar now shows one line per section (Overview, Checks, Search and AI, Your site, Tools, Settings) instead of every page; the Crawlsure header leads to the pages of each section. Setup and Import moved to the new Settings section.
Note: See TracChangeset for help on using the changeset viewer.