Test Failed
Push — develop ( 66133f...833c7b )
by Paul
06:57
created

Shortcode::buildShortcode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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