This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Amarkal\Taxonomy; |
||
4 | |||
5 | /** |
||
6 | * WordPress taxonomy form utilities |
||
7 | */ |
||
8 | class Form |
||
9 | { |
||
10 | /** |
||
11 | * @var Singleton The reference to *Singleton* instance of this class |
||
12 | */ |
||
13 | private static $instance; |
||
14 | |||
15 | /** |
||
16 | * @var Array Stores a form for each taxonomy |
||
17 | */ |
||
18 | private $forms = array(); |
||
19 | |||
20 | /** |
||
21 | * Returns the *Singleton* instance of this class. |
||
22 | * |
||
23 | * @return Singleton The *Singleton* instance. |
||
24 | */ |
||
25 | public static function get_instance() |
||
26 | { |
||
27 | if( null === static::$instance ) |
||
28 | { |
||
29 | static::$instance = new static(); |
||
30 | } |
||
31 | return static::$instance; |
||
32 | } |
||
33 | |||
34 | /** |
||
35 | * Add a form field to both the add & edit forms for a given taxonomy. |
||
36 | * |
||
37 | * @param string $taxonomy_name |
||
38 | * @param array $component |
||
39 | * @throws \RuntimeException if duplicate names are registered under the same taxonomy |
||
40 | */ |
||
41 | public function add_field( $taxonomy_name, $component ) |
||
42 | { |
||
43 | if( !isset($this->forms[$taxonomy_name]) ) |
||
44 | { |
||
45 | // Add fields to taxonomy add and edit forms |
||
46 | add_action( "{$taxonomy_name}_add_form_fields", array($this, 'render_add_form') ); |
||
47 | add_action( "{$taxonomy_name}_edit_form_fields", array($this, 'render_edit_form') ); |
||
48 | |||
49 | // Save the data from taxonomy add and edit forms |
||
50 | add_action( "create_{$taxonomy_name}", array($this, 'update_term') ); |
||
51 | add_action( "edited_{$taxonomy_name}", array($this, 'update_term') ); |
||
52 | |||
53 | // Modify the taxonomy term table |
||
54 | add_filter( "manage_edit-{$taxonomy_name}_columns", array($this, 'modify_table_columns') ); |
||
55 | add_filter( "manage_{$taxonomy_name}_custom_column", array($this, 'modify_table_content'), 10, 3 ); |
||
56 | add_filter( "manage_edit-{$taxonomy_name}_sortable_columns", array($this, 'modify_table_sortable_columns') ); |
||
57 | add_filter( 'terms_clauses', array($this, 'sort_custom_column'), 10, 3 ); |
||
58 | |||
59 | $this->forms[$taxonomy_name] = new \Amarkal\UI\Form(); |
||
60 | } |
||
61 | |||
62 | $this->forms[$taxonomy_name]->add_component( |
||
63 | array_merge( $this->default_props(), $component ) |
||
64 | ); |
||
65 | } |
||
66 | |||
67 | /** |
||
68 | * Render the 'edit term' form for a given taxonomy |
||
69 | * |
||
70 | * @param object $term Taxonomy term |
||
71 | */ |
||
72 | public function render_edit_form( $term ) |
||
73 | { |
||
74 | $form = $this->forms[$term->taxonomy]; |
||
75 | $new_instance = array(); |
||
76 | |||
77 | foreach( $form->get_components() as $component ) |
||
78 | { |
||
79 | $new_instance[$component->name] = \get_term_meta($term->term_id, $component->name, true); |
||
80 | } |
||
81 | |||
82 | $form->update($new_instance); |
||
83 | |||
84 | include __DIR__.'/EditForm.phtml'; |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * Render the 'add new term' form for a given taxonomy |
||
89 | * |
||
90 | * @param string $taxonomy Taxonomy name |
||
91 | */ |
||
92 | public function render_add_form( $taxonomy ) |
||
93 | { |
||
94 | $form = $this->forms[$taxonomy]; |
||
95 | $form->update(); |
||
96 | |||
97 | include __DIR__.'/AddForm.phtml'; |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * Update the meta values for a given term. Called once one of the add/edit |
||
102 | * forms is saved. |
||
103 | * |
||
104 | * @param type $term_id |
||
105 | */ |
||
106 | function update_term( $term_id ) |
||
107 | { |
||
108 | $term = \get_term( $term_id ); |
||
109 | |||
110 | foreach( $this->forms[$term->taxonomy]->get_components() as $component ) |
||
111 | { |
||
112 | $term_meta = filter_input(INPUT_POST, $component->name); |
||
113 | if( null !== $term_meta ) |
||
114 | { |
||
115 | \update_term_meta($term_id, $component->name, $term_meta); |
||
116 | } |
||
117 | } |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Add additional columns to the term table. |
||
122 | * |
||
123 | * @param array $columns |
||
124 | * @return array |
||
125 | */ |
||
126 | View Code Duplication | function modify_table_columns( $columns ) |
|
0 ignored issues
–
show
|
|||
127 | { |
||
128 | $this->traverse_components(function( $taxonomy, $component ) use ( &$columns ) |
||
129 | { |
||
130 | if( $component->table['show'] ) |
||
131 | { |
||
132 | $columns[$component->name] = $component->title; |
||
133 | } |
||
134 | }); |
||
135 | return $columns; |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Retrieve the data for a given column in the term table. |
||
140 | * |
||
141 | * @see https://developer.wordpress.org/reference/hooks/manage_this-screen-taxonomy_custom_column/ |
||
142 | * |
||
143 | * @param type $content |
||
144 | * @param type $column_name |
||
145 | * @param type $term_id |
||
146 | * @return type |
||
147 | */ |
||
148 | function modify_table_content( $content, $column_name, $term_id ) |
||
149 | { |
||
150 | $term = \get_term($term_id); |
||
151 | $this->traverse_components(function( $taxonomy, $component ) use ( &$content, $column_name, $term ) |
||
152 | { |
||
153 | if( $component->table['show'] && |
||
154 | $term->taxonomy === $taxonomy && |
||
155 | $component->name === $column_name |
||
156 | ) { |
||
157 | $content = \get_term_meta($term->term_id, $component->name, true); |
||
158 | } |
||
159 | }); |
||
160 | return $content; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Make custom table columns sortable. |
||
165 | * |
||
166 | * @param array $columns |
||
167 | * @return string |
||
168 | */ |
||
169 | View Code Duplication | function modify_table_sortable_columns( $columns ) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
170 | { |
||
171 | $this->traverse_components(function( $taxonomy, $component ) use ( &$columns ) |
||
172 | { |
||
173 | if( $component->table['show'] && |
||
174 | $component->table['sortable'] |
||
175 | ) { |
||
176 | $columns[$component->name] = $component->name; |
||
177 | } |
||
178 | }); |
||
179 | return $columns; |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * Modify terms_clauses to allow sorting custom WordPress Admin Table Columns by a custom Taxonomy Term meta |
||
184 | * |
||
185 | * @see https://developer.wordpress.org/reference/hooks/terms_clauses/ |
||
186 | * |
||
187 | * @global type $wpdb |
||
188 | * @param type $clauses |
||
189 | * @param type $taxonomies |
||
190 | * @param type $args |
||
191 | * @return string |
||
192 | */ |
||
193 | public function sort_custom_column( $clauses, $taxonomies, $args ) |
||
194 | { |
||
195 | $this->traverse_components(function( $taxonomy, $component ) use ( &$clauses, $args ) |
||
196 | { |
||
197 | if( in_array($taxonomy, $args['taxonomy']) && |
||
198 | $component->table['sortable'] && |
||
199 | $component->name === $args['orderby'] |
||
200 | ) |
||
201 | { |
||
202 | global $wpdb; |
||
203 | // tt refers to the $wpdb->term_taxonomy table |
||
204 | $clauses['join'] .= " LEFT JOIN {$wpdb->termmeta} AS tm ON t.term_id = tm.term_id"; |
||
205 | $clauses['where'] = "tt.taxonomy = '{$taxonomy}' AND (tm.meta_key = '{$component->name}' OR tm.meta_key IS NULL)"; |
||
206 | $clauses['orderby'] = "ORDER BY tm.meta_value"; |
||
207 | } |
||
208 | }); |
||
209 | return $clauses; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * The default form field properties. This is merged with the user given |
||
214 | * properties. When the component is rendered, this will be merged with the |
||
215 | * component's properties as well. |
||
216 | * |
||
217 | * @return array |
||
218 | */ |
||
219 | private function default_props() |
||
220 | { |
||
221 | return array( |
||
222 | 'type' => null, |
||
223 | 'title' => null, |
||
224 | 'description' => null, |
||
225 | 'table' => array( |
||
226 | 'show' => false, |
||
227 | 'sortable' => false |
||
228 | ) |
||
229 | ); |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Treverse the $fields array. |
||
234 | * |
||
235 | * @param collable $callback Called on each iteration |
||
236 | */ |
||
237 | private function traverse_components( $callback ) |
||
238 | { |
||
239 | foreach( $this->forms as $taxonomy => $form ) |
||
240 | { |
||
241 | foreach( $form->get_components() as $component ) |
||
242 | { |
||
243 | $callback( $taxonomy, $component ); |
||
244 | } |
||
245 | } |
||
246 | } |
||
247 | } |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.