Column slug => width in pixels. */ private function column_widths(): array { /** * Filter the per-column widths. * * @since 1.0.0 * * @param array $widths Column slug => width in pixels. */ return (array) apply_filters( 'acato_readable_list_tables_column_widths', array( 'title' => 260, 'author' => 115, 'categories' => 120, 'tags' => 95, 'date' => 130, // Post Expirator. 'expirationdate' => 130, // Duplicate Post. 'duplicate_post_original_item' => 130, // Yoast SEO. 'wpseo-title' => 170, 'wpseo-metadesc' => 190, 'wpseo-focuskw' => 130, ) ); } /** * Width for columns that have no explicit width of their own. * * `min-width` cannot do this job: `table-layout: fixed` ignores it on cells, * so an unsized column still collapses to ~20px and drags its header into a * letter-per-line stack. * * @return int Width in pixels. */ private function default_width(): int { /** * Filter the fallback width for unrecognised columns. * * @since 1.0.0 * * @param int $width Width in pixels. */ return (int) apply_filters( 'acato_readable_list_tables_default_width', 130 ); } /** * Column classes that must keep the width their own stylesheet gives them. * * These are the deliberately narrow ones: the checkbox, the comment bubble * and the Yoast score icons. Widening them to the default would waste a lot * of horizontal space. * * @return string[] CSS class names, without the leading dot. */ private function narrow_columns(): array { /** * Filter the columns that keep their own width. * * @since 1.0.0 * * @param string[] $classes CSS class names, without the leading dot. */ return (array) apply_filters( 'acato_readable_list_tables_narrow_columns', array( 'check-column', 'column-comments', 'column-wpseo-score', 'column-wpseo-score-readability', 'column-wpseo-links', 'column-wpseo-linked', 'column-wpseo-cornerstone', 'column-wpseo-inclusive-language', ) ); } /** * Whether to pin the checkbox and title columns while scrolling sideways. * * @return bool True to pin them. */ private function sticky_enabled(): bool { /** * Filter whether the identity columns are pinned. * * @since 1.0.0 * * @param bool $sticky Whether to pin the checkbox and title columns. */ return (bool) apply_filters( 'acato_readable_list_tables_sticky_columns', true ); } /** * Register and enqueue the stylesheet and script. * * Every column that would otherwise be auto-width gets a pixel width. A * fixed table is as wide as its columns demand, so the table grows past its * container rather than squeezing the title column down to nothing; the * scroll container takes care of the overflow. Columns an editor hides are * `display: none` and drop out of that sum, so switching a few off through * Screen Options is enough to make it fit without scrolling. Any leftover * space on wider screens is divided over the columns by the browser. * * Left untyped on purpose: this is an action callback in a file under * strict_types, so a loosely typed value from a third party would otherwise * be fatal. * * @param mixed $hook_suffix The current admin page. * * @return void */ public function enqueue_assets( $hook_suffix ): void { if ( 'edit.php' !== $hook_suffix || ! $this->is_enabled() ) { return; } wp_enqueue_style( self::HANDLE, plugins_url( 'assets/css/list-tables.css', ACATO_READABLE_LIST_TABLES_PLUGIN_FILE ), array(), ACATO_READABLE_LIST_TABLES_VERSION ); wp_add_inline_style( self::HANDLE, $this->column_css() ); wp_enqueue_script( self::HANDLE, plugins_url( 'assets/js/list-tables.js', ACATO_READABLE_LIST_TABLES_PLUGIN_FILE ), array(), ACATO_READABLE_LIST_TABLES_VERSION, true ); wp_add_inline_script( self::HANDLE, 'window.acatoReadableListTables = ' . wp_json_encode( array( 'label' => __( 'Post list, scrolls horizontally', 'acato-readable-list-tables' ), 'sticky' => $this->sticky_enabled(), ) ) . ';', 'before' ); } /** * Build the filterable part of the stylesheet. * * @return string CSS. */ private function column_css(): string { $narrow = array_filter( array_map( 'sanitize_html_class', $this->narrow_columns() ) ); $css = ''; if ( $narrow ) { /* * Everything except the deliberately narrow columns. * * box-sizing, because wp-admin cells are content-box and the 10px * cell padding would otherwise be added on top of every width. * * width, as a floor for any column not sized explicitly, including * columns from plugins this one does not know about. The specific * widths after it have the same specificity and come later, so they * win. `:where()` keeps the exclusion list at zero specificity. */ $css .= sprintf( ".fixed .manage-column:not(:where(.%s)){box-sizing:border-box;width:%dpx}\n", implode( ', .', $narrow ), absint( $this->default_width() ) ); } foreach ( $this->column_widths() as $column => $width ) { $column = sanitize_html_class( (string) $column ); if ( '' === $column || ! $width ) { continue; } $css .= sprintf( ".fixed .column-%s{width:%dpx}\n", $column, absint( $width ) ); } return $css; } }