PATH:
home
/
nappmpmd
/
bestyment.online
/
wp-content
/
themes
/
wvc-theme
/
includes
/
form-submissions
<?php namespace WVC\FormSubmissions; /** * WVC Form Submissions Helper Functions * * Helper functions for querying and retrieving form submission data * * @package WVC_Theme * @subpackage FormSubmissions * @author 10Web * @since 1.0.0 * @version 1.0.16 */ // Prevent direct access if ( ! defined("ABSPATH")) { exit; } /** * Helper function to get form submissions by form ID */ function wvc_get_form_submissions_by_form_id($form_id, $limit = 10) { $args = array( 'post_type' => 'wvc_form_data', 'post_status' => 'private', 'posts_per_page' => $limit, 'meta_query' => array( array( 'key' => '_wvc_form_id', 'value' => $form_id, 'compare' => '=' ) ), 'orderby' => 'date', 'order' => 'DESC' ); return get_posts($args); } /** * Helper function to get form submissions by section name */ function wvc_get_form_submissions_by_section($section_name, $limit = 10) { $args = array( 'post_type' => 'wvc_form_data', 'post_status' => 'private', 'posts_per_page' => $limit, 'meta_query' => array( array( 'key' => '_wvc_section_name', 'value' => $section_name, 'compare' => '=' ) ), 'orderby' => 'date', 'order' => 'DESC' ); return get_posts($args); } /** * Helper function to get form submissions by specific field value */ function wvc_get_form_submissions_by_field($field_name, $field_value, $limit = 10) { $args = array( 'post_type' => 'wvc_form_data', 'post_status' => 'private', 'posts_per_page' => $limit, 'meta_query' => array( array( 'key' => '_wvc_field_' . sanitize_key($field_name), 'value' => $field_value, 'compare' => '=' ) ), 'orderby' => 'date', 'order' => 'DESC' ); return get_posts($args); } /** * Helper function to search form submissions by multiple criteria */ function wvc_search_form_submissions($criteria = array(), $limit = 10) { $meta_query = array('relation' => 'AND'); // Add form ID filter if provided if (!empty($criteria['form_id'])) { $meta_query[] = array( 'key' => '_wvc_form_id', 'value' => $criteria['form_id'], 'compare' => '=' ); } // Add section filter if provided if (!empty($criteria['section_name'])) { $meta_query[] = array( 'key' => '_wvc_section_name', 'value' => $criteria['section_name'], 'compare' => '=' ); } // Add field-specific filters if (!empty($criteria['fields']) && is_array($criteria['fields'])) { foreach ($criteria['fields'] as $field_name => $field_value) { $meta_query[] = array( 'key' => '_wvc_field_' . sanitize_key($field_name), 'value' => $field_value, 'compare' => 'LIKE' ); } } // Add date range filter if provided if (!empty($criteria['date_from']) || !empty($criteria['date_to'])) { $date_query = array(); if (!empty($criteria['date_from'])) { $date_query['after'] = $criteria['date_from']; } if (!empty($criteria['date_to'])) { $date_query['before'] = $criteria['date_to']; } } $args = array( 'post_type' => 'wvc_form_data', 'post_status' => 'private', 'posts_per_page' => $limit, 'meta_query' => $meta_query, 'orderby' => 'date', 'order' => 'DESC' ); // Add date query if specified if (!empty($date_query)) { $args['date_query'] = array($date_query); } return get_posts($args); } /** * Helper function to get form fields from the first submission of a specific form ID */ function wvc_get_form_fields_by_form_id($form_id) { // Get all submissions for this form ID to extract all field names $submissions = wvc_get_form_submissions_by_form_id($form_id, -1); if (empty($submissions)) { return array(); } $all_fields = array(); // Loop through all submissions to collect all unique field names foreach ($submissions as $submission) { $post_id = $submission->ID; $form_data_json = get_post_meta($post_id, '_wvc_form_data', true); $form_data = $form_data_json ? json_decode($form_data_json, true) : array(); // If JSON data is available, merge the keys if (!empty($form_data)) { $all_fields = array_merge($all_fields, array_keys($form_data)); } else { // Fallback: get from individual field meta $all_meta = get_post_meta($post_id); foreach ($all_meta as $meta_key => $meta_value) { if (strpos($meta_key, '_wvc_field_') === 0) { $field_name = str_replace('_wvc_field_', '', $meta_key); $all_fields[] = $field_name; } } } } // Return unique field names return array_unique($all_fields); } /** * Helper function to get all submissions for a form ID with their field data */ function wvc_get_form_submissions_with_fields($form_id, $limit = -1) { $submissions = wvc_get_form_submissions_by_form_id($form_id, $limit); $submissions_data = array(); foreach ($submissions as $submission) { $submission_data = wvc_get_form_submission_data($submission->ID); $submissions_data[] = $submission_data; } return $submissions_data; } /** * Helper function to get distinct form IDs with submission counts */ function wvc_get_distinct_form_ids_with_counts() { global $wpdb; $query = " SELECT pm.meta_value as form_id, COUNT(*) as submission_count FROM {$wpdb->postmeta} pm INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID WHERE pm.meta_key = '_wvc_form_id' AND p.post_type = 'wvc_form_data' AND p.post_status = 'private' GROUP BY pm.meta_value ORDER BY submission_count DESC, pm.meta_value ASC "; $results = $wpdb->get_results($query); $form_data = array(); foreach ($results as $result) { $form_data[] = array( 'form_id' => $result->form_id, 'submission_count' => intval($result->submission_count) ); } return $form_data; } /** * Helper function to get submission count for a specific form ID */ function wvc_get_form_submission_count($form_id) { $args = array( 'post_type' => 'wvc_form_data', 'post_status' => 'private', 'posts_per_page' => -1, 'meta_query' => array( array( 'key' => '_wvc_form_id', 'value' => $form_id, 'compare' => '=' ) ), 'fields' => 'ids' ); $posts = get_posts($args); return count($posts); } /** * Helper function to get total form submissions count */ function wvc_get_total_submissions_count() { $count = wp_count_posts('wvc_form_data'); return $count->private ?? 0; } /** * Helper function to get form data from a submission post */ function wvc_get_form_submission_data($post_id) { $form_data_json = get_post_meta($post_id, '_wvc_form_data', true); $form_data = $form_data_json ? json_decode($form_data_json, true) : array(); // Get the complete form data structure $form_data_complete = get_post_meta($post_id, '_wvc_form_data_complete', true); // Get submission metadata $submission_metadata = get_post_meta($post_id, '_wvc_submission_metadata', true); // Get individual form fields with case-insensitive lookup support $individual_fields = array(); $individual_fields_lowercase_map = array(); // Map lowercase keys to actual values $all_meta = get_post_meta($post_id); foreach ($all_meta as $meta_key => $meta_value) { if (strpos($meta_key, '_wvc_field_') === 0) { $field_name = str_replace('_wvc_field_', '', $meta_key); $value = $meta_value[0]; $individual_fields[$field_name] = $value; // Also store with lowercase key for case-insensitive lookup $individual_fields_lowercase_map[strtolower($field_name)] = $value; } } // Merge form_data with case-insensitive matching // This ensures fields like 'preferLocation' (schema) match 'preferlocation' (stored) if (!empty($form_data) && is_array($form_data)) { foreach ($form_data as $key => $value) { $lowercase_key = strtolower($key); // If not already in individual_fields, add it with lowercase key mapping if (!isset($individual_fields[$key])) { $individual_fields_lowercase_map[$lowercase_key] = $value; } } } return array( 'post_id' => $post_id, // Post ID for direct access 'form_id' => get_post_meta($post_id, '_wvc_form_id', true), 'section_name' => get_post_meta($post_id, '_wvc_section_name', true), 'timestamp' => get_post_meta($post_id, '_wvc_timestamp', true), 'session_id' => get_post_meta($post_id, '_wvc_session_id', true), 'page_url' => get_post_meta($post_id, '_wvc_page_url', true), 'user_agent' => get_post_meta($post_id, '_wvc_user_agent', true), 'submission_attempt' => get_post_meta($post_id, '_wvc_submission_attempt', true), 'form_version' => get_post_meta($post_id, '_wvc_form_version', true), 'validation_errors' => get_post_meta($post_id, '_wvc_validation_errors', true), 'form_data' => $form_data, // Original JSON format for backward compatibility 'form_data_complete' => $form_data_complete, // Array format 'individual_fields' => $individual_fields, // Individual field values (exact case) 'individual_fields_lowercase_map' => $individual_fields_lowercase_map, // Case-insensitive lookup 'submission_metadata' => $submission_metadata, // Additional metadata 'submission_date' => get_the_date('Y-m-d H:i:s', $post_id) ); } /** * Helper function to get all registered forms with submission counts * * This function retrieves forms from the wvc_form post type (registered via REST API) * and combines them with submission counts from wvc_form_data. * Unlike wvc_get_distinct_form_ids_with_counts(), this shows ALL registered forms, * even those with 0 submissions. * * @return array Array of form data with keys: form_key, form_label, submission_count */ function wvc_get_all_registered_forms_with_counts() { // Get all registered forms from wvc_form post type $registered_forms = get_posts(array( 'post_type' => 'wvc_form', 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'title', 'order' => 'ASC' )); $form_data = array(); foreach ($registered_forms as $form) { $form_key = get_post_meta($form->ID, 'wvc_form_key', true); // Skip if no form_key (shouldn't happen, but safety check) if (empty($form_key)) { continue; } // Get submission count for this form $submission_count = wvc_get_form_submission_count($form_key); // Get form version $form_version = get_post_meta($form->ID, 'wvc_form_version', true); $form_data[] = array( 'form_key' => $form_key, 'form_label' => $form->post_title, 'submission_count' => $submission_count, 'form_id' => $form->ID, // Useful for future operations 'form_version' => !empty($form_version) ? intval($form_version) : null ); } // Sort by submission count (descending), then by form_label usort($form_data, function($a, $b) { if ($a['submission_count'] === $b['submission_count']) { return strcmp($a['form_label'], $b['form_label']); } return $b['submission_count'] - $a['submission_count']; }); return $form_data; } /** * Get submissions for CSV export with date filtering * * @param string $form_id Form key * @param array $filters Date range filters * @return array Submissions data */ function wvc_get_submissions_for_export($form_id, $filters = array()) { $args = array( 'post_type' => 'wvc_form_data', 'post_status' => 'private', 'posts_per_page' => 1000, // Hard limit 'meta_query' => array( array( 'key' => '_wvc_form_id', 'value' => $form_id, 'compare' => '=' ) ), 'orderby' => 'date', 'order' => 'DESC' ); // Add date filtering if (!empty($filters['date_range'])) { $date_query = array(); switch ($filters['date_range']) { case 'today': $date_query['after'] = 'today'; break; case 'last_7': $date_query['after'] = '7 days ago'; break; case 'last_30': $date_query['after'] = '30 days ago'; break; case 'last_90': $date_query['after'] = '90 days ago'; break; case 'custom': if (!empty($filters['date_from'])) { $date_query['after'] = $filters['date_from']; } if (!empty($filters['date_to'])) { $date_query['before'] = $filters['date_to']; $date_query['inclusive'] = true; } break; } if (!empty($date_query)) { $args['date_query'] = array($date_query); } } $posts = get_posts($args); // Get full submission data $submissions = array(); foreach ($posts as $post) { $submissions[] = wvc_get_form_submission_data($post->ID); } return $submissions; } /** * Helper function to get form fields from registered form schema or first submission * * This function first tries to get field definitions from the wvc_form post type * (registered via REST API). If not found, falls back to extracting from submissions. * * @param string $form_key The form key to get fields for * @return array Array of field names */ function wvc_get_form_fields_by_form_key($form_key) { // First, try to get fields from registered form schema $forms = get_posts(array( 'post_type' => 'wvc_form', 'meta_key' => 'wvc_form_key', 'meta_value' => $form_key, 'post_status' => 'publish', 'numberposts' => 1, )); if (!empty($forms)) { $form = $forms[0]; $fields = get_post_meta($form->ID, 'wvc_form_fields', true); // Extract field names from field specifications if (!empty($fields) && is_array($fields)) { $field_names = array(); foreach ($fields as $field) { // Use 'key' field (or 'name' as fallback) for field identifier $field_key = $field['key'] ?? $field['name'] ?? ''; if (!empty($field_key)) { $field_names[] = $field_key; } } if (!empty($field_names)) { return $field_names; } } } // Fallback: extract from submissions (old behavior) return wvc_get_form_fields_by_form_id($form_key); } /** * Get email notification settings for a form * * @param string $form_key The form key * @return array Settings array with 'enabled' and 'emails' keys */ function wvc_get_email_notification_settings($form_key) { // Get the wvc_form post $forms = get_posts(array( 'post_type' => 'wvc_form', 'meta_key' => 'wvc_form_key', 'meta_value' => $form_key, 'post_status' => 'publish', 'numberposts' => 1, )); if (empty($forms)) { return array( 'enabled' => false, 'emails' => array() ); } $form_post = $forms[0]; $settings = get_post_meta($form_post->ID, 'wvc_form_email_settings', true); // Return default settings if not found if (empty($settings) || !is_array($settings)) { return array( 'enabled' => false, 'emails' => array() ); } return array( 'enabled' => isset($settings['enabled']) ? (bool)$settings['enabled'] : false, 'emails' => isset($settings['emails']) && is_array($settings['emails']) ? $settings['emails'] : array() ); } /** * Send email notification for form submission * * @param int $submission_id The submission post ID * @param string $form_key The form key * @param array $recipient_emails Array of email addresses * @return bool True if email sent successfully, false otherwise */ function wvc_send_submission_notification_email($submission_id, $form_key, $recipient_emails) { // Validate inputs if (empty($submission_id) || empty($form_key) || empty($recipient_emails)) { error_log('WVC Email Notification: Missing required parameters'); return false; } // Get submission data $submission_data = wvc_get_form_submission_data($submission_id); if (empty($submission_data)) { error_log("WVC Email Notification: Could not retrieve submission data for ID {$submission_id}"); return false; } // Get form label $forms = get_posts(array( 'post_type' => 'wvc_form', 'meta_key' => 'wvc_form_key', 'meta_value' => $form_key, 'post_status' => 'publish', 'numberposts' => 1, )); $form_label = !empty($forms) ? $forms[0]->post_title : $form_key; // Generate email content $html_content = wvc_generate_submission_email_html($submission_data, $form_label); $text_content = wvc_generate_submission_email_text($submission_data, $form_label); // Prepare email $subject = sprintf('[%s] New Form Submission - %s', get_bloginfo('name'), $form_label ); // Set email headers for HTML $headers = array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>' ); // Send to each recipient $success_count = 0; $fail_count = 0; // Hook to capture PHPMailer errors $phpmailer_error = ''; add_action('wp_mail_failed', function($wp_error) use (&$phpmailer_error) { $phpmailer_error = $wp_error->get_error_message(); error_log("WVC Email PHPMailer Error: " . $phpmailer_error); }); foreach ($recipient_emails as $email) { if (!is_email($email)) { error_log("WVC Email Notification: Invalid email address: {$email}"); $fail_count++; continue; } error_log("--- Sending to: {$email} ---"); $sent = wp_mail($email, $subject, $html_content, $headers); if ($sent) { $success_count++; error_log("WVC Email Notification: wp_mail() returned TRUE for {$email}"); error_log("WVC Email Notification: Successfully queued/sent to {$email} for submission #{$submission_id}"); } else { $fail_count++; error_log("WVC Email Notification: wp_mail() returned FALSE for {$email}"); error_log("WVC Email Notification: Failed to send to {$email} for submission #{$submission_id}"); if (!empty($phpmailer_error)) { error_log("WVC Email Notification: PHPMailer Error: {$phpmailer_error}"); } } } error_log("=== End Email Debug ==="); // Log summary error_log(sprintf( 'WVC Email Notification Summary - Form: %s, Submission: %d, Sent: %d, Failed: %d', $form_key, $submission_id, $success_count, $fail_count )); // Return true if at least one email was sent successfully return $success_count > 0; } /** * Get hook settings for a form * * @param string $form_key The form key * @return array Settings array with 'enabled' and 'hooks' keys */ function wvc_get_hook_settings($form_key) { // Get the wvc_form post $forms = get_posts(array( 'post_type' => 'wvc_form', 'meta_key' => 'wvc_form_key', 'meta_value' => $form_key, 'post_status' => 'publish', 'numberposts' => 1, )); if (empty($forms)) { return array( 'enabled' => false, 'hooks' => array() ); } $form_post = $forms[0]; $settings = get_post_meta($form_post->ID, 'wvc_form_hook_settings', true); // Return default settings if not found if (empty($settings) || !is_array($settings)) { return array( 'enabled' => false, 'hooks' => array() ); } return array( 'enabled' => isset($settings['enabled']) ? (bool)$settings['enabled'] : false, 'hooks' => isset($settings['hooks']) && is_array($settings['hooks']) ? $settings['hooks'] : array() ); } /** * Format submission data as Slack blocks message * * @param array $submission_data Submission data from wvc_get_form_submission_data() * @param string $form_label Form label/title * @return array Array of Slack block objects */ function wvc_format_slack_blocks($submission_data, $form_label) { $blocks = array(); // Header block $blocks[] = array( 'type' => 'header', 'text' => array( 'type' => 'plain_text', 'text' => '🆕 New Form Submission' ) ); // Form info section $blocks[] = array( 'type' => 'section', 'fields' => array( array( 'type' => 'mrkdwn', 'text' => '*Form:*\n' . esc_html($form_label) ), array( 'type' => 'mrkdwn', 'text' => '*Submitted:*\n' . (!empty($submission_data['submission_date']) ? $submission_data['submission_date'] : date('Y-m-d H:i:s')) ) ) ); $blocks[] = array('type' => 'divider'); // Submission data header $blocks[] = array( 'type' => 'section', 'text' => array( 'type' => 'mrkdwn', 'text' => '*Submission Data:*' ) ); // Get field data from form_data_complete or individual_fields $field_data = array(); if (!empty($submission_data['form_data_complete']) && is_array($submission_data['form_data_complete'])) { $field_data = $submission_data['form_data_complete']; } elseif (!empty($submission_data['individual_fields']) && is_array($submission_data['individual_fields'])) { $field_data = $submission_data['individual_fields']; } elseif (!empty($submission_data['form_data']) && is_array($submission_data['form_data'])) { $field_data = $submission_data['form_data']; } // Separate long text fields from short fields $short_fields = array(); $long_fields = array(); foreach ($field_data as $field_name => $field_value) { // Skip empty values if (empty($field_value) && $field_value !== '0') { continue; } // Convert arrays/objects to string if (is_array($field_value) || is_object($field_value)) { $field_value = json_encode($field_value); } $field_value = (string)$field_value; // Make field name more readable $display_name = ucwords(str_replace('_', ' ', $field_name)); // If value is longer than 100 chars, it gets its own section if (strlen($field_value) > 100) { $long_fields[] = array( 'name' => $display_name, 'value' => $field_value ); } else { $short_fields[] = array( 'name' => $display_name, 'value' => $field_value ); } } // Add short fields in 2-column layout (max 10 fields per section) if (!empty($short_fields)) { $field_chunks = array_chunk($short_fields, 10); foreach ($field_chunks as $chunk) { $fields = array(); foreach ($chunk as $field) { $fields[] = array( 'type' => 'mrkdwn', 'text' => '*' . $field['name'] . ':*\n' . esc_html($field['value']) ); } $blocks[] = array( 'type' => 'section', 'fields' => $fields ); } } // Add long fields in their own sections foreach ($long_fields as $field) { $blocks[] = array( 'type' => 'section', 'text' => array( 'type' => 'mrkdwn', 'text' => '*' . $field['name'] . ':*\n```\n' . esc_html($field['value']) . '\n```' ) ); } $blocks[] = array('type' => 'divider'); // Footer context with metadata $context_elements = array(); $context_parts = array(); if (!empty($submission_data['post_id'])) { $context_parts[] = 'Submission ID: #' . $submission_data['post_id']; } // Get IP from submission metadata $ip_address = ''; if (!empty($submission_data['submission_metadata']) && is_array($submission_data['submission_metadata'])) { if (!empty($submission_data['submission_metadata']['ip_address'])) { $ip_address = $submission_data['submission_metadata']['ip_address']; $context_parts[] = 'IP: ' . $ip_address; } } // Get user agent if (!empty($submission_data['user_agent'])) { $user_agent = substr($submission_data['user_agent'], 0, 50); if (strlen($submission_data['user_agent']) > 50) { $user_agent .= '...'; } $context_parts[] = 'User Agent: ' . $user_agent; } if (!empty($context_parts)) { $context_elements[] = array( 'type' => 'mrkdwn', 'text' => implode(' | ', $context_parts) ); $blocks[] = array( 'type' => 'context', 'elements' => $context_elements ); } return $blocks; } /** * Send Slack notification for form submission * * @param int $submission_id The submission post ID * @param string $form_key The form key * @param array $hook_config Hook configuration array * @return bool True if notification sent successfully, false otherwise */ function wvc_send_slack_notification($submission_id, $form_key, $hook_config) { // Validate inputs (allow submission_id to be 0 for test submissions) if (!isset($submission_id) || empty($form_key) || empty($hook_config)) { error_log('WVC Slack Notification: Missing required parameters'); return false; } // Validate webhook URL if (empty($hook_config['webhook_url']) || !filter_var($hook_config['webhook_url'], FILTER_VALIDATE_URL)) { error_log('WVC Slack Notification: Invalid webhook URL'); return false; } // Ensure HTTPS if (strpos($hook_config['webhook_url'], 'https://') !== 0) { error_log('WVC Slack Notification: Webhook URL must use HTTPS'); return false; } // Get submission data (or create test data if submission_id is 0) if ($submission_id === 0) { // Create test submission data $submission_data = array( 'post_id' => 0, 'form_id' => $form_key, 'individual_fields' => array( 'test_field_1' => 'This is a test submission', 'test_field_2' => 'Testing webhook notification functionality', 'test_field_3' => 'Sample data for testing purposes', ), 'submission_metadata' => array( 'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown', 'submission_source' => 'admin_test', ), 'user_agent' => 'WordPress Admin Test', 'submission_date' => date('Y-m-d H:i:s'), ); } else { // Get real submission data $submission_data = wvc_get_form_submission_data($submission_id); if (empty($submission_data)) { error_log("WVC Slack Notification: Could not retrieve submission data for ID {$submission_id}"); return false; } } // Get form label $forms = get_posts(array( 'post_type' => 'wvc_form', 'meta_key' => 'wvc_form_key', 'meta_value' => $form_key, 'post_status' => 'publish', 'numberposts' => 1, )); $form_label = !empty($forms) ? $forms[0]->post_title : $form_key; // Format as Slack blocks $blocks = wvc_format_slack_blocks($submission_data, $form_label); // Build Slack payload $payload = array( 'text' => 'New Form Submission: ' . $form_label, 'blocks' => $blocks ); // Add channel override if specified if (!empty($hook_config['channel'])) { $payload['channel'] = $hook_config['channel']; } // Send to Slack webhook $response = wp_remote_post($hook_config['webhook_url'], array( 'body' => json_encode($payload), 'headers' => array( 'Content-Type' => 'application/json' ), 'timeout' => 5, 'sslverify' => true )); // Check for errors if (is_wp_error($response)) { error_log(sprintf( 'WVC Slack Notification: HTTP error for submission #%d - %s', $submission_id, $response->get_error_message() )); return false; } $response_code = wp_remote_retrieve_response_code($response); $response_body = wp_remote_retrieve_body($response); if ($response_code !== 200) { error_log(sprintf( 'WVC Slack Notification: Failed for submission #%d - HTTP %d: %s', $submission_id, $response_code, $response_body )); return false; } // Success error_log(sprintf( 'WVC Slack Notification: Successfully sent for submission #%d (hook: %s)', $submission_id, $hook_config['name'] ?? 'Unnamed' )); return true; } /** * Get 10Web dashboard logs URL * * @return string|null The logs URL or null if not available */ function wvc_get_tenweb_logs_url() { // Check if TENWEB_DASHBOARD constant is defined if (!defined('TENWEB_DASHBOARD')) { return null; } // Get domain ID $domain_id = get_site_option('tenweb_domain_id'); if (empty($domain_id)) { return null; } // Build logs URL return TENWEB_DASHBOARD . '/websites/' . $domain_id . '/hosting/logs'; }
[+]
..
[+]
admin
[-] email-template.php
[edit]
[-] index.php
[edit]
[-] form-schema-post-type.php
[edit]
[-] post-type.php
[edit]
[-] form-handler.php
[edit]
[-] helpers.php
[edit]