PluginProbe
Hash Form – Drag & Drop Form Builder / trunk
Hash Form – Drag & Drop Form Builder vtrunk
1.4.4 1.4.3 1.4.2 1.4.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.6.1 1.2.7 1.2.8 1.2.9 1.3.0 All 47 releases
hash-form / includes / HashFormStyleBuilder.php

HashFormStyleBuilder.php in Hash Form – Drag & Drop Form Builder trunk, at includes/HashFormStyleBuilder.php

308 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined('ABSPATH') || die();
3
4 /**
5 * The style template builder screen.
6 *
7 * A style template is a set of panels, not a document, so the post editor
8 * around it - title box, publish box, screen options - is chrome nobody uses.
9 * Two of those boxes were already being removed one by one; this takes the
10 * editor out of the picture instead. The editor is redirected here and this
11 * screen owns the whole page.
12 *
13 * The panel itself is untouched: this includes admin/styles/settings.php, so
14 * the sidebar, the live preview, the fields and the footer are exactly what
15 * they were. The builder is addressed with the same `post` query argument the
16 * editor used, which is what that panel reads to decide between Publish and
17 * Update, so it needed no change at all.
18 */
19 class HashFormStyleBuilder {
20
21 const PAGE_SLUG = 'hashform-style-builder';
22 const POST_TYPE = 'hashform-styles';
23
24 /** @var WP_Post|null The template the header is describing. */
25 private $editing = null;
26
27 public function __construct() {
28 add_action('admin_menu', array($this, 'add_page'), 21);
29 add_action('admin_head', array($this, 'hide_page'));
30
31 add_action('load-post.php', array($this, 'redirect_edit'));
32 add_action('load-post-new.php', array($this, 'redirect_new'));
33
34 add_filter('parent_file', array($this, 'parent_file'));
35 add_filter('submenu_file', array($this, 'submenu_file'));
36 add_filter('admin_body_class', array($this, 'body_class'));
37
38 add_action('in_admin_header', array($this, 'list_header'));
39
40 /*
41 * The admin footer belongs to a document-shaped screen. This one is a
42 * full-height editor with its own save bar pinned to the bottom, and
43 * "Thank you for creating with WordPress" underneath it just pushes
44 * that bar off the fold.
45 */
46 add_filter('admin_footer_text', array($this, 'footer_text'));
47 add_filter('update_footer', array($this, 'footer_text'), 11);
48 }
49
50 /**
51 * The builder URL for a template.
52 *
53 * `post` rather than a name of its own: admin/styles/settings.php already
54 * reads that argument to work out whether the template is published, and
55 * addressing the builder the same way the editor was keeps the panel
56 * working untouched.
57 *
58 * Deliberately nothing else. A new template used to be addressed with
59 * post_type as well, the way post-new.php was, and that argument is what
60 * wp-admin/admin.php reads into $typenow - so core resolved this screen's
61 * hook against `admin.php?post_type=hashform-styles`, a parent with no
62 * entry in $admin_page_hooks, looked for admin_page_hashform-style-builder
63 * rather than the hash-form_page_ name the submenu is registered under,
64 * found nothing and died with "Cannot load hashform-style-builder". The
65 * panel does not need it: it reads Publish or Update off the template's
66 * own post status.
67 *
68 * @param int $post_id
69 * @return string
70 */
71 public static function url($post_id = 0) {
72 $args = array('page' => self::PAGE_SLUG);
73
74 if ($post_id) {
75 $args['post'] = absint($post_id);
76 }
77
78 return add_query_arg($args, admin_url('admin.php'));
79 }
80
81 /**
82 * The style template list.
83 *
84 * @return string
85 */
86 public static function list_url() {
87 return admin_url('edit.php?post_type=' . self::POST_TYPE);
88 }
89
90 /**
91 * Whether the screen being rendered is the builder.
92 *
93 * @return bool
94 */
95 public static function is_builder() {
96 return is_admin() && self::PAGE_SLUG === HashFormHelper::get_var('page', 'sanitize_title');
97 }
98
99 /**
100 * Registered so it is reachable, hidden because it edits one template.
101 */
102 public function add_page() {
103 add_submenu_page(
104 'hashform',
105 esc_html__('Edit Style Template', 'hash-form'),
106 esc_html__('Edit Style Template', 'hash-form'),
107 'edit_hashform_styles',
108 self::PAGE_SLUG,
109 array($this, 'render')
110 );
111 }
112
113 public function hide_page() {
114 remove_submenu_page('hashform', self::PAGE_SLUG);
115 }
116
117 /**
118 * Sends the post editor to the builder.
119 */
120 public function redirect_edit() {
121 $post_id = absint(HashFormHelper::get_var('post', 'absint'));
122
123 if (!$post_id || self::POST_TYPE !== get_post_type($post_id)) {
124 return;
125 }
126
127 // Somebody who cannot edit it should meet the editor's own message
128 // rather than a builder that will not save.
129 if (!current_user_can('edit_post', $post_id)) {
130 return;
131 }
132
133 wp_safe_redirect(self::url($post_id));
134 exit;
135 }
136
137 /**
138 * Sends Add New to the builder.
139 */
140 public function redirect_new() {
141 if (self::POST_TYPE !== HashFormHelper::get_var('post_type', 'sanitize_key')) {
142 return;
143 }
144
145 if (!current_user_can('edit_hashform_styles')) {
146 return;
147 }
148
149 wp_safe_redirect(self::url());
150 exit;
151 }
152
153 /**
154 * The style list stays highlighted rather than the hidden builder entry.
155 */
156 public function parent_file($parent_file) {
157 return self::is_builder() ? 'hashform' : $parent_file;
158 }
159
160 public function submenu_file($submenu_file) {
161 return self::is_builder() ? 'edit.php?post_type=' . self::POST_TYPE : $submenu_file;
162 }
163
164 /**
165 * Empties the admin footer on this screen, and leaves it alone elsewhere.
166 *
167 * @param string $text
168 * @return string
169 */
170 public function footer_text($text) {
171 return self::is_builder() ? '' : $text;
172 }
173
174 public function body_class($classes) {
175 return self::is_builder() ? $classes . ' hf-style-builder-screen' : $classes;
176 }
177
178 /**
179 * The template being edited.
180 *
181 * A new one is a post object that exists only for this request. post-new.php
182 * used to write an auto-draft just for opening the screen, which is why the
183 * templates list collects rows nobody asked for; nothing is written here
184 * until Save, and the panel reads its defaults from an id of 0 quite
185 * happily.
186 *
187 * @return WP_Post|null
188 */
189 protected function current_post() {
190 $post_id = absint(HashFormHelper::get_var('post', 'absint'));
191
192 if ($post_id) {
193 $post = get_post($post_id);
194
195 return ($post && self::POST_TYPE === $post->post_type) ? $post : null;
196 }
197
198 return new WP_Post((object) array(
199 'ID' => 0,
200 'post_title' => '',
201 'post_type' => self::POST_TYPE,
202 'post_status' => 'auto-draft',
203 ));
204 }
205
206 public function render() {
207 if (!current_user_can('edit_hashform_styles')) {
208 wp_die(esc_html__('You are not allowed to edit style templates.', 'hash-form'));
209 }
210
211 $post = $this->current_post();
212
213 if (!$post) {
214 wp_die(esc_html__('That style template no longer exists.', 'hash-form'));
215 }
216
217 // The panel reads the template from the global, exactly as it did
218 // inside the metabox.
219 $GLOBALS['post'] = $post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
220 setup_postdata($post);
221
222 $this->editing = $post;
223 ?>
224 <?php
225 /*
226 * No .wrap of its own: admin/styles/settings.php opens the .hf-content
227 * the panel's styles are scoped to, and the bar above comes from
228 * in_admin_header like every other screen. Wrapping the panel in a
229 * second frame is what broke the sidebar headings.
230 */
231 ?>
232 <form method="post" id="post" class="hf-style-builder">
233 <input type="hidden" id="post_ID" name="post_ID" value="<?php echo absint($post->ID); ?>"/>
234 <?php
235 // The panel, unchanged. Rendered through HashFormStyles so that
236 // `self` inside the template resolves to that class, which is where
237 // the helpers it calls live.
238 HashFormStyles::render_settings_panel();
239 ?>
240 </form>
241 <?php
242 wp_reset_postdata();
243 }
244
245
246 /**
247 * The bar across the top, through the shared renderer.
248 *
249 * Printed on in_admin_header like every other hashform screen, so this
250 * reads as the same product as the list it came from rather than carrying
251 * a header of its own.
252 */
253 public function list_header() {
254 if (!self::is_builder()) {
255 return;
256 }
257
258 $post = $this->editing ? $this->editing : $this->current_post();
259
260 if (!$post) {
261 return;
262 }
263
264 $actions = array();
265
266 if ($post->ID) {
267 $trash = get_delete_post_link($post->ID);
268
269 if ($trash) {
270 // post.php sends the browser back where it came from, which
271 // here is a builder for a template that no longer exists.
272 $actions[] = array(
273 'label' => esc_html__('Trash', 'hash-form'),
274 'url' => add_query_arg('_wp_http_referer', rawurlencode(self::list_url()), $trash),
275 'class' => 'hf-list-action-trash',
276 );
277 }
278 }
279
280 $actions[] = array(
281 'label' => esc_html__('All Style Templates', 'hash-form'),
282 'url' => self::list_url(),
283 );
284
285 HashFormHelper::render_list_header(array(
286 'title' => $post->ID
287 ? esc_html__('Style template name', 'hash-form')
288 : esc_html__('Add New Style Template', 'hash-form'),
289 /*
290 * The name lives in the bar rather than in a row of its own. The
291 * form attribute is what carries it: this is printed on
292 * in_admin_header, outside the builder's form, and a field that is
293 * not associated with that form is simply dropped on save.
294 */
295 'title_field' => array(
296 'name' => 'post_title',
297 'value' => $post->post_title,
298 'placeholder' => esc_html__('Name this style template', 'hash-form'),
299 'form' => 'post',
300 ),
301 'actions' => $actions,
302 ));
303 }
304
305 }
306
307 new HashFormStyleBuilder();
308