PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / trunk
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar vtrunk
3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 All 156 releases
notificationx / includes / Extensions / NJF / NinjaForms.php

NinjaForms.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar trunk, at includes/Extensions/NJF/NinjaForms.php

426 lines 17.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * CF7 Extension
5 *
6 * @package NotificationX\Extensions
7 */
8
9 namespace NotificationX\Extensions\NJF;
10
11 use NotificationX\Core\Helper;
12 use NotificationX\Core\Rules;
13 use NotificationX\GetInstance;
14 use NotificationX\Extensions\Extension;
15 use NotificationX\Extensions\GlobalFields;
16
17 /**
18 * NinjaForms Extension
19 * @method static NinjaForms get_instance($args = null)
20 */
21 class NinjaForms extends Extension {
22 /**
23 * Instance of NinjaForms
24 *
25 * @var NinjaForms
26 */
27 use GetInstance;
28
29 public $priority = 15;
30 public $id = 'njf';
31 public $img = '';
32 public $doc_link = 'https://notificationx.com/docs/contact-form-submission-alert/';
33 public $types = 'form';
34 public $module = 'modules_njf';
35 public $module_priority = 10;
36 public $class = 'Ninja_Forms';
37
38 /**
39 * Initially Invoked when initialized.
40 */
41 public function __construct() {
42 parent::__construct();
43 }
44
45 public function init_extension()
46 {
47 $this->title = __('Ninja Forms', 'notificationx');
48 $this->module_title = __('Ninja Forms', 'notificationx');
49 }
50
51 public function init() {
52 parent::init();
53
54 add_action('ninja_forms_after_submission', array($this, 'save_new_records'));
55 }
56
57 public function init_fields(){
58 parent::init_fields();
59 add_filter('nx_form_list', [$this, 'nx_form_list'], 9);
60
61 }
62
63 /**
64 * This functions is hooked
65 *
66 * @return void
67 */
68 public function admin_actions() {
69 parent::admin_actions();
70
71 add_filter("nx_can_entry_{$this->id}", array($this, 'can_entry'), 10, 3);
72 }
73
74 /**
75 * This functions is hooked
76 *
77 * @hooked nx_public_action
78 * @return void
79 */
80 public function public_actions() {
81 parent::public_actions();
82
83 }
84
85 public function source_error_message($messages) {
86 if (!$this->class_exists()) {
87 $url = admin_url('plugin-install.php?s=ninja+forms&tab=search&type=term');
88 $messages[$this->id] = [
89 'message' => sprintf( '%s <a href="%s" target="_blank">%s</a> %s',
90 __( 'You have to install', 'notificationx' ),
91 $url,
92 __( 'Ninja Forms', 'notificationx' ),
93 __( 'plugin first.', 'notificationx' )
94 ),
95 'html' => true,
96 'type' => 'error',
97 'rules' => Rules::is('source', $this->id),
98 ];
99 }
100 return $messages;
101 }
102
103 public function nx_form_list($forms) {
104 $_forms = GlobalFields::get_instance()->normalize_fields($this->get_forms(), 'source', $this->id);
105 return array_merge($forms, $_forms);
106 }
107
108 public function get_forms() {
109 $forms = [];
110 if (!class_exists('Ninja_Forms')) {
111 return [];
112 }
113 global $wpdb;
114 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16.
115 $form_result = $wpdb->get_results('SELECT id, title FROM `' . $wpdb->prefix . 'nf3_forms` ORDER BY title');
116 if (!empty($form_result)) {
117 foreach ($form_result as $form) {
118 $key = $this->key($form->id);
119 $forms[$key] = $form->title;
120 }
121 }
122
123 return $forms;
124 }
125
126 public function saved_post($post, $data, $nx_id) {
127 $this->delete_notification(null, $nx_id);
128 $this->get_notification_ready($data);
129 }
130
131 /**
132 * This function responsible for making ready the notifications for the first time
133 * we have made a notification.
134 *
135 * @param string $type
136 * @param array $data
137 * @return void
138 */
139 public function get_notification_ready($data = array()) {
140 $form_list = !empty($data['__form_list']['value']) ? $data['__form_list']['value'] : (!empty($data['form_list']['value']) ? $data['form_list']['value'] : null);
141 if( !empty($form_list) ) {
142 $form_list = explode('_',$form_list);
143 $submissions = $this->get_submissions($form_list[1], $data);
144 if( count( $submissions ) > 0 ) {
145 $entries = [];
146 foreach ( $submissions as $submission ) {
147 if( !empty( $submission ) ) {
148 if (!empty($submission)) {
149 $key = $this->key($form_list[1]);
150 $entries[] = [
151 'nx_id' => $data['nx_id'],
152 'source' => $this->id,
153 'entry_key' => $key,
154 'data' => $submission,
155 ];
156 }
157 }
158 }
159 $this->update_notifications($entries);
160 }
161 }
162 }
163
164 public function get_submissions( $form_id, $data ) {
165 $subs = Ninja_Forms()->form( $form_id )->get_subs( array(), FALSE );
166 $fields = Ninja_Forms()->form( $form_id )->get_fields();
167 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
168 $hidden_field_types = apply_filters( 'nf_sub_hidden_field_types', array() );
169 $display_from = !empty( $data['display_from'] ) ? intval( $data['display_from'] ) : 30;
170 $cutoff_timestamp = strtotime("-{$display_from} days");
171
172 foreach( $subs as $sub ){
173 $timestamp = strtotime( $sub->get_sub_date('Y-m-d H:i') );
174 // Skip submissions older than $display_from days
175 if ($timestamp < $cutoff_timestamp) {
176 continue;
177 }
178 $value[ 'title' ] = $sub->get_form_title();
179 $value[ 'timestamp' ] = $timestamp;
180
181 // boolean - does this submission use a repeater
182 $hasRepeater = false;
183 // How many repeater submissions does this submission have
184 $submissionCount = 0;
185 // Ids of fields in the repeater
186 $fieldsetFieldIds=[];
187
188 foreach ($fields as $field_id => $field) {
189 // Bypass existing method if fieldset repeater
190 if('repeater'===$field->get_setting('type')){
191 $hasRepeater = true;
192
193 $fieldsetSubmission= $sub->get_field_value( $field_id );
194 $fieldsetSettings = $field->get_settings();
195 $fieldsetLabels = Ninja_Forms()->fieldsetRepeater
196 ->getFieldsetLabels($field_id, $fieldsetSettings, true);
197
198 foreach($fieldsetLabels as $fieldsetFieldId =>$fieldsetFieldLabel){
199
200 $fieldsetFieldIds[]=$fieldsetFieldId;
201
202 $field_labels[$fieldsetFieldId]= \WPN_Helper::maybe_escape_csv_column( $fieldsetFieldLabel );
203
204 $fieldType = Ninja_Forms()->fieldsetRepeater->getFieldtype($fieldsetFieldId, $fieldsetSettings);
205
206 $fieldsetFieldSubmissionCollection=Ninja_Forms()->fieldsetRepeater
207 ->extractSubmissionsByFieldsetField($fieldsetFieldId, $fieldsetSubmission);
208
209 $submissionCount = count($fieldsetFieldSubmissionCollection);
210
211 foreach ($fieldsetFieldSubmissionCollection as &$fieldsetFieldSubmission) {
212
213 if(is_array($fieldsetFieldSubmission['value'])){
214
215 $fieldsetFieldSubmission['value']= implode(', ',$fieldsetFieldSubmission['value']);
216 }
217 }
218
219
220 $value[$fieldsetFieldId]= array_column($fieldsetFieldSubmissionCollection,'value');
221 }
222
223 }else{
224 if (!is_int($field_id)) continue;
225 if( in_array( $field->get_setting( 'type' ), $hidden_field_types ) ) continue;
226
227 if ( $field->get_setting( 'admin_label' ) ) {
228 $field_labels[ $field->get_id() ] = \WPN_Helper::maybe_escape_csv_column( $field->get_setting( 'admin_label' ) );
229 } else {
230 $field_labels[ $field->get_id() ] = \WPN_Helper::maybe_escape_csv_column( $field->get_setting( 'label' ) );
231 }
232
233 $field_value = maybe_unserialize( $sub->get_field_value( $field_id ) );
234
235 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
236 $field_value = apply_filters('nf_subs_export_pre_value', $field_value, $field_id);
237 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
238 $field_value = apply_filters('ninja_forms_subs_export_pre_value', $field_value, $field_id, $form_id);
239 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
240 $field_value = apply_filters( 'ninja_forms_subs_export_field_value_' . $field->get_setting( 'type' ), $field_value, $field );
241
242 if ( is_array($field_value ) ) {
243 $field_value = implode( ',', $field_value );
244 }
245
246 $value[ $field_labels[ $field->get_id() ] ] = $field_value;
247
248 }
249 }
250
251 if(!$hasRepeater){
252 $value_array[] = $value;
253 }else{
254 // The the submission has repeater fields, create an indexed array first
255 $repeatingValueArray=[];
256 $index = 0;
257
258 do {
259 // iterate each column in the row 'value'
260 foreach($value as $fieldId=>$columnValue){
261
262 // If the column in the row value is not a repeater
263 // fieldset field, simply copy it into a new row of the
264 // repeating value array
265 if(!in_array($fieldId,$fieldsetFieldIds)){
266 $repeatingValueArray[$index][]=$columnValue;
267 }else{
268
269 // If the column in the row value is a repeater
270 // fieldset field, copy the next submission index value
271
272
273 $repeatingValueArray[$index][]=$columnValue[$index];
274 }
275 }
276 // at the end of the row value columns, increment the index
277 // until all the submission index values are added
278 $index++;
279 } while ($index < $submissionCount);
280
281 // After iterating the row value once for each submission index,
282 // add the repeatingValueArray to the value array
283
284 $value_array[]=$repeatingValueArray;
285 }
286
287 }
288 return $value_array;
289 }
290
291 public function restResponse($args) {
292 if (!class_exists('Ninja_Forms')) {
293 return [];
294 }
295
296 global $wpdb;
297 $table_name = $wpdb->prefix . 'nf3_forms';
298 if (!empty($args['inputValue'])) {
299 $limit = 10;
300 // Prepare the query with a LIKE condition
301 $query = $wpdb->prepare(
302 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16.
303 "SELECT id, title FROM {$table_name} WHERE title LIKE %s LIMIT %d",
304 '%' . $wpdb->esc_like($args['inputValue']) . '%',$limit
305 );
306 // Execute the query and retrieve the results
307 // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16.
308 $form_result = $wpdb->get_results($query);
309 if (!empty($form_result)) {
310 foreach ($form_result as $form) {
311 $key = $this->key($form->id);
312 $forms[$key] = $form->title;
313 }
314 }
315 $result = array_values(GlobalFields::get_instance()->normalize_fields($forms, 'source', $this->id));
316 return $result;
317 }
318
319 if (isset($args['form_id'])) {
320 if( is_array( $args['form_id'] ) ) {
321 $form_id = intval($args['form_id']['value']);
322 }else{
323 $form_id = intval($args['form_id']);
324 }
325 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16.
326 $queryresult = $wpdb->get_results('SELECT meta_value FROM `' . $wpdb->prefix . 'nf3_form_meta` WHERE parent_id = ' . $form_id . ' AND meta_key = "formContentData"');
327
328 if(isset($queryresult[0]) && isset($queryresult[0]->meta_value)){
329 $formdata = $queryresult[0]->meta_value;
330
331 $keys = $this->keys_generator($formdata);
332
333 $returned_keys = array();
334
335 if (is_array($keys) && !empty($keys)) {
336 foreach ($keys as $key) {
337 $returned_keys[] = array(
338 'label' => ucwords(str_replace('_', ' ', str_replace('-', ' ', $key))),
339 'value' => "tag_$key",
340 );
341 }
342
343 return $returned_keys;
344 }
345 }
346 }
347 wp_send_json_error([]);
348 }
349
350 public function keys_generator($fieldsString) {
351 $fields = array();
352 $fieldsdata = unserialize($fieldsString);
353 if (!empty($fieldsdata)) {
354 foreach ($fieldsdata as $field) {
355 if(!is_string($field)){
356 $field = !empty($field['cells'][0]['fields'][0]) ? $field['cells'][0]['fields'][0] : null;
357 }
358 if ($field && Helper::filter_contactform_key_names($field)) {
359 $fields[] = Helper::rename_contactform_key_names($field);
360 }
361 }
362 }
363 return $fields;
364 }
365
366 public function save_new_records($form_data) {
367 foreach ($form_data['fields'] as $field) {
368 $arr = Helper::rename_contactform_key_names($field['key']);
369 $data[$arr] = $field['value'];
370 }
371 $data['title'] = $form_data['settings']['title'];
372 $data['timestamp'] = time();
373
374 if (!empty($data)) {
375 $key = $this->key($form_data['form_id']);
376 $this->save([
377 'source' => $this->id,
378 'entry_key' => $key,
379 'data' => $data,
380 ]);
381 return true;
382 }
383 return false;
384 }
385
386 public function key($key) {
387 $key = $this->id . '_' . $key;
388 return $key;
389 }
390
391 /**
392 * Limit entry by selected form in 'Select a Form';
393 *
394 * @param [type] $return
395 * @param [type] $entry
396 * @param [type] $settings
397 * @return boolean
398 */
399 public function can_entry($return, $entry, $settings){
400 if(!empty($settings['form_list']) && !empty($entry['entry_key'])){
401 $selected_form = $settings['form_list'];
402 $form_id = $entry['entry_key'];
403 if($selected_form != $form_id){
404 return false;
405 }
406
407 }
408 return $return;
409 }
410
411 public function doc() {
412 /* translators: %1$s: Ninja Forms installed & configured link URL, %2$s: documentation link URL, %3$s: Watch video tutorial link URL, %4$s: Integration with Ninja Forms link URL, %5$s: WordPress Contact Forms Submission Rate link URL */
413 return sprintf(__('<p>Make sure that you have <a target="_blank" href="%1$s">Ninja Forms installed & configured</a> to use its campaign & form subscriptions data. For further assistance, check out our step by step <a target="_blank" href="%2$s">documentation</a>.</p>
414 <p>🎦 <a target="_blank" href="%3$s">Watch video tutorial</a> to learn quickly</p>
415 <p>👉 NotificationX <a target="_blank" href="%4$s">Integration with Ninja Forms</a></p>
416 <p><strong>Recommended Blog:</strong></p>
417 <p>🔥 Hacks to Increase Your <a target="_blank" href="%5$s">WordPress Contact Forms Submission Rate</a> Using NotificationX</p>', 'notificationx'),
418 'https://wordpress.org/plugins/ninja-forms/',
419 'https://notificationx.com/docs/ninja-forms/',
420 'https://www.youtube.com/watch?v=Ibv84iGcBHE',
421 'https://notificationx.com/integrations/ninja-forms/',
422 'https://notificationx.com/blog/wordpress-contact-forms/'
423 );
424 }
425 }
426