@@ -92,7 +92,10 @@ public function action_init() {
9292 * @since 1.0.0
9393 */
9494 public function action_admin_menu () {
95- add_submenu_page ( $ this ->parent_slug , __ ( 'Rewrite Rules Inspector ' , 'rewrite-rules-inspector ' ), __ ( 'Rewrite Rules ' , 'rewrite-rules-inspector ' ), $ this ->view_cap , $ this ->page_slug , array ( $ this , 'view_rules ' ) );
95+ $ hook = add_submenu_page ( $ this ->parent_slug , __ ( 'Rewrite Rules Inspector ' , 'rewrite-rules-inspector ' ), __ ( 'Rewrite Rules ' , 'rewrite-rules-inspector ' ), $ this ->view_cap , $ this ->page_slug , array ( $ this , 'view_rules ' ) );
96+
97+ // Add screen help.
98+ add_action ( 'load- ' . $ hook , array ( $ this , 'add_screen_help ' ) );
9699 }
97100
98101 /**
@@ -104,6 +107,198 @@ public function action_admin_notices() {
104107 echo '<div class="message updated"><p> ' . esc_html__ ( 'Rewrite rules flushed. ' , 'rewrite-rules-inspector ' ) . '</p></div> ' ;
105108 }
106109
110+ /**
111+ * Add screen help tabs to explain rewrite rules and permastructs.
112+ *
113+ * @since 1.5.0
114+ */
115+ public function add_screen_help () {
116+ $ screen = get_current_screen ();
117+
118+ // Overview tab.
119+ $ screen ->add_help_tab (
120+ array (
121+ 'id ' => 'overview ' ,
122+ 'title ' => __ ( 'Overview ' , 'rewrite-rules-inspector ' ),
123+ 'content ' => '<p> ' . __ ( 'The Rewrite Rules Inspector helps you understand and debug your WordPress site \'s URL structure. It shows you all the rewrite rules and permastructs that WordPress uses to handle URLs. ' , 'rewrite-rules-inspector ' ) . '</p> ' ,
124+ )
125+ );
126+
127+ // Rewrite Rules tab.
128+ $ screen ->add_help_tab (
129+ array (
130+ 'id ' => 'rewrite-rules ' ,
131+ 'title ' => __ ( 'Rewrite Rules ' , 'rewrite-rules-inspector ' ),
132+ 'content ' => '<p> ' . __ ( '<strong>Rewrite Rules</strong> are the actual URL patterns that WordPress uses to match incoming requests and determine what content to display. ' , 'rewrite-rules-inspector ' ) . '</p> ' .
133+ '<p> ' . __ ( 'Each rule consists of: ' , 'rewrite-rules-inspector ' ) . '</p> ' .
134+ '<ul> ' .
135+ '<li> ' . __ ( '<strong>Rule:</strong> A regular expression pattern that matches URLs (e.g., <code>^category/([^/]+)/?$</code>) ' , 'rewrite-rules-inspector ' ) . '</li> ' .
136+ '<li> ' . __ ( '<strong>Rewrite:</strong> The internal WordPress query that gets executed (e.g., <code>index.php?category_name=$matches[1]</code>) ' , 'rewrite-rules-inspector ' ) . '</li> ' .
137+ '<li> ' . __ ( '<strong>Source:</strong> Where the rule comes from (e.g., category, post, custom permastruct) ' , 'rewrite-rules-inspector ' ) . '</li> ' .
138+ '</ul> ' .
139+ '<p> ' . __ ( 'When someone visits a URL, WordPress checks these rules in order until it finds a match, then executes the corresponding rewrite to determine what content to show. ' , 'rewrite-rules-inspector ' ) . '</p> ' ,
140+ )
141+ );
142+
143+ // Permastructs tab.
144+ $ screen ->add_help_tab (
145+ array (
146+ 'id ' => 'permastructs ' ,
147+ 'title ' => __ ( 'Permastructs ' , 'rewrite-rules-inspector ' ),
148+ 'content ' => '<p> ' . __ ( '<strong>Permastructs</strong> are the URL structure templates that define how different types of content should be accessed via URLs. ' , 'rewrite-rules-inspector ' ) . '</p> ' .
149+ '<p> ' . __ ( 'For example: ' , 'rewrite-rules-inspector ' ) . '</p> ' .
150+ '<ul> ' .
151+ '<li> ' . __ ( '<strong>Post Permalink:</strong> <code>/%year%/%monthnum%/%day%/%postname%/</code> - defines how individual posts are accessed ' , 'rewrite-rules-inspector ' ) . '</li> ' .
152+ '<li> ' . __ ( '<strong>Category Archive:</strong> <code>/category/%category%</code> - defines how category pages are accessed ' , 'rewrite-rules-inspector ' ) . '</li> ' .
153+ '<li> ' . __ ( '<strong>Tag Archive:</strong> <code>/tag/%post_tag%</code> - defines how tag pages are accessed ' , 'rewrite-rules-inspector ' ) . '</li> ' .
154+ '</ul> ' .
155+ '<p> ' . __ ( 'WordPress uses these permastructs to generate the actual rewrite rules. The permastructs are like blueprints, while the rewrite rules are the specific patterns that get created from those blueprints. ' , 'rewrite-rules-inspector ' ) . '</p> ' .
156+ '<p> ' . __ ( 'You can customize permastructs through WordPress settings (Settings → Permalinks) or by using WordPress functions like <code>add_permastruct()</code> in your theme or plugin. ' , 'rewrite-rules-inspector ' ) . '</p> ' ,
157+ )
158+ );
159+
160+ // Troubleshooting tab.
161+ $ screen ->add_help_tab (
162+ array (
163+ 'id ' => 'troubleshooting ' ,
164+ 'title ' => __ ( 'Troubleshooting ' , 'rewrite-rules-inspector ' ),
165+ 'content ' => '<p> ' . __ ( '<strong>Common Issues:</strong> ' , 'rewrite-rules-inspector ' ) . '</p> ' .
166+ '<ul> ' .
167+ '<li> ' . __ ( '<strong>Missing Rules:</strong> If you see rules marked as "missing", try clicking the "Flush Rules" button to regenerate them. ' , 'rewrite-rules-inspector ' ) . '</li> ' .
168+ '<li> ' . __ ( '<strong>404 Errors:</strong> Check if the URL pattern exists in the rewrite rules. Use the "Match URL" filter to test specific URLs. ' , 'rewrite-rules-inspector ' ) . '</li> ' .
169+ '<li> ' . __ ( '<strong>Custom URLs Not Working:</strong> Verify that your custom permastruct is properly registered and that rewrite rules have been flushed. ' , 'rewrite-rules-inspector ' ) . '</li> ' .
170+ '<li> ' . __ ( '<strong>Plugin Conflicts:</strong> Some plugins may modify rewrite rules. Check the "Source" column to see which rules come from which sources. ' , 'rewrite-rules-inspector ' ) . '</li> ' .
171+ '</ul> ' .
172+ '<p> ' . __ ( '<strong>Tips:</strong> ' , 'rewrite-rules-inspector ' ) . '</p> ' .
173+ '<ul> ' .
174+ '<li> ' . __ ( 'Use the "Rule Source" filter to focus on specific types of rules. ' , 'rewrite-rules-inspector ' ) . '</li> ' .
175+ '<li> ' . __ ( 'Download the rules as a text file for offline analysis. ' , 'rewrite-rules-inspector ' ) . '</li> ' .
176+ '<li> ' . __ ( 'Check the permastructs section to understand the URL structure templates. ' , 'rewrite-rules-inspector ' ) . '</li> ' .
177+ '</ul> ' ,
178+ )
179+ );
180+
181+ // Help sidebar.
182+ $ screen ->set_help_sidebar (
183+ '<p><strong> ' . __ ( 'For more information: ' , 'rewrite-rules-inspector ' ) . '</strong></p> ' .
184+ '<p><a href="https://wordpress.org/support/article/using-permalinks/" target="_blank"> ' . __ ( 'WordPress Permalinks Documentation ' , 'rewrite-rules-inspector ' ) . '</a></p> ' .
185+ '<p><a href="https://developer.wordpress.org/reference/functions/add_rewrite_rule/" target="_blank"> ' . __ ( 'WordPress Rewrite API ' , 'rewrite-rules-inspector ' ) . '</a></p> ' .
186+ '<p><a href="https://github.com/Automattic/Rewrite-Rules-Inspector" target="_blank"> ' . __ ( 'Plugin on GitHub ' , 'rewrite-rules-inspector ' ) . '</a></p> '
187+ );
188+ }
189+
190+ /**
191+ * Get all permastructs that WordPress is aware of.
192+ *
193+ * @since 1.5.0
194+ * @return array Array of permastructs with their names and structures.
195+ */
196+ public function get_permastructs () {
197+ global $ wp_rewrite ;
198+
199+ $ permastructs = array ();
200+
201+ // Core permastructs.
202+ $ permastructs ['post ' ] = array (
203+ 'name ' => __ ( 'Post Permalink ' , 'rewrite-rules-inspector ' ),
204+ 'structure ' => $ wp_rewrite ->permalink_structure ,
205+ 'description ' => __ ( 'The permalink structure for posts ' , 'rewrite-rules-inspector ' ),
206+ );
207+
208+ $ permastructs ['date ' ] = array (
209+ 'name ' => __ ( 'Date Archive ' , 'rewrite-rules-inspector ' ),
210+ 'structure ' => $ wp_rewrite ->get_date_permastruct (),
211+ 'description ' => __ ( 'The permalink structure for date archives ' , 'rewrite-rules-inspector ' ),
212+ );
213+
214+ $ permastructs ['search ' ] = array (
215+ 'name ' => __ ( 'Search Results ' , 'rewrite-rules-inspector ' ),
216+ 'structure ' => $ wp_rewrite ->get_search_permastruct (),
217+ 'description ' => __ ( 'The permalink structure for search results ' , 'rewrite-rules-inspector ' ),
218+ );
219+
220+ $ permastructs ['author ' ] = array (
221+ 'name ' => __ ( 'Author Archive ' , 'rewrite-rules-inspector ' ),
222+ 'structure ' => $ wp_rewrite ->get_author_permastruct (),
223+ 'description ' => __ ( 'The permalink structure for author archives ' , 'rewrite-rules-inspector ' ),
224+ );
225+
226+ $ permastructs ['comments ' ] = array (
227+ 'name ' => __ ( 'Comments ' , 'rewrite-rules-inspector ' ),
228+ 'structure ' => $ wp_rewrite ->root . $ wp_rewrite ->comments_base ,
229+ 'description ' => __ ( 'The permalink structure for comments ' , 'rewrite-rules-inspector ' ),
230+ );
231+
232+ $ permastructs ['root ' ] = array (
233+ 'name ' => __ ( 'Root ' , 'rewrite-rules-inspector ' ),
234+ 'structure ' => $ wp_rewrite ->root . '/ ' ,
235+ 'description ' => __ ( 'The root permalink structure ' , 'rewrite-rules-inspector ' ),
236+ );
237+
238+ // Extra permastructs including tags, categories, etc.
239+ foreach ( $ wp_rewrite ->extra_permastructs as $ permastructname => $ permastruct ) {
240+ $ structure = '' ;
241+ if ( is_array ( $ permastruct ) ) {
242+ // Pre 3.4 compat.
243+ if ( count ( $ permastruct ) === 2 ) {
244+ $ structure = $ permastruct [0 ];
245+ } else {
246+ $ structure = $ permastruct ['struct ' ] ?? '' ;
247+ }
248+ } else {
249+ $ structure = $ permastruct ;
250+ }
251+
252+ // Generate human-readable names and descriptions.
253+ $ name = ucwords ( str_replace ( array ( '_ ' , '- ' ), ' ' , $ permastructname ) );
254+ /* translators: %s: permastruct name */
255+ $ description = sprintf ( __ ( 'The permalink structure for %s ' , 'rewrite-rules-inspector ' ), strtolower ( $ name ) );
256+
257+ // Special cases for common permastructs.
258+ switch ( $ permastructname ) {
259+ case 'category ' :
260+ $ name = __ ( 'Category Archive ' , 'rewrite-rules-inspector ' );
261+ $ description = __ ( 'The permalink structure for category archives ' , 'rewrite-rules-inspector ' );
262+ break ;
263+ case 'post_tag ' :
264+ $ name = __ ( 'Tag Archive ' , 'rewrite-rules-inspector ' );
265+ $ description = __ ( 'The permalink structure for tag archives ' , 'rewrite-rules-inspector ' );
266+ break ;
267+ case 'post_format ' :
268+ $ name = __ ( 'Post Format Archive ' , 'rewrite-rules-inspector ' );
269+ $ description = __ ( 'The permalink structure for post format archives ' , 'rewrite-rules-inspector ' );
270+ break ;
271+ case 'test_custom ' :
272+ $ name = __ ( 'Test Custom (Demo) ' , 'rewrite-rules-inspector ' );
273+ $ description = __ ( 'A custom permastruct added for testing the permastructs display feature ' , 'rewrite-rules-inspector ' );
274+ break ;
275+ case 'demo_archive ' :
276+ $ name = __ ( 'Demo Archive (Test) ' , 'rewrite-rules-inspector ' );
277+ $ description = __ ( 'A demo archive permastruct with date-based structure for testing ' , 'rewrite-rules-inspector ' );
278+ break ;
279+ }
280+
281+ $ permastructs [ $ permastructname ] = array (
282+ 'name ' => $ name ,
283+ 'structure ' => $ structure ,
284+ 'description ' => $ description ,
285+ );
286+ }
287+
288+ // Filter out empty structures.
289+ $ permastructs = array_filter (
290+ $ permastructs ,
291+ function ( $ permastruct ) {
292+ return ! empty ( $ permastruct ['structure ' ] );
293+ }
294+ );
295+
296+ // Allow filtering of permastructs.
297+ $ permastructs = apply_filters ( 'rri_permastructs ' , $ permastructs );
298+
299+ return $ permastructs ;
300+ }
301+
107302 /**
108303 * Get the rewrite rules for the current view.
109304 *
@@ -250,15 +445,38 @@ public function view_rules() {
250445 border-top-color: #fecfd0;
251446 border-bottom-color: #f99b9d;
252447 }
448+ #permastructs-section {
449+ margin-top: 30px;
450+ }
451+ .permastruct-structure {
452+ font-family: monospace;
453+ background: #f6f7f7;
454+ padding: 2px 6px;
455+ border-radius: 3px;
456+ font-size: 13px;
457+ }
253458 </style>
254459 <div class="wrap">
255460 <h1><?php echo esc_html ( get_admin_page_title () ); ?> </h1>
256461
462+ <?php
463+ // Get permastructs for jump link.
464+ $ permastructs = $ this ->get_permastructs ();
465+ ?>
466+
467+ <h2 id="rewrite-rules-section"><?php esc_html_e ( 'Rewrite Rules ' , 'rewrite-rules-inspector ' ); ?> </h2>
468+
469+ <?php if ( ! empty ( $ permastructs ) ) : ?>
470+ <p>
471+ <a href="#permastructs-section"><?php esc_html_e ( 'Jump to Permastructs ' , 'rewrite-rules-inspector ' ); ?> </a>
472+ </p>
473+ <?php endif ; ?>
474+
257475 <?php
258476 $ missing_count = 0 ;
259477 foreach ( $ rules as $ rule ) {
260478 if ( 'missing ' === $ rule ['source ' ] ) {
261- $ missing_count ++ ;
479+ ++ $ missing_count ;
262480 }
263481 }
264482
@@ -286,10 +504,90 @@ public function view_rules() {
286504 printf ( esc_html__ ( 'A listing of all %1$s rewrite rules for this site. ' , 'rewrite-rules-inspector ' ), count ( $ wp_list_table ->items ) );
287505 ?>
288506 </p>
289- <?php endif ;
507+ <?php endif ; ?>
290508
291- $ wp_list_table ->display ();
292- ?>
509+ <?php $ wp_list_table ->display (); ?>
510+
511+ <?php if ( ! empty ( $ permastructs ) ) : ?>
512+ <h2 id="permastructs-section"><?php esc_html_e ( 'Permastructs ' , 'rewrite-rules-inspector ' ); ?> </h2>
513+
514+ <p>
515+ <?php
516+ /* translators: %d: Count of permastructs */
517+ printf ( esc_html__ ( 'A listing of all %d permastructs that WordPress is aware of. ' , 'rewrite-rules-inspector ' ), count ( $ permastructs ) );
518+ ?>
519+ <a href="#rewrite-rules-section"><?php esc_html_e ( 'Jump to Rewrite Rules ' , 'rewrite-rules-inspector ' ); ?> </a>
520+ </p>
521+
522+ <?php
523+ // Create a simple list table for permastructs.
524+ $ permastructs_table = new WP_List_Table (
525+ array (
526+ 'singular ' => 'Permastruct ' ,
527+ 'plural ' => 'Permastructs ' ,
528+ )
529+ );
530+
531+ // Set up the columns.
532+ $ permastructs_table ->_column_headers = array (
533+ array (
534+ 'name ' => __ ( 'Name ' , 'rewrite-rules-inspector ' ),
535+ 'structure ' => __ ( 'Structure ' , 'rewrite-rules-inspector ' ),
536+ 'description ' => __ ( 'Description ' , 'rewrite-rules-inspector ' ),
537+ ),
538+ array (),
539+ array (),
540+ );
541+
542+ // Set the items.
543+ $ permastructs_table ->items = $ permastructs ;
544+
545+ // Display the table.
546+ ?>
547+ <table class="wp-list-table widefat fixed striped">
548+ <thead>
549+ <tr>
550+ <th scope="col" class="manage-column column-name column-primary">
551+ <?php esc_html_e ( 'Name ' , 'rewrite-rules-inspector ' ); ?>
552+ </th>
553+ <th scope="col" class="manage-column column-structure">
554+ <?php esc_html_e ( 'Structure ' , 'rewrite-rules-inspector ' ); ?>
555+ </th>
556+ <th scope="col" class="manage-column column-description">
557+ <?php esc_html_e ( 'Description ' , 'rewrite-rules-inspector ' ); ?>
558+ </th>
559+ </tr>
560+ </thead>
561+ <tbody id="the-list">
562+ <?php foreach ( $ permastructs as $ permastruct ) : ?>
563+ <tr>
564+ <td class="name column-name column-primary">
565+ <strong><?php echo esc_html ( $ permastruct ['name ' ] ); ?> </strong>
566+ </td>
567+ <td class="structure column-structure">
568+ <code class="permastruct-structure"><?php echo esc_html ( $ permastruct ['structure ' ] ); ?> </code>
569+ </td>
570+ <td class="description column-description">
571+ <?php echo esc_html ( $ permastruct ['description ' ] ); ?>
572+ </td>
573+ </tr>
574+ <?php endforeach ; ?>
575+ </tbody>
576+ <tfoot>
577+ <tr>
578+ <th scope="col" class="manage-column column-name column-primary">
579+ <?php esc_html_e ( 'Name ' , 'rewrite-rules-inspector ' ); ?>
580+ </th>
581+ <th scope="col" class="manage-column column-structure">
582+ <?php esc_html_e ( 'Structure ' , 'rewrite-rules-inspector ' ); ?>
583+ </th>
584+ <th scope="col" class="manage-column column-description">
585+ <?php esc_html_e ( 'Description ' , 'rewrite-rules-inspector ' ); ?>
586+ </th>
587+ </tr>
588+ </tfoot>
589+ </table>
590+ <?php endif ; ?>
293591 </div>
294592 <?php
295593 }
0 commit comments