PluginProbe ʕ •ᴥ•ʔ
AlphaListing / 4.4.0
AlphaListing v4.4.0
trunk 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0
alphalisting / src / Shortcode / QueryParts / ColumnWidth.php
alphalisting / src / Shortcode / QueryParts Last commit date
Alphabet.php 1 month ago BackToTop.php 1 month ago ColumnGap.php 1 month ago ColumnWidth.php 1 month ago Columns.php 1 month ago ExcludePosts.php 1 month ago ExcludeTerms.php 1 month ago HideEmptyTerms.php 1 month ago HideEmpty_Deprecated.php 1 month ago InstanceId.php 1 month ago ParentPost.php 1 month ago ParentTermCommon.php 1 month ago ParentTermId.php 1 month ago ParentTermSlugOrId.php 1 month ago PostType.php 1 month ago PostsTerms.php 1 month ago SymbolsFirst.php 1 month ago Taxonomy.php 1 month ago TermsCommon.php 1 month ago TermsTerms.php 1 month ago
ColumnWidth.php
147 lines
1 <?php
2 /**
3 * Alphabet Query Part.
4 *
5 * @package alphalisting
6 */
7
8 declare(strict_types=1);
9
10 namespace eslin87\AlphaListing\Shortcode\QueryParts;
11
12 if (!defined("ABSPATH")) {
13 exit();
14 }
15
16 use eslin87\AlphaListing\Shortcode\Extension;
17
18 /**
19 * Column Width Query Part extension
20 */
21 class ColumnWidth extends Extension {
22 private const ALLOWED_UNITS = ['px', 'em', 'rem', '%', 'ch'];
23 private const MAX_PIXEL_VALUE = 1200.0;
24 private const MAX_PERCENT_VALUE = 100.0;
25 public const DEFAULT_COLUMN_WIDTH = '15em';
26
27 /**
28 * The attribute for this Query Part.
29 *
30 * @since 4.0.0
31 * @var string
32 */
33 public $attribute_name = 'column-width';
34
35 /**
36 * The column width.
37 *
38 * @var string
39 */
40 public $column_width = self::DEFAULT_COLUMN_WIDTH;
41
42 /**
43 * Sanitize the shortcode attribute.
44 *
45 * @param mixed $value The value of the shortcode attribute.
46 * @param array $attributes The complete set of shortcode attributes.
47 * @return string
48 */
49 public function sanitize_attribute($value, array $attributes) {
50 return $this->sanitize_css_length($value, self::DEFAULT_COLUMN_WIDTH);
51 }
52
53 /**
54 * Update the query with this extension's additional configuration.
55 *
56 * @param \AlphaListing\Query $query The query.
57 * @param string $display The display/query type.
58 * @param string $key The name of the attribute.
59 * @param mixed $value The shortcode attribute value.
60 * @param array $attributes The complete set of shortcode attributes.
61 * @return mixed The updated query.
62 */
63 public function shortcode_query($query, string $display, string $key, $value, array $attributes) {
64 $this->column_width = $this->sanitize_css_length($value, self::DEFAULT_COLUMN_WIDTH);
65 $this->add_hook('filter', 'alphalisting_styles', [$this, 'return_styles'], 10, 3);
66 return $query;
67 }
68
69 /**
70 * Return the stylesheet for this instance.
71 *
72 * @param string $styles The stylesheet.
73 * @param mixed $query The listing query instance passed by the filter.
74 * @param mixed $instance_id The listing instance id passed by the filter.
75 * @return string
76 */
77 public function return_styles($styles, $query = null, $instance_id = null): string {
78 return sprintf('%s --alphalisting-column-width: %s; ', $styles, $this->column_width);
79 }
80
81 /**
82 * Ensure the provided column width is a safe CSS length value.
83 *
84 * @param mixed $value Potential CSS length value.
85 * @param string $default Default value to use when sanitization fails.
86 * @return string
87 */
88 private function sanitize_css_length($value, string $default): string {
89 if (is_string($value)) {
90 $value = trim($value);
91 } elseif (is_numeric($value)) {
92 $value = (string) $value;
93 } else {
94 return $default;
95 }
96
97 if ('' === $value) {
98 return $default;
99 }
100
101 if (preg_match('/^0+(?:\.0+)?$/', $value)) {
102 return '0';
103 }
104
105 if (!preg_match('/^([0-9]+(?:\.[0-9]+)?)\s*(px|em|rem|%|ch)$/i', $value, $matches)) {
106 return $default;
107 }
108
109 $number = (float) $matches[1];
110 $unit = strtolower($matches[2]);
111
112 if (!in_array($unit, self::ALLOWED_UNITS, true)) {
113 return $default;
114 }
115
116 if ($number < 0) {
117 return $default;
118 }
119
120 if ('px' === $unit) {
121 $number = min($number, self::MAX_PIXEL_VALUE);
122 }
123
124 if (in_array($unit, ['%', 'ch'], true)) {
125 $number = min($number, self::MAX_PERCENT_VALUE);
126 }
127
128 $number_string = $this->format_numeric_value($number);
129
130 return $number_string . $unit;
131 }
132
133 /**
134 * Normalize numeric values before concatenating with units.
135 *
136 * @param float $number The numeric value to format.
137 * @return string
138 */
139 private function format_numeric_value(float $number): string {
140 if (floor($number) === $number) {
141 return (string) (int) $number;
142 }
143
144 return rtrim(rtrim(sprintf('%.4f', $number), '0'), '.');
145 }
146 }
147