Last active
March 15, 2026 06:02
-
-
Save arenagroove/2deceba3f09fde5ec732a5e6e5f9cefe to your computer and use it in GitHub Desktop.
WordPress MU plugin — Admin Columns — Featured Image, URL Path, Modified Date, Post ID. Per-column enable/disable, role visibility, and URL path truncation — all configurable via Settings → LR Admin Columns.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Plugin Name: LR Admin Columns | |
| * Description: Unified admin list columns — Featured Image, URL Path, Modified Date, Post ID. Per-column enable/disable, role visibility, and URL path truncation — all configurable via Settings → LR Admin Columns. | |
| * Version: 1.1.2 | |
| * Author: Luis Martinez | |
| * Author URI: https://www.lessrain.com | |
| * Requires at least: 5.6 | |
| * Tested up to: 6.5 | |
| * Requires PHP: 7.4 | |
| * | |
| * Changelog: | |
| * 1.1.2 — 2026-03-11 | |
| * - Fixed fallback_image not persisting after save — array_replace_recursive | |
| * was clobbering top-level string values; replaced with explicit merge | |
| * - Fixed media uploader — moved JS to admin_footer hook, most reliable | |
| * way to ensure wp.media is available before binding | |
| * - Fallback image now correctly used in column output | |
| * 1.1.1 — 2026-03-11 | |
| * - URL path word-break fix, media uploader via wp_add_inline_script | |
| * 1.1.0 — 2026-03-11 | |
| * - Settings page with column toggles, role restrictions, truncation | |
| * 1.0.0 — 2026-03-11 | |
| * - Initial unified release | |
| */ | |
| defined( 'ABSPATH' ) || exit; | |
| if ( ! is_admin() ) { | |
| return; | |
| } | |
| // ============================================================================= | |
| // DEFAULTS & SETTINGS | |
| // ============================================================================= | |
| function lr_col_defaults(): array { | |
| return [ | |
| 'fallback_image' => defined( 'LR_TEMPLATE_DIR_URI' ) | |
| ? trailingslashit( LR_TEMPLATE_DIR_URI ) . 'assets/images/brand-logo.svg' | |
| : '', | |
| 'columns' => [ | |
| 'lr_featured_image' => [ | |
| 'enabled' => true, | |
| 'roles' => [], | |
| ], | |
| 'lr_slug' => [ | |
| 'enabled' => true, | |
| 'roles' => [], | |
| 'truncate' => false, | |
| 'truncate_length' => 40, | |
| ], | |
| 'lr_modified' => [ | |
| 'enabled' => true, | |
| 'roles' => [], | |
| ], | |
| 'lr_post_id' => [ | |
| 'enabled' => true, | |
| 'roles' => [], | |
| ], | |
| ], | |
| ]; | |
| } | |
| /** | |
| * Returns merged settings — saved values win over defaults. | |
| * Does NOT use array_replace_recursive to avoid string key collisions. | |
| */ | |
| function lr_col_settings(): array { | |
| $saved = get_option( 'lr_admin_columns', [] ); | |
| $defaults = lr_col_defaults(); | |
| // Top-level scalar: fallback_image | |
| $out = $defaults; | |
| if ( ! empty( $saved['fallback_image'] ) ) { | |
| $out['fallback_image'] = $saved['fallback_image']; | |
| } | |
| // Per-column settings | |
| foreach ( array_keys( $defaults['columns'] ) as $key ) { | |
| $saved_col = $saved['columns'][ $key ] ?? []; | |
| $def_col = $defaults['columns'][ $key ]; | |
| $out['columns'][ $key ]['enabled'] = isset( $saved_col['enabled'] ) | |
| ? (bool) $saved_col['enabled'] | |
| : $def_col['enabled']; | |
| $out['columns'][ $key ]['roles'] = isset( $saved_col['roles'] ) && is_array( $saved_col['roles'] ) | |
| ? $saved_col['roles'] | |
| : $def_col['roles']; | |
| if ( $key === 'lr_slug' ) { | |
| $out['columns'][ $key ]['truncate'] = isset( $saved_col['truncate'] ) | |
| ? (bool) $saved_col['truncate'] | |
| : $def_col['truncate']; | |
| $out['columns'][ $key ]['truncate_length'] = isset( $saved_col['truncate_length'] ) | |
| ? max( 10, (int) $saved_col['truncate_length'] ) | |
| : $def_col['truncate_length']; | |
| } | |
| } | |
| return $out; | |
| } | |
| function lr_col_user_can_see( array $col ): bool { | |
| $roles = $col['roles'] ?? []; | |
| if ( empty( $roles ) ) { | |
| return true; | |
| } | |
| $user = wp_get_current_user(); | |
| foreach ( $roles as $role ) { | |
| if ( in_array( $role, (array) $user->roles, true ) ) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // ============================================================================= | |
| // HELPERS | |
| // ============================================================================= | |
| function lr_columns_register( string $post_type, callable $register_cb, callable $output_cb ): void { | |
| if ( 'post' === $post_type ) { | |
| add_filter( 'manage_posts_columns', $register_cb ); | |
| add_action( 'manage_posts_custom_column', $output_cb, 10, 2 ); | |
| } elseif ( 'page' === $post_type ) { | |
| add_filter( 'manage_pages_columns', $register_cb ); | |
| add_action( 'manage_pages_custom_column', $output_cb, 10, 2 ); | |
| } else { | |
| add_filter( "manage_{$post_type}_posts_columns", $register_cb ); | |
| add_action( "manage_{$post_type}_posts_custom_column", $output_cb, 10, 2 ); | |
| } | |
| } | |
| // ============================================================================= | |
| // 1. FEATURED IMAGE | |
| // ============================================================================= | |
| function lr_col_image_register( array $columns ): array { | |
| $s = lr_col_settings(); | |
| if ( ! $s['columns']['lr_featured_image']['enabled'] || ! lr_col_user_can_see( $s['columns']['lr_featured_image'] ) ) { | |
| return $columns; | |
| } | |
| $new = []; | |
| foreach ( $columns as $key => $title ) { | |
| if ( 'title' === $key ) { | |
| $new['lr_featured_image'] = 'Image'; | |
| } | |
| $new[ $key ] = $title; | |
| } | |
| return $new; | |
| } | |
| function lr_col_image_output( string $column, int $post_id ): void { | |
| if ( 'lr_featured_image' !== $column ) { | |
| return; | |
| } | |
| $s = lr_col_settings(); | |
| $image_src = $s['fallback_image']; | |
| if ( function_exists( 'lr_get_enhanced_featured_img' ) ) { | |
| $enhanced = lr_get_enhanced_featured_img( $post_id ); | |
| if ( $enhanced ) { | |
| $image_src = isset( $enhanced['img'] ) | |
| ? $enhanced['img']['sizes']['thumbnail'] | |
| : $enhanced['sizes']['thumbnail']; | |
| } | |
| } else { | |
| $thumb_id = get_post_thumbnail_id( $post_id ); | |
| if ( $thumb_id ) { | |
| $src = wp_get_attachment_image_src( $thumb_id, 'thumbnail' ); | |
| if ( $src ) { | |
| $image_src = $src[0]; | |
| } | |
| } | |
| } | |
| if ( ! $image_src ) { | |
| return; | |
| } | |
| printf( | |
| '<img src="%s" alt="%s" decoding="async" width="40" height="40">', | |
| esc_url( $image_src ), | |
| esc_attr( get_the_title( $post_id ) ) | |
| ); | |
| } | |
| // ============================================================================= | |
| // 2. URL PATH | |
| // ============================================================================= | |
| function lr_col_slug_register( array $columns ): array { | |
| $s = lr_col_settings(); | |
| if ( ! $s['columns']['lr_slug']['enabled'] || ! lr_col_user_can_see( $s['columns']['lr_slug'] ) ) { | |
| return $columns; | |
| } | |
| $screen = get_current_screen(); | |
| if ( ! $screen || ! is_post_type_viewable( $screen->post_type ) ) { | |
| return $columns; | |
| } | |
| $columns['lr_slug'] = 'URL Path'; | |
| return $columns; | |
| } | |
| function lr_col_slug_output( string $column, int $post_id ): void { | |
| if ( 'lr_slug' !== $column ) { | |
| return; | |
| } | |
| static $home = null; | |
| if ( null === $home ) { | |
| $home = get_home_url(); | |
| } | |
| $post = get_post( $post_id ); | |
| if ( ! $post ) { | |
| return; | |
| } | |
| $col_s = lr_col_settings()['columns']['lr_slug']; | |
| $truncate = (bool) $col_s['truncate']; | |
| $limit = max( 10, (int) $col_s['truncate_length'] ); | |
| $maybe_truncate = static function( string $path ) use ( $truncate, $limit ): string { | |
| if ( $truncate && mb_strlen( $path ) > $limit ) { | |
| return mb_substr( $path, 0, $limit ) . '…'; | |
| } | |
| return $path; | |
| }; | |
| if ( in_array( $post->post_status, [ 'draft', 'pending', 'future' ], true ) ) { | |
| $sample = get_sample_permalink( $post_id ); | |
| if ( ! empty( $sample[0] ) ) { | |
| $path = str_replace( [ $home, '%pagename%', '%postname%' ], [ '', $sample[1], $sample[1] ], $sample[0] ); | |
| printf( | |
| '<span style="color:#999;" title="%1$s"><code>%2$s</code></span>', | |
| esc_attr( $path ), | |
| esc_html( $maybe_truncate( $path ) ) | |
| ); | |
| } | |
| } else { | |
| $full_url = get_permalink( $post_id ); | |
| $path = urldecode( str_replace( $home, '', $full_url ) ); | |
| printf( | |
| '<a href="%1$s" target="_blank" title="%2$s"><code>%3$s</code></a>', | |
| esc_url( $full_url ), | |
| esc_attr( $path ), | |
| esc_html( $maybe_truncate( $path ) ) | |
| ); | |
| } | |
| } | |
| // ============================================================================= | |
| // 3. MODIFIED DATE | |
| // ============================================================================= | |
| function lr_col_modified_register( array $columns ): array { | |
| $s = lr_col_settings(); | |
| if ( ! $s['columns']['lr_modified']['enabled'] || ! lr_col_user_can_see( $s['columns']['lr_modified'] ) ) { | |
| return $columns; | |
| } | |
| $new = []; | |
| foreach ( $columns as $key => $label ) { | |
| $new[ $key ] = $label; | |
| if ( 'date' === $key ) { | |
| $new['lr_modified'] = 'Modified'; | |
| } | |
| } | |
| if ( ! isset( $new['lr_modified'] ) ) { | |
| $new['lr_modified'] = 'Modified'; | |
| } | |
| return $new; | |
| } | |
| function lr_col_modified_output( string $column, int $post_id ): void { | |
| if ( 'lr_modified' !== $column ) { | |
| return; | |
| } | |
| printf( | |
| '<div class="lr-mod-date"><em>%s %s</em><br><small>by <strong>%s</strong></small></div>', | |
| esc_html( get_post_modified_time( 'Y/m/d', false, $post_id ) ), | |
| esc_html( get_post_modified_time( 'g:i a', false, $post_id ) ), | |
| esc_html( lr_col_modified_get_author( $post_id ) ) | |
| ); | |
| } | |
| function lr_col_modified_get_author( int $post_id ): string { | |
| static $cache = []; | |
| $resolve = static function( int $uid ) use ( &$cache ): ?string { | |
| if ( ! $uid ) return null; | |
| if ( ! isset( $cache[ $uid ] ) ) { | |
| $u = get_userdata( $uid ); | |
| $cache[$uid] = $u ? $u->display_name : null; | |
| } | |
| return $cache[ $uid ]; | |
| }; | |
| $name = $resolve( (int) get_post_meta( $post_id, '_edit_last', true ) ); | |
| if ( $name ) return $name; | |
| foreach ( wp_get_post_revisions( $post_id, [ 'posts_per_page' => 5, 'order' => 'DESC', 'orderby' => 'date' ] ) as $rev ) { | |
| if ( str_contains( $rev->post_name, 'autosave' ) ) continue; | |
| $name = $resolve( (int) $rev->post_author ); | |
| if ( $name ) return $name; | |
| } | |
| $post = get_post( $post_id ); | |
| if ( $post ) { | |
| $name = $resolve( (int) $post->post_author ); | |
| if ( $name ) return $name; | |
| } | |
| return 'Unknown'; | |
| } | |
| // Sortable | |
| foreach ( [ 'post', 'page' ] as $_pt ) { | |
| add_filter( "manage_edit-{$_pt}_sortable_columns", fn( $c ) => array_merge( $c, [ 'lr_modified' => 'modified' ] ) ); | |
| } | |
| add_action( 'registered_post_type', function( string $pt ): void { | |
| if ( ! in_array( $pt, [ 'post', 'page', 'attachment' ], true ) ) { | |
| add_filter( "manage_edit-{$pt}_sortable_columns", fn( $c ) => array_merge( $c, [ 'lr_modified' => 'modified' ] ) ); | |
| } | |
| } ); | |
| add_action( 'pre_get_posts', function( WP_Query $q ): void { | |
| if ( ! is_admin() || wp_doing_ajax() || ! $q->is_main_query() ) return; | |
| $screen = get_current_screen(); | |
| if ( ! $screen || ! in_array( $screen->base, [ 'edit', 'upload' ], true ) ) return; | |
| if ( in_array( $q->get( 'orderby' ), [ 'modified', 'lr_modified' ], true ) ) { | |
| $q->set( 'orderby', 'modified' ); | |
| $order = strtoupper( $q->get( 'order' ) ); | |
| $q->set( 'order', in_array( $order, [ 'ASC', 'DESC' ], true ) ? $order : 'DESC' ); | |
| } | |
| } ); | |
| // ============================================================================= | |
| // 4. POST ID | |
| // ============================================================================= | |
| function lr_col_id_register( array $columns ): array { | |
| $s = lr_col_settings(); | |
| if ( ! $s['columns']['lr_post_id']['enabled'] || ! lr_col_user_can_see( $s['columns']['lr_post_id'] ) ) { | |
| return $columns; | |
| } | |
| $columns['lr_post_id'] = 'ID'; | |
| return $columns; | |
| } | |
| function lr_col_id_output( string $column, int $post_id ): void { | |
| if ( 'lr_post_id' === $column ) { | |
| echo absint( $post_id ); | |
| } | |
| } | |
| // ============================================================================= | |
| // REGISTER via current_screen | |
| // ============================================================================= | |
| add_action( 'current_screen', function (): void { | |
| $screen = get_current_screen(); | |
| if ( ! $screen || 'edit' !== $screen->base ) return; | |
| $pt = $screen->post_type; | |
| lr_columns_register( $pt, 'lr_col_image_register', 'lr_col_image_output' ); | |
| lr_columns_register( $pt, 'lr_col_slug_register', 'lr_col_slug_output' ); | |
| lr_columns_register( $pt, 'lr_col_modified_register', 'lr_col_modified_output' ); | |
| lr_columns_register( $pt, 'lr_col_id_register', 'lr_col_id_output' ); | |
| } ); | |
| // ============================================================================= | |
| // CSS | |
| // ============================================================================= | |
| add_action( 'admin_head', function (): void { | |
| $screen = get_current_screen(); | |
| if ( ! $screen || 'edit' !== $screen->base ) return; | |
| echo '<style> | |
| .wp-list-table .column-title, | |
| .wp-list-table .column-post_title { min-width: 180px; } | |
| .column-lr_featured_image { width: 58px !important; min-width: 58px; } | |
| .column-lr_featured_image img { | |
| display: block; | |
| width: 40px !important; height: 40px !important; | |
| max-width: 40px !important; max-height: 40px !important; | |
| object-fit: cover; | |
| } | |
| .column-lr_featured_image img[src*=".png"], | |
| .column-lr_featured_image img[src*=".svg"] { | |
| background-image: | |
| linear-gradient(45deg,#c3c4c7 25%,transparent 25%,transparent 75%,#c3c4c7 75%,#c3c4c7), | |
| linear-gradient(45deg,#c3c4c7 25%,transparent 25%,transparent 75%,#c3c4c7 75%,#c3c4c7); | |
| background-position: 0 0, 5px 5px; | |
| background-size: 10px 10px; | |
| } | |
| .column-lr_featured_image::before { opacity: 0; } | |
| .column-lr_slug { width: 180px; min-width: 120px; max-width: 220px; } | |
| .column-lr_slug code { background: none; padding: 0; font-size: inherit; word-break: break-all; } | |
| .column-lr_modified { width: 150px; min-width: 130px; max-width: 170px; white-space: nowrap; } | |
| .lr-mod-date { line-height: 1.6; } | |
| .column-lr_post_id { width: 70px; min-width: 60px; max-width: 80px; white-space: nowrap; } | |
| @media screen and (max-width: 1280px) { .wp-list-table .column-lr_post_id { display: none; } } | |
| @media screen and (max-width: 1100px) { .wp-list-table .column-lr_modified, .wp-list-table .column-author { display: none; } } | |
| @media screen and (max-width: 960px) { .wp-list-table .column-lr_slug { display: none; } } | |
| @media screen and (max-width: 782px) { .wp-list-table .column-lr_featured_image { display: none; } } | |
| </style>'; | |
| } ); | |
| // ============================================================================= | |
| // SETTINGS | |
| // ============================================================================= | |
| add_action( 'admin_menu', function (): void { | |
| add_options_page( 'LR Admin Columns', 'LR Admin Columns', 'manage_options', 'lr-admin-columns', 'lr_admin_columns_settings_page' ); | |
| } ); | |
| add_action( 'admin_init', function (): void { | |
| register_setting( 'lr_admin_columns', 'lr_admin_columns', [ 'sanitize_callback' => 'lr_admin_columns_sanitize' ] ); | |
| } ); | |
| function lr_admin_columns_sanitize( $input ): array { | |
| $defaults = lr_col_defaults(); | |
| $out = $defaults; | |
| // Fallback image — save whatever came in (already a URL from the form) | |
| $out['fallback_image'] = isset( $input['fallback_image'] ) | |
| ? esc_url_raw( trim( $input['fallback_image'] ) ) | |
| : $defaults['fallback_image']; | |
| foreach ( array_keys( $defaults['columns'] ) as $key ) { | |
| $col = $input['columns'][ $key ] ?? []; | |
| $out['columns'][ $key ]['enabled'] = ! empty( $col['enabled'] ); | |
| $roles = $col['roles'] ?? []; | |
| $out['columns'][ $key ]['roles'] = is_array( $roles ) | |
| ? array_map( 'sanitize_key', array_values( $roles ) ) | |
| : []; | |
| if ( $key === 'lr_slug' ) { | |
| $out['columns'][ $key ]['truncate'] = ! empty( $col['truncate'] ); | |
| $out['columns'][ $key ]['truncate_length'] = max( 10, min( 200, (int) ( $col['truncate_length'] ?? 40 ) ) ); | |
| } | |
| } | |
| return $out; | |
| } | |
| add_action( 'admin_enqueue_scripts', function ( string $hook ): void { | |
| if ( 'settings_page_lr-admin-columns' === $hook ) { | |
| wp_enqueue_media(); | |
| } | |
| } ); | |
| // Media uploader JS — admin_footer guarantees wp.media is fully loaded | |
| add_action( 'admin_footer', function (): void { | |
| $screen = get_current_screen(); | |
| if ( ! $screen || 'settings_page_lr-admin-columns' !== $screen->id ) return; | |
| ?> | |
| <script> | |
| (function($) { | |
| $(function() { | |
| // Fallback image picker | |
| var mediaFrame; | |
| $('#lr_fallback_image_btn').on('click', function(e) { | |
| e.preventDefault(); | |
| if ( mediaFrame ) { | |
| mediaFrame.open(); | |
| return; | |
| } | |
| mediaFrame = wp.media({ | |
| title: 'Select Fallback Image', | |
| button: { text: 'Use this image' }, | |
| multiple: false, | |
| library: { type: 'image' } | |
| }); | |
| mediaFrame.on('select', function() { | |
| var att = mediaFrame.state().get('selection').first().toJSON(); | |
| $('#lr_fallback_image').val(att.url); | |
| $('#lr_fallback_preview').attr('src', att.url).show(); | |
| }); | |
| mediaFrame.open(); | |
| }); | |
| // Clear fallback image | |
| $('#lr_fallback_image_clear').on('click', function(e) { | |
| e.preventDefault(); | |
| $('#lr_fallback_image').val(''); | |
| $('#lr_fallback_preview').attr('src', '').hide(); | |
| }); | |
| // Truncation length toggle | |
| $('#lr_truncate_toggle').on('change', function() { | |
| var $row = $('#lr_truncate_length_row'); | |
| $row.css({ opacity: this.checked ? '1' : '.4', pointerEvents: this.checked ? 'auto' : 'none' }); | |
| }); | |
| }); | |
| }(jQuery)); | |
| </script> | |
| <?php | |
| } ); | |
| function lr_admin_columns_settings_page(): void { | |
| $s = lr_col_settings(); | |
| $all_roles = wp_roles()->get_names(); | |
| $col_meta = [ | |
| 'lr_featured_image' => [ 'icon' => '🖼️', 'label' => 'Featured Image' ], | |
| 'lr_slug' => [ 'icon' => '🔗', 'label' => 'URL Path' ], | |
| 'lr_modified' => [ 'icon' => '🕐', 'label' => 'Modified Date' ], | |
| 'lr_post_id' => [ 'icon' => '#', 'label' => 'Post ID' ], | |
| ]; | |
| ?> | |
| <div class="wrap"> | |
| <h1>LR Admin Columns</h1> | |
| <p style="color:#666;">Configure which columns appear on post type list screens, who can see them, and how they behave.</p> | |
| <form method="post" action="options.php"> | |
| <?php settings_fields( 'lr_admin_columns' ); ?> | |
| <table class="widefat" style="margin-top:20px;border-radius:4px;overflow:hidden;"> | |
| <thead> | |
| <tr style="background:#f0f0f1;"> | |
| <th style="padding:12px 16px;width:180px;">Column</th> | |
| <th style="padding:12px 16px;width:80px;">Show</th> | |
| <th style="padding:12px 16px;">Visible to roles <span style="font-weight:400;color:#888;">(empty = everyone)</span></th> | |
| <th style="padding:12px 16px;">Options</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <?php foreach ( $col_meta as $key => $meta ) : | |
| $col = $s['columns'][ $key ]; | |
| $checked_roles = $col['roles'] ?? []; | |
| ?> | |
| <tr style="border-top:1px solid #e0e0e0;"> | |
| <td style="padding:14px 16px;font-weight:600;"> | |
| <?php echo esc_html( $meta['icon'] . ' ' . $meta['label'] ); ?> | |
| </td> | |
| <td style="padding:14px 16px;"> | |
| <label class="lr-toggle"> | |
| <input type="checkbox" | |
| name="lr_admin_columns[columns][<?php echo esc_attr( $key ); ?>][enabled]" | |
| value="1" <?php checked( ! empty( $col['enabled'] ) ); ?>> | |
| <span class="lr-toggle-slider"></span> | |
| </label> | |
| </td> | |
| <td style="padding:14px 16px;"> | |
| <div style="display:flex;flex-wrap:wrap;gap:8px 16px;"> | |
| <?php foreach ( $all_roles as $role_key => $role_name ) : ?> | |
| <label style="display:flex;align-items:center;gap:4px;cursor:pointer;"> | |
| <input type="checkbox" | |
| name="lr_admin_columns[columns][<?php echo esc_attr( $key ); ?>][roles][]" | |
| value="<?php echo esc_attr( $role_key ); ?>" | |
| <?php checked( in_array( $role_key, $checked_roles, true ) ); ?>> | |
| <?php echo esc_html( translate_user_role( $role_name ) ); ?> | |
| </label> | |
| <?php endforeach; ?> | |
| </div> | |
| </td> | |
| <td style="padding:14px 16px;"> | |
| <?php if ( 'lr_slug' === $key ) : | |
| $truncate = ! empty( $col['truncate'] ); | |
| $limit = (int) ( $col['truncate_length'] ?? 40 ); | |
| ?> | |
| <label style="display:flex;align-items:center;gap:6px;margin-bottom:8px;"> | |
| <input type="checkbox" id="lr_truncate_toggle" | |
| name="lr_admin_columns[columns][lr_slug][truncate]" | |
| value="1" <?php checked( $truncate ); ?>> | |
| Truncate long paths | |
| </label> | |
| <label id="lr_truncate_length_row" | |
| style="display:flex;align-items:center;gap:6px;<?php echo $truncate ? '' : 'opacity:.4;pointer-events:none;'; ?>"> | |
| Max characters: | |
| <input type="number" min="10" max="200" style="width:70px;" | |
| name="lr_admin_columns[columns][lr_slug][truncate_length]" | |
| value="<?php echo esc_attr( $limit ); ?>"> | |
| </label> | |
| <?php else : ?> | |
| <span style="color:#aaa;">—</span> | |
| <?php endif; ?> | |
| </td> | |
| </tr> | |
| <?php endforeach; ?> | |
| </tbody> | |
| </table> | |
| <h2 style="margin-top:32px;">Fallback Image</h2> | |
| <p style="color:#666;">Shown in the Image column when a post has no featured image.</p> | |
| <div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;"> | |
| <input type="text" id="lr_fallback_image" | |
| name="lr_admin_columns[fallback_image]" | |
| value="<?php echo esc_attr( $s['fallback_image'] ); ?>" | |
| class="regular-text" placeholder="https://…"> | |
| <button type="button" class="button" id="lr_fallback_image_btn">Select Image</button> | |
| <button type="button" class="button" id="lr_fallback_image_clear">Clear</button> | |
| <img id="lr_fallback_preview" | |
| src="<?php echo esc_url( $s['fallback_image'] ); ?>" | |
| style="width:40px;height:40px;object-fit:cover;border:1px solid #ddd;border-radius:2px;<?php echo $s['fallback_image'] ? '' : 'display:none;'; ?>"> | |
| </div> | |
| <h2 style="margin-top:32px;">Responsive Behaviour</h2> | |
| <p style="color:#666;">Columns hide in priority order as the viewport narrows:</p> | |
| <table class="widefat" style="max-width:460px;border-radius:4px;overflow:hidden;"> | |
| <thead><tr style="background:#f0f0f1;"> | |
| <th style="padding:8px 14px;">Breakpoint</th> | |
| <th style="padding:8px 14px;">Hidden</th> | |
| </tr></thead> | |
| <tbody> | |
| <tr><td style="padding:8px 14px;">≤ 1280px</td><td style="padding:8px 14px;">Post ID</td></tr> | |
| <tr style="background:#f9f9f9;"><td style="padding:8px 14px;">≤ 1100px</td><td style="padding:8px 14px;">Modified + Author</td></tr> | |
| <tr><td style="padding:8px 14px;">≤ 960px</td><td style="padding:8px 14px;">URL Path</td></tr> | |
| <tr style="background:#f9f9f9;"><td style="padding:8px 14px;">≤ 782px</td><td style="padding:8px 14px;">Featured Image</td></tr> | |
| </tbody> | |
| </table> | |
| <p style="margin-top:24px;"><?php submit_button( 'Save Settings', 'primary', 'submit', false ); ?></p> | |
| </form> | |
| </div> | |
| <style> | |
| .lr-toggle { position:relative; display:inline-block; width:40px; height:22px; } | |
| .lr-toggle input { opacity:0; width:0; height:0; } | |
| .lr-toggle-slider { position:absolute; cursor:pointer; inset:0; background:#ccc; border-radius:22px; transition:.2s; } | |
| .lr-toggle-slider:before { content:''; position:absolute; width:16px; height:16px; left:3px; bottom:3px; background:#fff; border-radius:50%; transition:.2s; } | |
| .lr-toggle input:checked + .lr-toggle-slider { background:#2271b1; } | |
| .lr-toggle input:checked + .lr-toggle-slider:before { transform:translateX(18px); } | |
| </style> | |
| <?php | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment