Changeset 3788580
- Timestamp:
- 11/06/2026 07:05:54 PM (2 hours ago)
- Location:
- w4-post-list
- Files:
-
- 14 edited
- 1 copied
-
tags/3.1.0 (copied) (copied from w4-post-list/trunk )
-
tags/3.1.0/includes/class-w4-post-list.php (modified) (1 diff)
-
tags/3.1.0/includes/class-widget-postlist.php (modified) (4 diffs)
-
tags/3.1.0/includes/functions.php (modified) (1 diff)
-
tags/3.1.0/includes/helpers/class-helper-style.php (modified) (7 diffs)
-
tags/3.1.0/languages/w4-post-list.pot (modified) (5 diffs)
-
tags/3.1.0/readme.txt (modified) (2 diffs)
-
tags/3.1.0/w4-post-list.php (modified) (1 diff)
-
trunk/includes/class-w4-post-list.php (modified) (1 diff)
-
trunk/includes/class-widget-postlist.php (modified) (4 diffs)
-
trunk/includes/functions.php (modified) (1 diff)
-
trunk/includes/helpers/class-helper-style.php (modified) (7 diffs)
-
trunk/languages/w4-post-list.pot (modified) (5 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/w4-post-list.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
w4-post-list/tags/3.1.0/includes/class-w4-post-list.php
r3724093 r3788580 30 30 * @var string 31 31 */ 32 public $version = '3. 0.9';32 public $version = '3.1.0'; 33 33 34 34 /** -
w4-post-list/tags/3.1.0/includes/class-widget-postlist.php
r2883184 r3788580 13 13 * Postlist Widget Class 14 14 * 15 * Kept for classic (widget-area) themes. Block themes place a list with the 16 * W4 Post List block instead, which is what the description points to. 17 * 15 18 * @class W4PL_Widget_Postlist 16 19 */ 17 20 class W4PL_Widget_Postlist extends WP_Widget { 18 21 19 function __construct() { 22 /** 23 * Constructor 24 */ 25 public function __construct() { 20 26 parent::__construct( 21 27 'w4_post_list', 22 28 __( 'W4 Post List', 'w4-post-list' ), 23 29 array( 24 'classname' => 'w4pl_widget', 25 'description' => __( 'Display lists created with W4 Post List', 'w4-post-list' ), 30 'classname' => 'w4pl_widget', 31 'description' => __( 'Show a list made with W4 Post List. In the block editor, use the W4 Post List block instead.', 'w4-post-list' ), 32 'customize_selective_refresh' => true, 26 33 ), 27 34 array( … … 32 39 } 33 40 34 function widget( $args, $instance ) { 35 extract( $args ); 36 37 if ( empty( $instance['id'] ) ) { 38 return ''; 41 /** 42 * Front-end output. 43 * 44 * @param array $args Widget area arguments (before/after markup from the theme). 45 * @param array $instance Saved widget settings. 46 */ 47 public function widget( $args, $instance ) { 48 $list_id = 0; 49 if ( isset( $instance['id'] ) ) { 50 $list_id = (int) $instance['id']; 39 51 } 40 52 41 $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); 42 43 echo $before_widget; 44 45 if ( $title ) { 46 echo $before_title . $title . $after_title; 53 if ( $list_id < 1 ) { 54 return; 47 55 } 48 56 49 echo do_shortcode( '[postlist id="' . $instance['id'] . '"]' ); 57 $args = wp_parse_args( 58 $args, 59 array( 60 'before_widget' => '', 61 'after_widget' => '', 62 'before_title' => '', 63 'after_title' => '', 64 ) 65 ); 50 66 51 echo $after_widget; 67 $title = ''; 68 if ( isset( $instance['title'] ) ) { 69 $title = $instance['title']; 70 } 71 $title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); 72 73 // The before/after strings are the theme's own sidebar markup, printed 74 // as every core widget prints them. 75 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 76 77 if ( '' !== $title ) { 78 echo $args['before_title'] . wp_kses_post( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 79 } 80 81 // The list is rendered by the plugin's own pipeline; the shortcode 82 // output is the product, already assembled from escaped tags. 83 echo do_shortcode( '[postlist id="' . $list_id . '"]' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 84 85 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 52 86 } 53 87 54 function update( $new_instance, $old_instance ) { 88 /** 89 * Sanitize the settings before they are saved. 90 * 91 * @param array $new_instance Submitted settings. 92 * @param array $old_instance Previously saved settings. 93 * @return array 94 */ 95 public function update( $new_instance, $old_instance ) { 55 96 $instance = $old_instance; 56 $instance['title'] = strip_tags( $new_instance['title'] ); 57 $instance['id'] = (int) $new_instance['id']; 97 $instance['title'] = ''; 98 $instance['id'] = 0; 99 100 if ( isset( $new_instance['title'] ) ) { 101 $instance['title'] = sanitize_text_field( $new_instance['title'] ); 102 } 103 if ( isset( $new_instance['id'] ) ) { 104 $instance['id'] = (int) $new_instance['id']; 105 } 58 106 59 107 return $instance; 60 108 } 61 109 62 function form( $instance ) { 63 $title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : ''; 64 $id = isset( $instance['id'] ) ? (int) ( $instance['id'] ) : 0; 110 /** 111 * Settings form. 112 * 113 * @param array $instance Saved widget settings. 114 */ 115 public function form( $instance ) { 116 $title = ''; 117 $id = 0; 118 119 if ( isset( $instance['title'] ) ) { 120 $title = $instance['title']; 121 } 122 if ( isset( $instance['id'] ) ) { 123 $id = (int) $instance['id']; 124 } 65 125 66 126 $lists = get_posts( … … 69 129 'post_type' => W4PL_Config::LIST_POST_TYPE, 70 130 'posts_per_page' => -1, 131 'orderby' => 'title', 132 'order' => 'ASC', 71 133 ) 72 134 ); … … 74 136 ?> 75 137 <p> 76 <strong> 77 <?php _e( 'Title', 'w4-post-list' ); ?>: 78 </strong> 79 <br /><input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" 80 name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo $title; ?>" /> 138 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"> 139 <?php esc_html_e( 'Title:', 'w4-post-list' ); ?> 140 </label> 141 <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" 142 name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" 143 value="<?php echo esc_attr( $title ); ?>" /> 81 144 </p> 82 145 <p> 83 < strong>84 <?php _e( 'Select a list', 'w4-post-list' ); ?>:85 </ strong>86 < br />87 <select id="<?php echo $this->get_field_id( 'id' ); ?>" name="<?php echo $this->get_field_name( 'id'); ?>">88 < ?php89 90 $id = (int) $id;91 92 foreach ( $lists as $list ) {93 printf(94 '<option value="%d"%s>%s</option>',95 $list->ID,96 $id === $list->ID ? ' selected="selected"' : '',97 e mpty( $list->post_title ) ? 'List#' . $list->ID : $list->post_title98 );99 }100 ?>146 <label for="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>"> 147 <?php esc_html_e( 'List:', 'w4-post-list' ); ?> 148 </label> 149 <select class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>" 150 name="<?php echo esc_attr( $this->get_field_name( 'id' ) ); ?>"> 151 <option value="0"<?php selected( $id, 0 ); ?>><?php esc_html_e( '— Select a list —', 'w4-post-list' ); ?></option> 152 <?php foreach ( $lists as $list ) : ?> 153 <option value="<?php echo esc_attr( $list->ID ); ?>"<?php selected( $id, $list->ID ); ?>> 154 <?php 155 $label = $list->post_title; 156 if ( '' === $label ) { 157 /* translators: %d: list ID */ 158 $label = sprintf( __( 'List #%d', 'w4-post-list' ), $list->ID ); 159 } 160 echo esc_html( $label ); 161 ?> 162 </option> 163 <?php endforeach; ?> 101 164 </select> 102 <br /> 103 <?php _e( 'OR', 'w4-post-list' ); ?> 104 <br /> 105 <a class="button" 106 href="<?php echo esc_url( admin_url( 'post-new.php?post_type=' . W4PL_Config::LIST_POST_TYPE ) ); ?>"> 107 <?php _e( 'Create a new one', 'w4-post-list' ); ?> 165 </p> 166 <p> 167 <a class="button" href="<?php echo esc_url( admin_url( 'post-new.php?post_type=' . W4PL_Config::LIST_POST_TYPE ) ); ?>"> 168 <?php esc_html_e( 'Create a new list', 'w4-post-list' ); ?> 108 169 </a> 109 170 </p> -
w4-post-list/tags/3.1.0/includes/functions.php
r3724093 r3788580 118 118 119 119 /** 120 * The style and script handle a list's own CSS and JavaScript print under. 121 * 122 * @since 3.1.0 123 * 124 * @param int $list_id List ID. 125 * @return string 126 */ 127 function w4pl_list_asset_handle( $list_id ) { 128 return 'w4pl-list-' . (int) $list_id; 129 } 130 131 /** 132 * The list's CSS as a style tag, through the WordPress style API. 133 * 134 * The CSS is attached to a src-less per-list handle and printed in place, 135 * where the raw tag used to be. Every render prints its own tag, as every 136 * render did through 3.0.9: a render whose output is thrown away (an excerpt 137 * built from `the_content`, an Open Graph scanner) must not use up the tag 138 * the visible render needs, so the handle is taken off the printed list 139 * first. The data stays readable through `wp_styles()->get_data()`. 140 * 141 * @since 3.1.0 142 * 143 * @param int $list_id List ID. 144 * @param string $css The list's CSS, `[listid]` already replaced. 145 * @return string Style tag. 146 */ 147 function w4pl_get_list_inline_style( $list_id, $css ) { 148 $handle = w4pl_list_asset_handle( $list_id ); 149 $styles = wp_styles(); 150 151 if ( ! wp_style_is( $handle, 'registered' ) ) { 152 wp_register_style( $handle, false, array(), W4PL_VERSION ); 153 wp_add_inline_style( $handle, $css ); 154 } 155 156 $styles->done = array_diff( $styles->done, array( $handle ) ); 157 158 // Not wp_print_styles(): that would also run the once-per-page 159 // `wp_print_styles` action from inside the content. 160 ob_start(); 161 $styles->do_items( array( $handle ) ); 162 163 return (string) ob_get_clean(); 164 } 165 166 /** 167 * The list's JavaScript as a script tag, through the WordPress script API. 168 * 169 * Same contract as w4pl_get_list_inline_style(): printed in place, once per 170 * render. On WordPress 6.3+ the tag carries whatever the 171 * `wp_inline_script_attributes` filter adds, so a CSP plugin's nonce covers it. 172 * 173 * @since 3.1.0 174 * 175 * @param int $list_id List ID. 176 * @param string $js The list's JavaScript, `[listid]` already replaced. 177 * @return string Script tag. 178 */ 179 function w4pl_get_list_inline_script( $list_id, $js ) { 180 $handle = w4pl_list_asset_handle( $list_id ); 181 $scripts = wp_scripts(); 182 183 if ( ! wp_script_is( $handle, 'registered' ) ) { 184 wp_register_script( $handle, false, array(), W4PL_VERSION, false ); 185 wp_add_inline_script( $handle, $js ); 186 } 187 188 $scripts->done = array_diff( $scripts->done, array( $handle ) ); 189 190 // Not wp_print_scripts(): that fires the once-per-page `wp_print_scripts` 191 // action every time it is called. 192 ob_start(); 193 $scripts->do_items( array( $handle ) ); 194 195 return (string) ob_get_clean(); 196 } 197 198 /** 120 199 * The page of a list the request asks for, from page{list id}. 121 200 * -
w4-post-list/tags/3.1.0/includes/helpers/class-helper-style.php
r3625190 r3788580 12 12 13 13 /** 14 * Meta query implementor class14 * Per-list CSS / JavaScript: editor fields, defaults and output. 15 15 * 16 16 * @class W4PL_Helper_Style … … 31 31 * Style control field on list editor 32 32 * 33 * @param array $fields List editor fields.34 * @param array $ options List options.35 * @return array List editor fields.33 * @param array $fields List editor fields. 34 * @param array $post_data List post data. 35 * @return array List editor fields. 36 36 */ 37 37 public function list_edit_form_fields( $fields, $post_data ) { … … 52 52 'input_class' => 'widefat', 53 53 'desc2' => sprintf( 54 /* translators: %s: list ID */ 54 55 __( 55 ' this css rules is placed inline just before the list is place at front-end(not in the HEAD tag).56 <br /> to apply css just for current list, use <code>#w4pl-list-%s</code> asparent selector.57 <br />Alternatively, you can use <code>#w4pl-list-[listid]</code> to dynamically this selector.',56 'Printed right before the list (not in the HEAD tag). 57 <br />To style just this list, use <code>#w4pl-list-%s</code> as the parent selector. 58 <br />Alternatively, use <code>#w4pl-list-[listid]</code> and the ID is filled in for you.', 58 59 'w4-post-list' 59 60 ), … … 69 70 'type' => 'textarea', 70 71 'input_class' => 'widefat', 71 'desc2' => __( ' javascript loads right after template ends. don\'t use <code><script></code> tag', 'w4-post-list' ),72 'desc2' => __( 'Runs right after the list. Don\'t use a <code><script></code> tag.', 'w4-post-list' ), 72 73 'after' => '</div><!--.w4pl_group_fields--></div><!--#w4pl_field_group_style-->', 73 74 ); … … 95 96 */ 96 97 public function pre_save_options( $options ) { 97 foreach ( array( 'class' => '', 'js' => '', 'css' => '', ) as $k => $v) {98 foreach ( array( 'class', 'js', 'css' ) as $k ) { 98 99 if ( array_key_exists( $k, $options ) && empty( $options[ $k ] ) ) { 99 100 unset( $options[ $k ] ); … … 129 130 * Parse list render html to include css/js. 130 131 * 131 * @param object $obj Instance of W4PL_List 132 * The list's CSS and JavaScript go through the WordPress style and script 133 * API under a per-list handle (`w4pl-list-{id}`) and are printed in place, 134 * where the raw `<style>` / `<script>` tags used to be: the CSS right 135 * before the list, the JavaScript right after it, on every render, as 136 * before. Going through the API means the inline script tag carries 137 * whatever `wp_inline_script_attributes` adds (CSP nonces, on WordPress 138 * 6.3+), and site owners can read the data through `wp_styles()` / 139 * `wp_scripts()`. 140 * 141 * Printing in place rather than from the footer keeps every consumer of 142 * the returned HTML working unchanged: the admin live preview and the 143 * block editor's server-side render have no `wp_footer`, and a list 144 * rendered after `wp_print_footer_scripts` would otherwise lose its CSS. 145 * 146 * @param object $obj Instance of W4PL_List. 132 147 */ 133 148 public function parse_html( $obj ) { 134 // unique list class149 // Unique list class. 135 150 $class = trim( 'w4pl ' . $obj->options['class'] ); 136 151 $obj->html = str_replace( 'id="w4pl-list-' . $obj->id . '"', 'id="w4pl-list-' . $obj->id . '" class="' . $class . '"', $obj->html ); … … 146 161 // Css push. 147 162 if ( ! empty( $obj->css ) ) { 148 $obj->html = '<style id="w4pl-css-' . $obj->id . '" type="text/css">' . $obj->css . '</style>' . "\n". $obj->html;163 $obj->html = w4pl_get_list_inline_style( $obj->id, $obj->css ) . $obj->html; 149 164 } 150 165 151 166 // Js push. 152 167 if ( ! empty( $obj->js ) ) { 153 $obj->html .= "\n" . '<script id="w4pl-js-' . $obj->id . '" type="text/javascript">' . $obj->js . '</script>' . "\n";168 $obj->html .= "\n" . w4pl_get_list_inline_script( $obj->id, $obj->js ); 154 169 } 155 170 } -
w4-post-list/tags/3.1.0/languages/w4-post-list.pot
r3724093 r3788580 4 4 "Project-Id-Version: W4 Post List\n" 5 5 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/w4-post-list/\n" 6 "POT-Creation-Date: 2026-1 0-02 02:48:42+00:00\n"6 "POT-Creation-Date: 2026-11-06 19:05:29+00:00\n" 7 7 "MIME-Version: 1.0\n" 8 8 "Content-Type: text/plain; charset=utf-8\n" … … 685 685 msgstr "" 686 686 687 #: includes/class-config.php:29 includes/class-widget-postlist.php:77687 #: includes/class-config.php:29 688 688 msgid "Title" 689 689 msgstr "" … … 854 854 msgstr "" 855 855 856 #: includes/class-widget-postlist.php:25 857 msgid "Display lists created with W4 Post List" 858 msgstr "" 859 860 #: includes/class-widget-postlist.php:84 861 msgid "Select a list" 862 msgstr "" 863 864 #: includes/class-widget-postlist.php:103 865 #: includes/helpers/class-helper-posts-date_query.php:89 866 #: includes/helpers/class-helper-posts-meta_query.php:164 867 msgid "OR" 868 msgstr "" 869 870 #: includes/class-widget-postlist.php:107 871 msgid "Create a new one" 856 #: includes/class-widget-postlist.php:31 857 msgid "" 858 "Show a list made with W4 Post List. In the block editor, use the W4 Post " 859 "List block instead." 860 msgstr "" 861 862 #: includes/class-widget-postlist.php:139 863 msgid "Title:" 864 msgstr "" 865 866 #: includes/class-widget-postlist.php:147 867 msgid "List:" 868 msgstr "" 869 870 #: includes/class-widget-postlist.php:151 871 msgid "— Select a list —" 872 msgstr "" 873 874 #: includes/class-widget-postlist.php:158 875 #. translators: %d: list ID 876 msgid "List #%d" 877 msgstr "" 878 879 #: includes/class-widget-postlist.php:168 880 msgid "Create a new list" 872 881 msgstr "" 873 882 … … 1051 1060 #: includes/helpers/class-helper-posts-tax_query.php:216 1052 1061 msgid "Relation" 1062 msgstr "" 1063 1064 #: includes/helpers/class-helper-posts-date_query.php:89 1065 #: includes/helpers/class-helper-posts-meta_query.php:164 1066 msgid "OR" 1053 1067 msgstr "" 1054 1068 … … 1366 1380 msgstr "" 1367 1381 1368 #: includes/helpers/class-helper-style.php:5 41369 msgid "" 1370 "this css rules is placed inline just before the list is place at front-end"1371 " (not in the HEAD tag).\n"1372 "\t\t\t\t\t\t\t\t<br /> to apply css just for currentlist, use "1373 "<code>#w4pl-list-%s</code> as parent selector.\n"1374 "\t\t\t\t\t\t\t\t<br />Alternatively, you can use"1375 " <code>#w4pl-list-[listid]</code> to dynamically this selector."1376 msgstr "" 1377 1378 #: includes/helpers/class-helper-style.php:6 81382 #: includes/helpers/class-helper-style.php:55 1383 #. translators: %s: list ID 1384 msgid "" 1385 "Printed right before the list (not in the HEAD tag).\n" 1386 "\t\t\t\t\t\t\t\t<br />To style just this list, use " 1387 "<code>#w4pl-list-%s</code> as the parent selector.\n" 1388 "\t\t\t\t\t\t\t\t<br />Alternatively, use <code>#w4pl-list-[listid]</code> " 1389 "and the ID is filled in for you." 1390 msgstr "" 1391 1392 #: includes/helpers/class-helper-style.php:69 1379 1393 msgid "JavaScript" 1380 1394 msgstr "" 1381 1395 1382 #: includes/helpers/class-helper-style.php:71 1383 msgid "" 1384 "javascript loads right after template ends. don't use " 1385 "<code><script></code> tag" 1386 msgstr "" 1387 1388 #: includes/helpers/class-helper-style.php:78 1396 #: includes/helpers/class-helper-style.php:72 1397 msgid "Runs right after the list. Don't use a <code><script></code> tag." 1398 msgstr "" 1399 1400 #: includes/helpers/class-helper-style.php:79 1389 1401 msgid "HTML class name" 1390 1402 msgstr "" 1391 1403 1392 #: includes/helpers/class-helper-style.php:8 01404 #: includes/helpers/class-helper-style.php:81 1393 1405 msgid "applied on the wrapper html DIV tag" 1394 1406 msgstr "" -
w4-post-list/tags/3.1.0/readme.txt
r3724093 r3788580 3 3 Tags: post list, user list, post grid, category list, shortcode 4 4 Requires at least: 5.8 5 Tested up to: 7.1. 25 Tested up to: 7.1.4 6 6 Requires PHP: 7.4 7 Stable tag: 3. 0.97 Stable tag: 3.1.0 8 8 License: GPLv3 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 135 135 136 136 == Changelog == 137 = 3.1.0 = 138 * Improved: A list's CSS and JavaScript print in the same place as before but through WordPress's own style and script API, so on WordPress 6.3+ a CSP plugin's nonce covers the list's script and developers can read a list's CSS and JavaScript from `wp_styles()` / `wp_scripts()` under the handle `w4pl-list-{id}`. 139 * Improved: The classic widget has a "— Select a list —" placeholder, lists sorted by title, escaped output and a description that points block editors to the W4 Post List block. 140 * Tested up to WordPress 7.1.4. 137 141 = 3.0.9 = 138 142 * Fix: AJAX pagination keeps the list's page when visitors go Back, Forward or reload. Each page is recorded in the address bar, so a visitor who opens a post and comes back lands on the page they were reading. -
w4-post-list/tags/3.1.0/w4-post-list.php
r3724093 r3788580 4 4 * Plugin URI: https://w4dev.com/plugins/w4-post-list 5 5 * Description: Create lists of posts, terms and users — grouped archives, taxonomy indexes and user directories — placed anywhere with the block, [postlist] shortcode or widget. 6 * Version: 3. 0.96 * Version: 3.1.0 7 7 * Requires at least: 5.8 8 8 * Requires PHP: 7.4 -
w4-post-list/trunk/includes/class-w4-post-list.php
r3724093 r3788580 30 30 * @var string 31 31 */ 32 public $version = '3. 0.9';32 public $version = '3.1.0'; 33 33 34 34 /** -
w4-post-list/trunk/includes/class-widget-postlist.php
r2883184 r3788580 13 13 * Postlist Widget Class 14 14 * 15 * Kept for classic (widget-area) themes. Block themes place a list with the 16 * W4 Post List block instead, which is what the description points to. 17 * 15 18 * @class W4PL_Widget_Postlist 16 19 */ 17 20 class W4PL_Widget_Postlist extends WP_Widget { 18 21 19 function __construct() { 22 /** 23 * Constructor 24 */ 25 public function __construct() { 20 26 parent::__construct( 21 27 'w4_post_list', 22 28 __( 'W4 Post List', 'w4-post-list' ), 23 29 array( 24 'classname' => 'w4pl_widget', 25 'description' => __( 'Display lists created with W4 Post List', 'w4-post-list' ), 30 'classname' => 'w4pl_widget', 31 'description' => __( 'Show a list made with W4 Post List. In the block editor, use the W4 Post List block instead.', 'w4-post-list' ), 32 'customize_selective_refresh' => true, 26 33 ), 27 34 array( … … 32 39 } 33 40 34 function widget( $args, $instance ) { 35 extract( $args ); 36 37 if ( empty( $instance['id'] ) ) { 38 return ''; 41 /** 42 * Front-end output. 43 * 44 * @param array $args Widget area arguments (before/after markup from the theme). 45 * @param array $instance Saved widget settings. 46 */ 47 public function widget( $args, $instance ) { 48 $list_id = 0; 49 if ( isset( $instance['id'] ) ) { 50 $list_id = (int) $instance['id']; 39 51 } 40 52 41 $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); 42 43 echo $before_widget; 44 45 if ( $title ) { 46 echo $before_title . $title . $after_title; 53 if ( $list_id < 1 ) { 54 return; 47 55 } 48 56 49 echo do_shortcode( '[postlist id="' . $instance['id'] . '"]' ); 57 $args = wp_parse_args( 58 $args, 59 array( 60 'before_widget' => '', 61 'after_widget' => '', 62 'before_title' => '', 63 'after_title' => '', 64 ) 65 ); 50 66 51 echo $after_widget; 67 $title = ''; 68 if ( isset( $instance['title'] ) ) { 69 $title = $instance['title']; 70 } 71 $title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); 72 73 // The before/after strings are the theme's own sidebar markup, printed 74 // as every core widget prints them. 75 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 76 77 if ( '' !== $title ) { 78 echo $args['before_title'] . wp_kses_post( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 79 } 80 81 // The list is rendered by the plugin's own pipeline; the shortcode 82 // output is the product, already assembled from escaped tags. 83 echo do_shortcode( '[postlist id="' . $list_id . '"]' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 84 85 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 52 86 } 53 87 54 function update( $new_instance, $old_instance ) { 88 /** 89 * Sanitize the settings before they are saved. 90 * 91 * @param array $new_instance Submitted settings. 92 * @param array $old_instance Previously saved settings. 93 * @return array 94 */ 95 public function update( $new_instance, $old_instance ) { 55 96 $instance = $old_instance; 56 $instance['title'] = strip_tags( $new_instance['title'] ); 57 $instance['id'] = (int) $new_instance['id']; 97 $instance['title'] = ''; 98 $instance['id'] = 0; 99 100 if ( isset( $new_instance['title'] ) ) { 101 $instance['title'] = sanitize_text_field( $new_instance['title'] ); 102 } 103 if ( isset( $new_instance['id'] ) ) { 104 $instance['id'] = (int) $new_instance['id']; 105 } 58 106 59 107 return $instance; 60 108 } 61 109 62 function form( $instance ) { 63 $title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : ''; 64 $id = isset( $instance['id'] ) ? (int) ( $instance['id'] ) : 0; 110 /** 111 * Settings form. 112 * 113 * @param array $instance Saved widget settings. 114 */ 115 public function form( $instance ) { 116 $title = ''; 117 $id = 0; 118 119 if ( isset( $instance['title'] ) ) { 120 $title = $instance['title']; 121 } 122 if ( isset( $instance['id'] ) ) { 123 $id = (int) $instance['id']; 124 } 65 125 66 126 $lists = get_posts( … … 69 129 'post_type' => W4PL_Config::LIST_POST_TYPE, 70 130 'posts_per_page' => -1, 131 'orderby' => 'title', 132 'order' => 'ASC', 71 133 ) 72 134 ); … … 74 136 ?> 75 137 <p> 76 <strong> 77 <?php _e( 'Title', 'w4-post-list' ); ?>: 78 </strong> 79 <br /><input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" 80 name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo $title; ?>" /> 138 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"> 139 <?php esc_html_e( 'Title:', 'w4-post-list' ); ?> 140 </label> 141 <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" 142 name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" 143 value="<?php echo esc_attr( $title ); ?>" /> 81 144 </p> 82 145 <p> 83 < strong>84 <?php _e( 'Select a list', 'w4-post-list' ); ?>:85 </ strong>86 < br />87 <select id="<?php echo $this->get_field_id( 'id' ); ?>" name="<?php echo $this->get_field_name( 'id'); ?>">88 < ?php89 90 $id = (int) $id;91 92 foreach ( $lists as $list ) {93 printf(94 '<option value="%d"%s>%s</option>',95 $list->ID,96 $id === $list->ID ? ' selected="selected"' : '',97 e mpty( $list->post_title ) ? 'List#' . $list->ID : $list->post_title98 );99 }100 ?>146 <label for="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>"> 147 <?php esc_html_e( 'List:', 'w4-post-list' ); ?> 148 </label> 149 <select class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>" 150 name="<?php echo esc_attr( $this->get_field_name( 'id' ) ); ?>"> 151 <option value="0"<?php selected( $id, 0 ); ?>><?php esc_html_e( '— Select a list —', 'w4-post-list' ); ?></option> 152 <?php foreach ( $lists as $list ) : ?> 153 <option value="<?php echo esc_attr( $list->ID ); ?>"<?php selected( $id, $list->ID ); ?>> 154 <?php 155 $label = $list->post_title; 156 if ( '' === $label ) { 157 /* translators: %d: list ID */ 158 $label = sprintf( __( 'List #%d', 'w4-post-list' ), $list->ID ); 159 } 160 echo esc_html( $label ); 161 ?> 162 </option> 163 <?php endforeach; ?> 101 164 </select> 102 <br /> 103 <?php _e( 'OR', 'w4-post-list' ); ?> 104 <br /> 105 <a class="button" 106 href="<?php echo esc_url( admin_url( 'post-new.php?post_type=' . W4PL_Config::LIST_POST_TYPE ) ); ?>"> 107 <?php _e( 'Create a new one', 'w4-post-list' ); ?> 165 </p> 166 <p> 167 <a class="button" href="<?php echo esc_url( admin_url( 'post-new.php?post_type=' . W4PL_Config::LIST_POST_TYPE ) ); ?>"> 168 <?php esc_html_e( 'Create a new list', 'w4-post-list' ); ?> 108 169 </a> 109 170 </p> -
w4-post-list/trunk/includes/functions.php
r3724093 r3788580 118 118 119 119 /** 120 * The style and script handle a list's own CSS and JavaScript print under. 121 * 122 * @since 3.1.0 123 * 124 * @param int $list_id List ID. 125 * @return string 126 */ 127 function w4pl_list_asset_handle( $list_id ) { 128 return 'w4pl-list-' . (int) $list_id; 129 } 130 131 /** 132 * The list's CSS as a style tag, through the WordPress style API. 133 * 134 * The CSS is attached to a src-less per-list handle and printed in place, 135 * where the raw tag used to be. Every render prints its own tag, as every 136 * render did through 3.0.9: a render whose output is thrown away (an excerpt 137 * built from `the_content`, an Open Graph scanner) must not use up the tag 138 * the visible render needs, so the handle is taken off the printed list 139 * first. The data stays readable through `wp_styles()->get_data()`. 140 * 141 * @since 3.1.0 142 * 143 * @param int $list_id List ID. 144 * @param string $css The list's CSS, `[listid]` already replaced. 145 * @return string Style tag. 146 */ 147 function w4pl_get_list_inline_style( $list_id, $css ) { 148 $handle = w4pl_list_asset_handle( $list_id ); 149 $styles = wp_styles(); 150 151 if ( ! wp_style_is( $handle, 'registered' ) ) { 152 wp_register_style( $handle, false, array(), W4PL_VERSION ); 153 wp_add_inline_style( $handle, $css ); 154 } 155 156 $styles->done = array_diff( $styles->done, array( $handle ) ); 157 158 // Not wp_print_styles(): that would also run the once-per-page 159 // `wp_print_styles` action from inside the content. 160 ob_start(); 161 $styles->do_items( array( $handle ) ); 162 163 return (string) ob_get_clean(); 164 } 165 166 /** 167 * The list's JavaScript as a script tag, through the WordPress script API. 168 * 169 * Same contract as w4pl_get_list_inline_style(): printed in place, once per 170 * render. On WordPress 6.3+ the tag carries whatever the 171 * `wp_inline_script_attributes` filter adds, so a CSP plugin's nonce covers it. 172 * 173 * @since 3.1.0 174 * 175 * @param int $list_id List ID. 176 * @param string $js The list's JavaScript, `[listid]` already replaced. 177 * @return string Script tag. 178 */ 179 function w4pl_get_list_inline_script( $list_id, $js ) { 180 $handle = w4pl_list_asset_handle( $list_id ); 181 $scripts = wp_scripts(); 182 183 if ( ! wp_script_is( $handle, 'registered' ) ) { 184 wp_register_script( $handle, false, array(), W4PL_VERSION, false ); 185 wp_add_inline_script( $handle, $js ); 186 } 187 188 $scripts->done = array_diff( $scripts->done, array( $handle ) ); 189 190 // Not wp_print_scripts(): that fires the once-per-page `wp_print_scripts` 191 // action every time it is called. 192 ob_start(); 193 $scripts->do_items( array( $handle ) ); 194 195 return (string) ob_get_clean(); 196 } 197 198 /** 120 199 * The page of a list the request asks for, from page{list id}. 121 200 * -
w4-post-list/trunk/includes/helpers/class-helper-style.php
r3625190 r3788580 12 12 13 13 /** 14 * Meta query implementor class14 * Per-list CSS / JavaScript: editor fields, defaults and output. 15 15 * 16 16 * @class W4PL_Helper_Style … … 31 31 * Style control field on list editor 32 32 * 33 * @param array $fields List editor fields.34 * @param array $ options List options.35 * @return array List editor fields.33 * @param array $fields List editor fields. 34 * @param array $post_data List post data. 35 * @return array List editor fields. 36 36 */ 37 37 public function list_edit_form_fields( $fields, $post_data ) { … … 52 52 'input_class' => 'widefat', 53 53 'desc2' => sprintf( 54 /* translators: %s: list ID */ 54 55 __( 55 ' this css rules is placed inline just before the list is place at front-end(not in the HEAD tag).56 <br /> to apply css just for current list, use <code>#w4pl-list-%s</code> asparent selector.57 <br />Alternatively, you can use <code>#w4pl-list-[listid]</code> to dynamically this selector.',56 'Printed right before the list (not in the HEAD tag). 57 <br />To style just this list, use <code>#w4pl-list-%s</code> as the parent selector. 58 <br />Alternatively, use <code>#w4pl-list-[listid]</code> and the ID is filled in for you.', 58 59 'w4-post-list' 59 60 ), … … 69 70 'type' => 'textarea', 70 71 'input_class' => 'widefat', 71 'desc2' => __( ' javascript loads right after template ends. don\'t use <code><script></code> tag', 'w4-post-list' ),72 'desc2' => __( 'Runs right after the list. Don\'t use a <code><script></code> tag.', 'w4-post-list' ), 72 73 'after' => '</div><!--.w4pl_group_fields--></div><!--#w4pl_field_group_style-->', 73 74 ); … … 95 96 */ 96 97 public function pre_save_options( $options ) { 97 foreach ( array( 'class' => '', 'js' => '', 'css' => '', ) as $k => $v) {98 foreach ( array( 'class', 'js', 'css' ) as $k ) { 98 99 if ( array_key_exists( $k, $options ) && empty( $options[ $k ] ) ) { 99 100 unset( $options[ $k ] ); … … 129 130 * Parse list render html to include css/js. 130 131 * 131 * @param object $obj Instance of W4PL_List 132 * The list's CSS and JavaScript go through the WordPress style and script 133 * API under a per-list handle (`w4pl-list-{id}`) and are printed in place, 134 * where the raw `<style>` / `<script>` tags used to be: the CSS right 135 * before the list, the JavaScript right after it, on every render, as 136 * before. Going through the API means the inline script tag carries 137 * whatever `wp_inline_script_attributes` adds (CSP nonces, on WordPress 138 * 6.3+), and site owners can read the data through `wp_styles()` / 139 * `wp_scripts()`. 140 * 141 * Printing in place rather than from the footer keeps every consumer of 142 * the returned HTML working unchanged: the admin live preview and the 143 * block editor's server-side render have no `wp_footer`, and a list 144 * rendered after `wp_print_footer_scripts` would otherwise lose its CSS. 145 * 146 * @param object $obj Instance of W4PL_List. 132 147 */ 133 148 public function parse_html( $obj ) { 134 // unique list class149 // Unique list class. 135 150 $class = trim( 'w4pl ' . $obj->options['class'] ); 136 151 $obj->html = str_replace( 'id="w4pl-list-' . $obj->id . '"', 'id="w4pl-list-' . $obj->id . '" class="' . $class . '"', $obj->html ); … … 146 161 // Css push. 147 162 if ( ! empty( $obj->css ) ) { 148 $obj->html = '<style id="w4pl-css-' . $obj->id . '" type="text/css">' . $obj->css . '</style>' . "\n". $obj->html;163 $obj->html = w4pl_get_list_inline_style( $obj->id, $obj->css ) . $obj->html; 149 164 } 150 165 151 166 // Js push. 152 167 if ( ! empty( $obj->js ) ) { 153 $obj->html .= "\n" . '<script id="w4pl-js-' . $obj->id . '" type="text/javascript">' . $obj->js . '</script>' . "\n";168 $obj->html .= "\n" . w4pl_get_list_inline_script( $obj->id, $obj->js ); 154 169 } 155 170 } -
w4-post-list/trunk/languages/w4-post-list.pot
r3724093 r3788580 4 4 "Project-Id-Version: W4 Post List\n" 5 5 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/w4-post-list/\n" 6 "POT-Creation-Date: 2026-1 0-02 02:48:42+00:00\n"6 "POT-Creation-Date: 2026-11-06 19:05:29+00:00\n" 7 7 "MIME-Version: 1.0\n" 8 8 "Content-Type: text/plain; charset=utf-8\n" … … 685 685 msgstr "" 686 686 687 #: includes/class-config.php:29 includes/class-widget-postlist.php:77687 #: includes/class-config.php:29 688 688 msgid "Title" 689 689 msgstr "" … … 854 854 msgstr "" 855 855 856 #: includes/class-widget-postlist.php:25 857 msgid "Display lists created with W4 Post List" 858 msgstr "" 859 860 #: includes/class-widget-postlist.php:84 861 msgid "Select a list" 862 msgstr "" 863 864 #: includes/class-widget-postlist.php:103 865 #: includes/helpers/class-helper-posts-date_query.php:89 866 #: includes/helpers/class-helper-posts-meta_query.php:164 867 msgid "OR" 868 msgstr "" 869 870 #: includes/class-widget-postlist.php:107 871 msgid "Create a new one" 856 #: includes/class-widget-postlist.php:31 857 msgid "" 858 "Show a list made with W4 Post List. In the block editor, use the W4 Post " 859 "List block instead." 860 msgstr "" 861 862 #: includes/class-widget-postlist.php:139 863 msgid "Title:" 864 msgstr "" 865 866 #: includes/class-widget-postlist.php:147 867 msgid "List:" 868 msgstr "" 869 870 #: includes/class-widget-postlist.php:151 871 msgid "— Select a list —" 872 msgstr "" 873 874 #: includes/class-widget-postlist.php:158 875 #. translators: %d: list ID 876 msgid "List #%d" 877 msgstr "" 878 879 #: includes/class-widget-postlist.php:168 880 msgid "Create a new list" 872 881 msgstr "" 873 882 … … 1051 1060 #: includes/helpers/class-helper-posts-tax_query.php:216 1052 1061 msgid "Relation" 1062 msgstr "" 1063 1064 #: includes/helpers/class-helper-posts-date_query.php:89 1065 #: includes/helpers/class-helper-posts-meta_query.php:164 1066 msgid "OR" 1053 1067 msgstr "" 1054 1068 … … 1366 1380 msgstr "" 1367 1381 1368 #: includes/helpers/class-helper-style.php:5 41369 msgid "" 1370 "this css rules is placed inline just before the list is place at front-end"1371 " (not in the HEAD tag).\n"1372 "\t\t\t\t\t\t\t\t<br /> to apply css just for currentlist, use "1373 "<code>#w4pl-list-%s</code> as parent selector.\n"1374 "\t\t\t\t\t\t\t\t<br />Alternatively, you can use"1375 " <code>#w4pl-list-[listid]</code> to dynamically this selector."1376 msgstr "" 1377 1378 #: includes/helpers/class-helper-style.php:6 81382 #: includes/helpers/class-helper-style.php:55 1383 #. translators: %s: list ID 1384 msgid "" 1385 "Printed right before the list (not in the HEAD tag).\n" 1386 "\t\t\t\t\t\t\t\t<br />To style just this list, use " 1387 "<code>#w4pl-list-%s</code> as the parent selector.\n" 1388 "\t\t\t\t\t\t\t\t<br />Alternatively, use <code>#w4pl-list-[listid]</code> " 1389 "and the ID is filled in for you." 1390 msgstr "" 1391 1392 #: includes/helpers/class-helper-style.php:69 1379 1393 msgid "JavaScript" 1380 1394 msgstr "" 1381 1395 1382 #: includes/helpers/class-helper-style.php:71 1383 msgid "" 1384 "javascript loads right after template ends. don't use " 1385 "<code><script></code> tag" 1386 msgstr "" 1387 1388 #: includes/helpers/class-helper-style.php:78 1396 #: includes/helpers/class-helper-style.php:72 1397 msgid "Runs right after the list. Don't use a <code><script></code> tag." 1398 msgstr "" 1399 1400 #: includes/helpers/class-helper-style.php:79 1389 1401 msgid "HTML class name" 1390 1402 msgstr "" 1391 1403 1392 #: includes/helpers/class-helper-style.php:8 01404 #: includes/helpers/class-helper-style.php:81 1393 1405 msgid "applied on the wrapper html DIV tag" 1394 1406 msgstr "" -
w4-post-list/trunk/readme.txt
r3724093 r3788580 3 3 Tags: post list, user list, post grid, category list, shortcode 4 4 Requires at least: 5.8 5 Tested up to: 7.1. 25 Tested up to: 7.1.4 6 6 Requires PHP: 7.4 7 Stable tag: 3. 0.97 Stable tag: 3.1.0 8 8 License: GPLv3 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 135 135 136 136 == Changelog == 137 = 3.1.0 = 138 * Improved: A list's CSS and JavaScript print in the same place as before but through WordPress's own style and script API, so on WordPress 6.3+ a CSP plugin's nonce covers the list's script and developers can read a list's CSS and JavaScript from `wp_styles()` / `wp_scripts()` under the handle `w4pl-list-{id}`. 139 * Improved: The classic widget has a "— Select a list —" placeholder, lists sorted by title, escaped output and a description that points block editors to the W4 Post List block. 140 * Tested up to WordPress 7.1.4. 137 141 = 3.0.9 = 138 142 * Fix: AJAX pagination keeps the list's page when visitors go Back, Forward or reload. Each page is recorded in the address bar, so a visitor who opens a post and comes back lands on the page they were reading. -
w4-post-list/trunk/w4-post-list.php
r3724093 r3788580 4 4 * Plugin URI: https://w4dev.com/plugins/w4-post-list 5 5 * Description: Create lists of posts, terms and users — grouped archives, taxonomy indexes and user directories — placed anywhere with the block, [postlist] shortcode or widget. 6 * Version: 3. 0.96 * Version: 3.1.0 7 7 * Requires at least: 5.8 8 8 * Requires PHP: 7.4
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)