Test Failed
Push — develop ( db5b9c...b55dd4 )
by Paul
17:52
created

Shortcode::attributes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 11
c 0
b 0
f 0
dl 0
loc 14
ccs 0
cts 11
cp 0
rs 9.9
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Shortcodes;
4
5
use GeminiLabs\SiteReviews\Contracts\ShortcodeContract;
6
use GeminiLabs\SiteReviews\Database\ShortcodeOptionManager;
7
use GeminiLabs\SiteReviews\Defaults\DefaultsAbstract;
8
use GeminiLabs\SiteReviews\Helper;
9
use GeminiLabs\SiteReviews\Helpers\Arr;
10
use GeminiLabs\SiteReviews\Helpers\Cast;
11
use GeminiLabs\SiteReviews\Helpers\Str;
12
use GeminiLabs\SiteReviews\Modules\Html\Builder;
13
use GeminiLabs\SiteReviews\Modules\Multilingual;
14
use GeminiLabs\SiteReviews\Modules\Rating;
15
use GeminiLabs\SiteReviews\Modules\Sanitizer;
16
use GeminiLabs\SiteReviews\Modules\Style;
17
18
abstract class Shortcode implements ShortcodeContract
19
{
20
    public array $args;
21
    public string $debug;
22
    public string $description;
23
    public string $from;
24 8
    public string $name;
25
    public string $tag;
26 8
27
    public function __construct()
28
    {
29
        $this->args = [];
30
        $this->debug = '';
31
        $this->description = $this->description();
32
        $this->from = '';
33
        $this->name = $this->name();
34
        $this->tag = $this->tag();
35
    }
36
37
    public function attributes(array $values, string $from = 'function'): array
38
    {
39
        $attributes = $this->defaults()->dataAttributes($values);
40
        $attributes = wp_parse_args($attributes, [
41
            'class' => glsr(Style::class)->styleClasses(),
42
            'data-from' => $from,
43
            'data-shortcode' => $this->tag,
44
            'id' => Arr::get($values, 'id'),
45
        ]);
46
        unset($attributes['data-id']);
47
        unset($attributes['data-form_id']);
48
        $attributes = glsr()->filterArray("shortcode/{$this->tag}/attributes", $attributes, $this);
49
        $attributes = array_map('esc_attr', $attributes);
50
        return $attributes;
51
    }
52
53
    public function build($args = [], string $from = 'shortcode'): string
54
    {
55
        $this->normalize(wp_parse_args($args), $from);
56
        $template = $this->buildTemplate();
57
        $attributes = $this->attributes($this->args, $from);
58
        $html = glsr(Builder::class)->div($template, $attributes);
59
        return sprintf('%s%s', $this->debug, $html);
60
    }
61
62
    public function defaults(): DefaultsAbstract
63
    {
64
        $classname = str_replace('Shortcodes\\', 'Defaults\\', get_class($this));
65
        $classname = str_replace('Shortcode', 'Defaults', $classname);
66
        return glsr($classname);
67
    }
68
69
    public function hasVisibleFields(array $args = []): bool
70
    {
71
        if (!empty($args)) {
72
            $this->normalize($args);
73
        }
74
        $defaults = $this->options('hide');
75
        $hide = $this->args['hide'] ?? [];
76
        $hide = array_flip(Arr::consolidate($hide));
77
        unset($defaults['if_empty'], $hide['if_empty']);
78
        return !empty(array_diff_key($defaults, $hide));
79
    }
80
81
    public function normalize(array $args, string $from = ''): ShortcodeContract
82
    {
83 8
        if (!empty($from)) {
84
            $this->from = $from;
85 8
        }
86 8
        $args = glsr()->filterArray('shortcode/args', $args, $this->tag);
87
        $args = $this->defaults()->unguardedRestrict($args);
88
        foreach ($args as $key => &$value) {
89
            $method = Helper::buildMethodName('normalize', $key);
90
            if (method_exists($this, $method)) {
91
                $value = call_user_func([$this, $method], $value, $args);
92
            }
93
        }
94
        $this->args = $args;
95
        return $this;
96
    }
97
98
    /**
99
     * Returns the options for a shortcode setting. Results are filtered
100
     * by the "site-reviews/shortcode/options/{$options}" hook.
101
     */
102
    public function options(string $option, array $args = []): array
103
    {
104
        $args['option'] = $option;
105
        $args['shortcode'] = $this->tag;
106
        return call_user_func([glsr(ShortcodeOptionManager::class), $option], $args);
107
    }
108
109
    public function register(): void
110
    {
111
        if (!function_exists('add_shortcode')) {
112
            return;
113
        }
114
        $shortcode = (new \ReflectionClass($this))->getShortName();
115
        $shortcode = Str::snakeCase($shortcode);
116
        $shortcode = str_replace('_shortcode', '', $shortcode);
117
        add_shortcode($shortcode, fn ($atts) => $this->build($atts));
118
        glsr()->append('shortcodes', get_class($this), $shortcode);
119
    }
120
121
    /**
122
     * Returns the filtered shortcode settings configuration.
123
     */
124
    public function settings(): array
125
    {
126
        $config = $this->config();
127
        $config = glsr()->filterArray("shortcode/{$this->tag}/config", $config, $this);
128
        $config = glsr()->filterArray('shortcode/config', $config, $this->tag, $this);
129
        return $config;
130
    }
131
132
    public function tag(): string
133
    {
134
        return Str::snakeCase(
135
            str_replace('Shortcode', '', (new \ReflectionClass($this))->getShortName())
136
        );
137
    }
138
139
    /**
140
     * Returns the unfiltered shortcode settings configuration.
141
     */
142
    abstract protected function config(): array;
143
144
    protected function debug(array $data = []): void
145
    {
146
        if (empty($this->args['debug']) || 'shortcode' !== $this->from) {
147
            return;
148
        }
149
        $data = wp_parse_args($data, [
150
            'args' => $this->args,
151
            'shortcode' => $this->tag,
152
        ]);
153
        ksort($data);
154
        ob_start();
155
        glsr_debug($data);
156
        $this->debug = ob_get_clean();
157
    }
158
159
    protected function displayOptions(): array
160
    {
161
        return [];
162
    }
163
164
    protected function hideOptions(): array
165
    {
166
        return [];
167
    }
168
169
    /**
170
     * @param string $value
171
     */
172
    protected function normalizeAssignedPosts($value): string
173
    {
174
        $values = Cast::toArray($value);
175
        $postTypes = [];
176
        foreach ($values as $postType) {
177
            if (!is_numeric($postType) && post_type_exists((string) $postType)) {
178
                $postTypes[] = $postType;
179
            }
180
        }
181
        $values = glsr(Sanitizer::class)->sanitizePostIds($values);
182
        $values = glsr(Multilingual::class)->getPostIdsForAllLanguages($values);
183
        $values = array_merge($values, $postTypes);
184
        return implode(',', $values);
185
    }
186
187
    /**
188
     * @param string $value
189
     */
190
    protected function normalizeAssignedTerms($value): string
191
    {
192
        $values = glsr(Sanitizer::class)->sanitizeTermIds($value);
193
        $values = glsr(Multilingual::class)->getTermIdsForAllLanguages($values);
194
        return implode(',', $values);
195
    }
196
197
    /**
198
     * @param string $value
199
     */
200
    protected function normalizeAssignedUsers($value): string
201
    {
202
        $values = glsr(Sanitizer::class)->sanitizeUserIds($value);
203
        return implode(',', $values);
204
    }
205
206
    /**
207
     * @param string|array $value
208
     */
209
    protected function normalizeHide($value): array
210
    {
211
        $hideKeys = array_keys($this->options('hide'));
212
        return array_filter(Cast::toArray($value),
213
            fn ($value) => in_array($value, $hideKeys)
214
        );
215
    }
216
217 8
    /**
218
     * @param string $value
219 8
     */
220 8
    protected function normalizeLabels($value): array
221 8
    {
222
        $defaults = [
223
            __('Excellent', 'site-reviews'),
224
            __('Very good', 'site-reviews'),
225
            __('Average', 'site-reviews'),
226
            __('Poor', 'site-reviews'),
227
            __('Terrible', 'site-reviews'),
228
        ];
229
        $maxRating = Rating::max();
230
        $defaults = array_pad(array_slice($defaults, 0, $maxRating), $maxRating, '');
231
        $labels = array_map('trim', explode(',', $value));
232
        foreach ($defaults as $i => $label) {
233
            if (!empty($labels[$i])) {
234
                $defaults[$i] = $labels[$i];
235
            }
236
        }
237
        return array_combine(range($maxRating, 1), $defaults);
238
    }
239
}
240