Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.30% covered (success)
91.30%
42 / 46
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Column
91.30% covered (success)
91.30%
42 / 46
66.67% covered (warning)
66.67%
4 / 6
16.17
0.00% covered (danger)
0.00%
0 / 1
 init
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
4.02
 renderColumnsHead
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 renderColumnsContent
80.00% covered (success)
80.00%
12 / 15
0.00% covered (danger)
0.00%
0 / 1
6.29
 makeColumnSortable
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setSortQuery
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getSortQueryArgs
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/**
6 * BeyondWords Posts Column.
7 *
8 * @package Beyondwords\Wordpress
9 * @author  Stuart McAlpine <stu@beyondwords.io>
10 * @since   3.0.0
11 */
12
13namespace Beyondwords\Wordpress\Component\Posts\Column;
14
15use Beyondwords\Wordpress\Component\Post\PostMetaUtils;
16use Beyondwords\Wordpress\Component\Settings\SettingsUtils;
17use Beyondwords\Wordpress\Core\CoreUtils;
18
19/**
20 * Column
21 *
22 * @since 3.0.0
23 */
24defined('ABSPATH') || exit;
25
26class Column
27{
28    public const ALLOWED_HTML = [
29        'span' => [
30            'class'   => [],
31        ],
32    ];
33
34    public const OUTPUT_YES = '<span class="dashicons dashicons-yes"></span> ';
35
36    public const OUTPUT_NO = '—';
37
38    public const OUTPUT_DISABLED = ' <span class="beyondwords--disabled">Disabled</span>';
39
40    public const OUTPUT_ERROR_PREFIX = '<span class="dashicons dashicons-warning"></span> ';
41
42    /**
43     * Init.
44     *
45     * @since 4.0.0
46     * @since 4.5.0 Make BeyondWords column sortable via the pre_get_posts query.
47     * @since 6.0.0 Make static.
48     */
49    public static function init()
50    {
51        add_action('wp_loaded', function (): void {
52            $postTypes = SettingsUtils::getCompatiblePostTypes();
53
54            if (is_array($postTypes)) {
55                foreach ($postTypes as $postType) {
56                    add_filter("manage_{$postType}_posts_columns", [self::class, 'renderColumnsHead']);
57                    add_action("manage_{$postType}_posts_custom_column", [self::class, 'renderColumnsContent'], 10, 2); // phpcs:ignore Generic.Files.LineLength.TooLong
58                    add_filter("manage_edit-{$postType}_sortable_columns", [self::class, 'makeColumnSortable']);
59                }
60            }
61        });
62
63        if (CoreUtils::isEditScreen()) {
64            add_action('pre_get_posts', [self::class, 'setSortQuery']);
65        }
66    }
67
68    /**
69     * Add a custom column with player status.
70     *
71     * @since 3.0.0
72     * @since 6.0.0 Make static.
73     *
74     * @param array $columns Array of <td> headers
75     *
76     * @return array
77     **/
78    public static function renderColumnsHead($columns)
79    {
80        return array_merge($columns, [
81            'beyondwords' => __('BeyondWords', 'speechkit'),
82        ]);
83    }
84
85    /**
86     * Render ✗|✓ in Posts list, under the BeyondWords column.
87     *
88     * @since 3.0.0
89     * @since 6.0.0 Make static and refactor using self::ALLOWED_HTML and PostMetaUtils.
90     *
91     * @param string $columnName Column name
92     * @param int    $postId     Post ID
93     *
94     * @return void
95     **/
96    public static function renderColumnsContent($columnName, $postId)
97    {
98        if ($columnName !== 'beyondwords') {
99            return;
100        }
101
102        $postTypes = SettingsUtils::getCompatiblePostTypes();
103
104        if (empty($postTypes)) {
105            return;
106        }
107
108        $errorMessage = PostMetaUtils::getErrorMessage($postId);
109        $hasContent   = PostMetaUtils::hasContent($postId);
110        $disabled     = PostMetaUtils::getDisabled($postId);
111
112        if (! empty($errorMessage)) {
113            echo wp_kses(self::OUTPUT_ERROR_PREFIX . $errorMessage, self::ALLOWED_HTML);
114        } elseif ($hasContent) {
115            echo wp_kses(self::OUTPUT_YES, self::ALLOWED_HTML);
116        } else {
117            echo wp_kses(self::OUTPUT_NO, self::ALLOWED_HTML);
118        }
119
120        if (! empty($disabled)) {
121            echo wp_kses(self::OUTPUT_DISABLED, self::ALLOWED_HTML);
122        }
123    }
124
125    /**
126     * Make the BeyondWords column sortable.
127     *
128     * @since 4.5.1
129     * @since 6.0.0 Make static.
130     *
131     * @param array $sortableColumns An array of sortable columns.
132     *
133     * @return array The adjusted array of sortable columns.
134     **/
135    public static function makeColumnSortable($sortableColumns)
136    {
137        // Make column 'beyondwords' sortable
138        $sortableColumns['beyondwords'] = 'beyondwords';
139
140        return $sortableColumns;
141    }
142
143    /**
144     * Set the query to sort by BeyondWords fields.
145     *
146     * @since 4.5.1
147     * @since 6.0.0 Make static.
148     *
149     * @param WP_Query $query WordPress query.
150     *
151     * @return WP_Query The adjusted query.
152     */
153    public static function setSortQuery($query)
154    {
155        $orderBy = $query->get('orderby');
156
157        if ($orderBy === 'beyondwords' && $query->is_main_query()) {
158            $query->set('meta_query', self::getSortQueryArgs());
159            $query->set('orderby', 'meta_value_num date');
160        }
161
162        return $query;
163    }
164
165    /**
166     * Get the sort search query args.
167     *
168     * @since 4.5.1
169     * @since 6.0.0 Make static.
170     *
171     * @param array $sortableColumns An array of sortable columns.
172     *
173     * @return array
174     */
175    public static function getSortQueryArgs()
176    {
177        return [
178            'relation' => 'OR',
179            [
180                'key' => 'beyondwords_generate_audio',
181                'compare' => 'NOT EXISTS',
182            ],
183            [
184                'key' => 'beyondwords_generate_audio',
185                'compare' => 'EXISTS',
186            ],
187        ];
188    }
189}