PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.3.3
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.3.3
3.3.3 3.3.2 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 All 158 releases
← All changes | includes/Extensions/NJF/NinjaForms.php +425 -0 0.2.5.6 → 3.3.3 View file →
@@ -1,0 +1,425 @@
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 +}