FREE & OPEN SOURCE Million Dollar Script is a free WordPress plugin for creating pixel grid advertising sites. Download now and extend with free or premium extensions.
Public access

List Page Customization

Access granted Updated Dec 15, 2025

List Page Customization

The Million Dollar Script list view (the /milliondollarscript/list/ route and the [milliondollarscript type="list"] shortcode) exposes filters that make it easy to add custom columns, modify row data, and control the display layout.

Rendering Overview

The list markup is generated by the MDS Ajax handler. Any filter you attach is applied everywhere the list appears—whether accessed via route, shortcode, or block.

Entry Points

Hook Purpose
mds_list_container_attributes Modify wrapper div attributes/classes
mds_list_wrapper_attributes Modify inner wrapper attributes
mds_list_columns Add, remove, or reorder column definitions
mds_list_heading_cell Tweak individual heading cell output
mds_list_heading_cells Modify all heading cells at once
mds_list_orders_sql Customize the SQL query for fetching records
mds_list_rows Filter the rows after fetching from database
mds_list_row_context Alter the data passed to each cell
mds_list_row_cells Modify all cells in a row
mds_list_cell Adjust any cell after rendering
mds_list_cell_{column_key} Adjust a specific column's cell
mds_list_link_* Change advertiser link target, label, or attributes
mds_list_grid_tracks Control CSS Grid column sizing
mds_list_grid_template Replace the final grid-template-columns string
mds_list_default_grid_tracks Override built-in default track sizes

The generated markup wraps the table in a .mds-list-wrapper div so the list can scroll horizontally on narrow screens without breaking the column layout.

Grid Layout Basics

The list renders as a CSS Grid. Each row inherits a grid-template-columns definition via the CSS custom property --mds-list-grid-template. The default template is derived from the active column definitions and filters, so custom columns automatically participate in the layout.

Key points:

  • Provide a grid_track key in your column definition to set an explicit track size (e.g., 'grid_track' => 'minmax(0, 2fr)')
  • Use mds_list_default_grid_tracks to override the built-in defaults for standard columns
  • Use mds_list_fallback_grid_track to change the catch-all template applied to additional columns
  • Filter mds_list_grid_tracks to inspect or modify the array of tracks before serialization
  • Filter mds_list_grid_template to replace the final space-delimited template string entirely

Banner headings are rendered inside a dedicated .mds-banner-row. They receive a data-column-count attribute and automatically span all grid columns, so the banner name always stretches across the full width regardless of how many columns are active.

Example: Add a Launch Date Column

This example shows how an extension can add a Carbon Fields date field to the advertiser form and display it on the list page.

<?php
/**
 * Plugin Name: MDS Launch Date Column
 * Description: Adds a launch date field and list column
 */

use Carbon_Fields\Field\Field;

// 1. Add a launch date field to the advertiser form
add_filter('mds_form_fields', function (array $fields, string $prefix) {
    $fields[] = Field::make('date', $prefix . 'launch_date', __('Launch Date', 'my-extension'))
        ->set_help_text(__('Optional: choose when this campaign goes live.', 'my-extension'))
        ->set_storage_format('Y-m-d');

    return $fields;
}, 10, 2);

// 2. Add a new column to the list view
add_filter('mds_list_columns', function (array $columns) {
    $columns[] = [
        'key'               => 'launch_date',
        'label'             => __('Launch Date', 'my-extension'),
        'render_callback'   => function (array $row_context) {
            $timestamp = strtotime(
                carbon_get_post_meta($row_context['ad_id'], MDS_PREFIX . 'launch_date')
            );

            if (!$timestamp) {
                return __('Not set', 'my-extension');
            }

            return esc_html(date_i18n(get_option('date_format'), $timestamp));
        },
        'cell_attributes'    => ['class' => ['list-cell', 'list-cell--launch-date']],
        'heading_attributes' => ['class' => ['list-heading', 'list-heading--launch-date']],
        'grid_track'         => 'minmax(100px, 1fr)',
    ];

    return $columns;
});

// 3. Optionally decorate future dates with a badge
add_filter('mds_list_cell_launch_date', function (array $cell, array $column, array $row_context) {
    $timestamp = strtotime(
        carbon_get_post_meta($row_context['ad_id'], MDS_PREFIX . 'launch_date')
    );

    if ($timestamp && $timestamp > time()) {
        $cell['content'] .= ' <span class="mds-badge mds-badge--scheduled">'
            . esc_html__('Scheduled', 'my-extension')
            . '</span>';
    }

    return $cell;
}, 10, 3);

The example assumes Carbon Fields is already loaded (it ships with the core plugin). The meta key follows the convention _mds_launch_date thanks to the prefix provided by the filter.

Column Definition Structure

When adding columns via mds_list_columns, each column is an array with these keys:

Key Type Required Description
key string Yes Unique identifier for the column
label string Yes Display text for the heading
render_callback callable Yes Function that returns cell content
cell_attributes array No HTML attributes for <td>
heading_attributes array No HTML attributes for <th>
grid_track string No CSS Grid track size (e.g., '1fr', 'minmax(0, 2fr)')

The render_callback receives a $row_context array containing:

  • ad_id - The post ID of the advertiser/pixel
  • order_id - The order ID
  • banner_id - The banner/grid ID
  • user_id - The user ID
  • Additional row data from the database query

Styling Your Columns

The CSS shipped with MDS recognizes class patterns like .list-cell--{key} and .list-heading--{key}. Target these selectors in your extension's CSS for custom styling:

/* Style the launch date column */
.list-cell--launch-date {
    font-family: monospace;
    color: #666;
}

.list-heading--launch-date {
    min-width: 120px;
}

/* Style the scheduled badge */
.mds-badge--scheduled {
    background: #e3f2fd;
    color: #1976d2;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.85em;
}

When targeting the grid, prefer the provided CSS variables rather than duplicating track definitions:

.mds-container .table-row {
    grid-template-columns: var(--mds-list-grid-template);
}

Additional Customization Ideas

Filter Records

Use mds_list_orders_sql to exclude specific order statuses:

add_filter('mds_list_orders_sql', function (string $sql) {
    // Only show completed orders
    return str_replace(
        'WHERE 1=1',
        "WHERE 1=1 AND order_status = 'completed'",
        $sql
    );
});

Customize Banner Headings

Inject custom content into banner rows:

add_filter('mds_list_banner_heading_cell', function (array $cell, int $banner_id) {
    $custom_text = get_post_meta($banner_id, '_banner_tagline', true);
    if ($custom_text) {
        $cell['content'] .= ' <small>(' . esc_html($custom_text) . ')</small>';
    }
    return $cell;
}, 10, 2);

Replace Advertiser Links

Change the default anchor to a button:

add_filter('mds_list_link_attributes', function (array $attrs, array $row_context) {
    $attrs['class'][] = 'button';
    $attrs['class'][] = 'button-primary';
    return $attrs;
}, 10, 2);

add_filter('mds_list_link_text', function (string $text, array $row_context) {
    return __('View Details', 'my-extension');
}, 10, 2);

Reorder Columns

Remove or reorder existing columns:

add_filter('mds_list_columns', function (array $columns) {
    // Remove a column by key
    $columns = array_filter($columns, function ($col) {
        return $col['key'] !== 'unwanted_column';
    });

    // Reorder: move 'status' to the end
    $status_col = null;
    foreach ($columns as $i => $col) {
        if ($col['key'] === 'status') {
            $status_col = $col;
            unset($columns[$i]);
            break;
        }
    }
    if ($status_col) {
        $columns[] = $status_col;
    }

    return array_values($columns);
});

Best Practices

  1. Use unique column keys - Prefix with your extension slug to avoid conflicts
  2. Escape all output - Always use esc_html(), esc_attr(), etc.
  3. Keep render callbacks fast - Avoid expensive queries; cache if needed
  4. Test with multiple grids - Ensure columns work when list shows all grids
  5. Provide sensible defaults - Handle missing data gracefully
  6. Document your columns - Let site admins know what new columns show

Further Reading