| 1 |
<?php |
| 2 |
/** |
| 3 |
* SureForms Single Entries Page. |
| 4 |
* |
| 5 |
* @since 0.0.13 |
| 6 |
* @package sureforms. |
| 7 |
*/ |
| 8 |
|
| 9 |
namespace SRFM\Admin\Views; |
| 10 |
|
| 11 |
use SRFM\Inc\Database\Tables\Entries; |
| 12 |
use SRFM\Inc\Helper; |
| 13 |
|
| 14 |
/** |
| 15 |
* Exit if accessed directly. |
| 16 |
*/ |
| 17 |
if ( ! defined( 'ABSPATH' ) ) { |
| 18 |
exit; |
| 19 |
} |
| 20 |
|
| 21 |
/** |
| 22 |
* Single entry page. |
| 23 |
* |
| 24 |
* @since 0.0.13 |
| 25 |
*/ |
| 26 |
class Single_Entry { |
| 27 |
/** |
| 28 |
* Stores the entry ID. |
| 29 |
* |
| 30 |
* @var string|null $entry_id ID for the specific entry. |
| 31 |
* @since 0.0.13 |
| 32 |
*/ |
| 33 |
private $entry_id; |
| 34 |
|
| 35 |
/** |
| 36 |
* Stores the entry data for the specified entry ID. |
| 37 |
* |
| 38 |
* @var array<mixed>|null $entry Entry data for the specified entry ID. |
| 39 |
* @since 0.0.13 |
| 40 |
*/ |
| 41 |
private $entry; |
| 42 |
|
| 43 |
/** |
| 44 |
* Initialize the properties. |
| 45 |
* |
| 46 |
* @since 0.0.13 |
| 47 |
*/ |
| 48 |
public function __construct() { |
| 49 |
if ( isset( $_GET['_wpnonce'] ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_entries_action' ) ) { |
| 50 |
return; |
| 51 |
} |
| 52 |
$this->entry_id = isset( $_GET['entry_id'] ) ? intval( sanitize_text_field( wp_unslash( $_GET['entry_id'] ) ) ) : null; |
| 53 |
$this->entry = $this->entry_id ? Entries::get( $this->entry_id ) : null; |
| 54 |
} |
| 55 |
|
| 56 |
/** |
| 57 |
* Render the single entry page if an entry is found. |
| 58 |
* |
| 59 |
* @since 0.0.13 |
| 60 |
* @return void |
| 61 |
*/ |
| 62 |
public function render() { |
| 63 |
if ( ! $this->entry ) { |
| 64 |
return; |
| 65 |
} |
| 66 |
$entry_status = $this->entry['status']; |
| 67 |
$submitted_on = gmdate( 'Y/m/d \a\t g:i a', strtotime( $this->entry['created_at'] ) ); |
| 68 |
$form_name = ! empty( get_the_title( $this->entry['form_id'] ) ) ? get_the_title( $this->entry['form_id'] ) : 'SureForms Form #' . intval( $this->entry['form_id'] ); |
| 69 |
$meta_data = $this->entry['form_data']; |
| 70 |
$excluded_fields = [ 'srfm-honeypot-field', 'g-recaptcha-response', 'srfm-sender-email-field' ]; |
| 71 |
$entry_logs = $this->entry['logs']; |
| 72 |
?> |
| 73 |
<div class="wrap"> |
| 74 |
<h1 class="wp-heading-inline"><?php esc_html_e( 'View Entry', 'sureforms' ); ?></h1> |
| 75 |
<form method="get" id="get"> <!-- check for nonce, referrer, etc. --> |
| 76 |
<div id="poststuff"> |
| 77 |
<div id="post-body" class="metabox-holder columns-2"> |
| 78 |
<div id="post-body-content"> |
| 79 |
<div id="titlediv"> |
| 80 |
<div id="titlewrap"> |
| 81 |
<label class="screen-reader-text" id="title-prompt-text" for="title"><?php esc_html_e( 'Add title', 'sureforms' ); ?></label> |
| 82 |
<input type="text" name="post_title" size="30" value="Entry #<?php echo esc_attr( $this->entry_id ); ?>" id="title" spellcheck="true" autocomplete="off" readonly> |
| 83 |
</div> |
| 84 |
</div><!-- /titlediv --> |
| 85 |
</div><!-- /post-body-content --> |
| 86 |
<div id="postbox-container-1" class="postbox-container"> |
| 87 |
<?php $this->render_submission_info( $form_name, $entry_status, $submitted_on ); ?> |
| 88 |
</div> |
| 89 |
<div id="postbox-container-2" class="postbox-container"> |
| 90 |
<?php $this->render_form_data( $meta_data, $excluded_fields ); ?> |
| 91 |
</div> |
| 92 |
<div id="postbox-container-3" class="postbox-container"> |
| 93 |
<?php $this->render_entry_logs( $entry_logs ); ?> |
| 94 |
</div> |
| 95 |
</div><!-- /post-body --> |
| 96 |
<br class="clear"> |
| 97 |
</div><!-- /poststuff --> |
| 98 |
</form> |
| 99 |
</div> |
| 100 |
<?php |
| 101 |
} |
| 102 |
|
| 103 |
/** |
| 104 |
* Render the submission information for a specific entry. |
| 105 |
* |
| 106 |
* @param string $form_name The form title/name. |
| 107 |
* @param string $entry_status The entry status (read/unread). |
| 108 |
* @param string $submitted_on The submission date. |
| 109 |
* @since 0.0.13 |
| 110 |
* @return void |
| 111 |
*/ |
| 112 |
private function render_submission_info( $form_name, $entry_status, $submitted_on ) { |
| 113 |
$mark_as_unread_url = add_query_arg( 'action', 'unread' ); |
| 114 |
$user_id = Helper::get_integer_value( $this->entry['user_id'] ); |
| 115 |
$user_info = 0 !== $user_id ? get_userdata( $user_id ) : null; |
| 116 |
$user_name = $user_info ? $user_info->display_name : ''; |
| 117 |
$user_profile_url = $user_info ? get_author_posts_url( $user_id ) : ''; |
| 118 |
?> |
| 119 |
<div id="sureform_form_name_meta" class="postbox "> |
| 120 |
<div class="postbox-header"> |
| 121 |
<!-- Removed "hndle ui-sortable-handle" class from h2 to remove the draggable stylings. --> |
| 122 |
<h2><?php esc_html_e( 'Submission Info', 'sureforms' ); ?></h2> |
| 123 |
</div> |
| 124 |
<div class="inside"> |
| 125 |
<table style="border-collapse: separate; border-spacing: 5px 5px;"> |
| 126 |
<tbody> |
| 127 |
<!-- TODO: Add Type and User info. --> |
| 128 |
<tr style="margin-bottom: 10px;"> |
| 129 |
<td><b><?php esc_html_e( 'Entry:', 'sureforms' ); ?></b></td> |
| 130 |
<td>#<?php echo esc_attr( $this->entry_id ); ?></td> |
| 131 |
</tr> |
| 132 |
<tr style="margin-bottom: 10px;"> |
| 133 |
<td><b><?php esc_html_e( 'Form Name:', 'sureforms' ); ?></b></td> |
| 134 |
<td><a target="_blank" rel="noopener" href="<?php the_permalink( $this->entry['form_id'] ); ?>"><?php echo esc_attr( $form_name ); ?></a></td> |
| 135 |
</tr> |
| 136 |
<?php if ( ! empty( $this->entry['submission_info']['user_ip'] ) ) { ?> |
| 137 |
<tr style="margin-bottom: 10px;"> |
| 138 |
<td><b><?php esc_html_e( 'User IP:', 'sureforms' ); ?></b></td> |
| 139 |
<td><a target="_blank" rel="noopener" href="https://ipinfo.io/"><?php echo esc_attr( $this->entry['submission_info']['user_ip'] ); ?></a></td> |
| 140 |
</tr> |
| 141 |
<?php } ?> |
| 142 |
<tr style="margin-bottom: 10px;"> |
| 143 |
<td><b><?php esc_html_e( 'Browser:', 'sureforms' ); ?></b></td> |
| 144 |
<td><?php echo esc_attr( $this->entry['submission_info']['browser_name'] ); ?></td> |
| 145 |
</tr> |
| 146 |
<tr style="margin-bottom: 10px;"> |
| 147 |
<td><b><?php esc_html_e( 'Device:', 'sureforms' ); ?></b></td> |
| 148 |
<td><?php echo esc_attr( $this->entry['submission_info']['device_name'] ); ?></td> |
| 149 |
</tr> |
| 150 |
<?php if ( 0 !== $user_id ) { ?> |
| 151 |
<tr style="margin-bottom: 10px;"> |
| 152 |
<td><b><?php esc_html_e( 'User:', 'sureforms' ); ?></b></td> |
| 153 |
<td><a target="_blank" rel="noopener" href="<?php echo esc_url( $user_profile_url ); ?>"><?php echo esc_attr( $user_name ); ?></a></td> |
| 154 |
</tr> |
| 155 |
<?php } ?> |
| 156 |
<tr style="margin-bottom: 10px;"> |
| 157 |
<td><b><?php esc_html_e( 'Status:', 'sureforms' ); ?></b></td> |
| 158 |
<td> |
| 159 |
<span style="text-transform: capitalize;"> |
| 160 |
<?php echo esc_attr( $entry_status ); ?> |
| 161 |
</span> |
| 162 |
<?php if ( 'read' === $entry_status ) { ?> |
| 163 |
<span> | <a href="<?php echo esc_url( $mark_as_unread_url ); ?>" id="srfm-entry-mark-unread" style="font-size: 12px;"><?php esc_html_e( 'Mark as Unread', 'sureforms' ); ?></a></span> |
| 164 |
<?php } ?> |
| 165 |
</td> |
| 166 |
</tr> |
| 167 |
<tr style="margin-bottom: 10px;"> |
| 168 |
<td><b><?php esc_html_e( 'Submitted On:', 'sureforms' ); ?></b></td> |
| 169 |
<td><?php echo esc_attr( $submitted_on ); ?></td> |
| 170 |
</tr> |
| 171 |
</tbody> |
| 172 |
</table> |
| 173 |
</div> |
| 174 |
</div> |
| 175 |
<?php |
| 176 |
} |
| 177 |
|
| 178 |
/** |
| 179 |
* Render the form data for a specific entry. |
| 180 |
* |
| 181 |
* @param array<mixed> $meta_data The form meta data. |
| 182 |
* @param array<string> $excluded_fields Fields to exlude from display. |
| 183 |
* @since 0.0.13 |
| 184 |
* @return void |
| 185 |
*/ |
| 186 |
private function render_form_data( $meta_data, $excluded_fields ) { |
| 187 |
?> |
| 188 |
<div id="sureform_entry_meta" class="postbox"> |
| 189 |
<div class="postbox-header"> |
| 190 |
<!-- Removed "hndle ui-sortable-handle" class from h2 to remove the draggable stylings. --> |
| 191 |
<h2><?php esc_html_e( 'Form Data', 'sureforms' ); ?></h2> |
| 192 |
<!-- <div class="handle-actions hide-if-no-js"><button type="button" class="handle-order-higher" aria-disabled="false" aria-describedby="sureform_entry_meta-handle-order-higher-description"><span class="screen-reader-text">Move up</span><span class="order-higher-indicator" aria-hidden="true"></span></button><span class="hidden" id="sureform_entry_meta-handle-order-higher-description">Move Form Data box up</span><button type="button" class="handle-order-lower" aria-disabled="false" aria-describedby="sureform_entry_meta-handle-order-lower-description"><span class="screen-reader-text">Move down</span><span class="order-lower-indicator" aria-hidden="true"></span></button><span class="hidden" id="sureform_entry_meta-handle-order-lower-description">Move Form Data box down</span><button type="button" class="handlediv" aria-expanded="true"><span class="screen-reader-text">Toggle panel: Form Data</span><span class="toggle-indicator" aria-hidden="true"></span></button></div> --> |
| 193 |
</div> |
| 194 |
<div class="inside"> |
| 195 |
<table class="widefat striped"> |
| 196 |
<tbody> |
| 197 |
<tr> |
| 198 |
<th><b><?php esc_html_e( 'Fields', 'sureforms' ); ?></b></th> |
| 199 |
<th><b><?php esc_html_e( 'Values', 'sureforms' ); ?></b></th> |
| 200 |
</tr> |
| 201 |
<?php |
| 202 |
foreach ( $meta_data as $field_name => $value ) { |
| 203 |
if ( in_array( $field_name, $excluded_fields, true ) ) { |
| 204 |
continue; |
| 205 |
} |
| 206 |
if ( false === str_contains( $field_name, '-lbl-' ) ) { |
| 207 |
continue; |
| 208 |
} |
| 209 |
$label = explode( '-lbl-', $field_name )[1]; |
| 210 |
// Getting the encrypted label. we are removing the block slug here. |
| 211 |
$label = explode( '-', $label )[0]; |
| 212 |
?> |
| 213 |
<tr> |
| 214 |
<td><b><?php echo $label ? wp_kses_post( html_entity_decode( Helper::decrypt( $label ) ) ) : ''; ?></b></td> |
| 215 |
<?php |
| 216 |
if ( false !== strpos( $field_name, 'srfm-upload' ) ) { |
| 217 |
?> |
| 218 |
<style> |
| 219 |
.file-cards-container { |
| 220 |
display: flex; |
| 221 |
flex-wrap: wrap; |
| 222 |
gap: 10px; |
| 223 |
} |
| 224 |
.file-card { |
| 225 |
border: 1px solid #ddd; |
| 226 |
border-radius: 4px; |
| 227 |
padding: 10px; |
| 228 |
width: 100px; /* Reduced width */ |
| 229 |
text-align: center; |
| 230 |
background: #f9f9f9; |
| 231 |
font-size: 12px; /* Reduced font size for smaller cards */ |
| 232 |
} |
| 233 |
.file-card-image img { |
| 234 |
max-width: 80px; /* Reduced max width */ |
| 235 |
max-height: 80px; /* Reduced max height */ |
| 236 |
object-fit: cover; |
| 237 |
} |
| 238 |
.file-card-icon { |
| 239 |
font-size: 24px; /* Reduced icon size */ |
| 240 |
margin-bottom: 5px; |
| 241 |
} |
| 242 |
.file-card-details { |
| 243 |
margin-bottom: 5px; |
| 244 |
font-weight: bold; |
| 245 |
} |
| 246 |
.file-card-url a { |
| 247 |
color: #007bff; |
| 248 |
text-decoration: none; |
| 249 |
font-size: 12px; /* Reduced font size */ |
| 250 |
} |
| 251 |
.file-card-url a:hover { |
| 252 |
text-decoration: underline; |
| 253 |
} |
| 254 |
</style> |
| 255 |
<td> |
| 256 |
<div class="file-cards-container"> |
| 257 |
<?php |
| 258 |
$upload_values = $value; |
| 259 |
if ( ! empty( $upload_values ) && is_array( $upload_values ) ) { |
| 260 |
foreach ( $upload_values as $file_url ) { |
| 261 |
$file_url = Helper::get_string_value( $file_url ); |
| 262 |
if ( ! empty( $file_url ) ) { |
| 263 |
$file_type = pathinfo( $file_url, PATHINFO_EXTENSION ); |
| 264 |
$is_image = in_array( $file_type, [ 'gif', 'png', 'bmp', 'jpg', 'jpeg', 'svg' ], true ); |
| 265 |
?> |
| 266 |
<div class="file-card"> |
| 267 |
<?php if ( $is_image ) { ?> |
| 268 |
<div class="file-card-image"> |
| 269 |
<a target="_blank" href="<?php echo esc_attr( urldecode( $file_url ) ); ?>"> |
| 270 |
<img src="<?php echo esc_attr( urldecode( $file_url ) ); ?>" alt="img" /> |
| 271 |
</a> |
| 272 |
</div> |
| 273 |
<?php } else { ?> |
| 274 |
<div class="file-card-icon"> |
| 275 |
<?php // Display a file icon for non-image files. ?> |
| 276 |
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4 16.333V4.667a1.333 1.333 0 011.333-1.333h13.334a1.333 1.333 0 011.333 1.333v11.666a1.333 1.333 0 01-1.333 1.333H5.333A1.333 1.333 0 014 16.333zm8-8h2v6h-2v-6zm-2 8h6v2H10v-2zm-6-6h4v6H4v-6zm0-4h16v2H4V6z"/></svg> |
| 277 |
</div> |
| 278 |
<div class="file-card-details"> |
| 279 |
<span><?php echo esc_html( strtoupper( $file_type ) ); ?></span> |
| 280 |
</div> |
| 281 |
<?php } ?> |
| 282 |
<div class="file-card-url"> |
| 283 |
<a target="_blank" href="<?php echo esc_attr( urldecode( $file_url ) ); ?>"><?php echo esc_html__( 'Open', 'sureforms' ); ?></a> |
| 284 |
</div> |
| 285 |
</div> |
| 286 |
<?php |
| 287 |
} |
| 288 |
} |
| 289 |
} |
| 290 |
?> |
| 291 |
</div> |
| 292 |
</td> |
| 293 |
<?php } elseif ( false !== strpos( $field_name, 'srfm-url' ) ) { ?> |
| 294 |
<td><a target="_blank" href="<?php echo esc_url( $value ); ?>"><?php echo esc_url( $value ); ?></a></td> |
| 295 |
<?php } else { ?> |
| 296 |
<td><?php echo false !== strpos( $value, PHP_EOL ) ? wp_kses_post( wpautop( $value ) ) : wp_kses_post( $value ); ?></td> |
| 297 |
<?php } ?> |
| 298 |
</tr> |
| 299 |
<?php } ?> |
| 300 |
</tbody> |
| 301 |
</table> |
| 302 |
</div> |
| 303 |
</div> |
| 304 |
<?php |
| 305 |
} |
| 306 |
|
| 307 |
/** |
| 308 |
* Render the entry logs for a specific entry. |
| 309 |
* |
| 310 |
* @param array<mixed> $entry_logs Entry logs stored in the database. |
| 311 |
* @since 0.0.13 |
| 312 |
* @return void |
| 313 |
*/ |
| 314 |
private function render_entry_logs( $entry_logs ) { |
| 315 |
?> |
| 316 |
<div id="sureform_entry_meta" class="postbox"> |
| 317 |
<div class="postbox-header"> |
| 318 |
<!-- Removed "hndle ui-sortable-handle" class from h2 to remove the draggable stylings. --> |
| 319 |
<h2><?php esc_html_e( 'Entry Logs', 'sureforms' ); ?></h2> |
| 320 |
<!-- <div class="handle-actions hide-if-no-js"><button type="button" class="handle-order-higher" aria-disabled="false" aria-describedby="sureform_entry_meta-handle-order-higher-description"><span class="screen-reader-text">Move up</span><span class="order-higher-indicator" aria-hidden="true"></span></button><span class="hidden" id="sureform_entry_meta-handle-order-higher-description">Move Form Data box up</span><button type="button" class="handle-order-lower" aria-disabled="false" aria-describedby="sureform_entry_meta-handle-order-lower-description"><span class="screen-reader-text">Move down</span><span class="order-lower-indicator" aria-hidden="true"></span></button><span class="hidden" id="sureform_entry_meta-handle-order-lower-description">Move Form Data box down</span><button type="button" class="handlediv" aria-expanded="true"><span class="screen-reader-text">Toggle panel: Form Data</span><span class="toggle-indicator" aria-hidden="true"></span></button></div> --> |
| 321 |
</div> |
| 322 |
<div class="inside"> |
| 323 |
<table class="widefat striped entry-logs-table"> |
| 324 |
<tbody> |
| 325 |
<?php if ( ! empty( $entry_logs ) ) { ?> |
| 326 |
<?php foreach ( $entry_logs as $log ) { ?> |
| 327 |
<tr> |
| 328 |
<td class="entry-log-container"> |
| 329 |
<div class="entry-log"> |
| 330 |
<h4 class="entry-log-title"> |
| 331 |
<?php echo esc_html( $log['title'] ); ?> |
| 332 |
<?php echo esc_html( gmdate( '\a\t Y-m-d H:i:s', $log['timestamp'] ) ); ?> |
| 333 |
</h4> |
| 334 |
<div class="entry-log-messages"> |
| 335 |
<?php foreach ( $log['messages'] as $message ) { ?> |
| 336 |
<p><?php echo esc_html( $message ); ?></p> |
| 337 |
<?php } ?> |
| 338 |
</div> |
| 339 |
</div> |
| 340 |
</td> |
| 341 |
</tr> |
| 342 |
<?php } ?> |
| 343 |
<?php } else { ?> |
| 344 |
<p><?php esc_html_e( 'No logs found for this entry.', 'sureforms' ); ?></p> |
| 345 |
<?php } ?> |
| 346 |
</tbody> |
| 347 |
</table> |
| 348 |
</div> |
| 349 |
</div> |
| 350 |
<?php |
| 351 |
} |
| 352 |
} |
| 353 |
|