Passed
Push — master ( 414b02...c77662 )
by Brian
04:42
created

getpaid_print_embed_styles()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 8
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * Template functions.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Displays an invoice.
11
 * 
12
 * @param WPInv_Invoice $invoice.
13
 */
14
function getpaid_invoice( $invoice ) {
15
    if ( ! empty( $invoice ) ) {
16
        wpinv_get_template( 'invoice/invoice.php', compact( 'invoice' ) );
17
    }
18
}
19
add_action( 'getpaid_invoice', 'getpaid_invoice', 10 );
20
21
/**
22
 * Displays the invoice footer.
23
 */
24
function getpaid_invoice_footer( $invoice ) {
25
    if ( ! empty( $invoice ) ) {
26
        wpinv_get_template( 'invoice/footer.php', compact( 'invoice' ) );
27
    }
28
}
29
add_action( 'getpaid_invoice_footer', 'getpaid_invoice_footer', 10 );
30
31
/**
32
 * Displays the invoice top bar.
33
 */
34
function getpaid_invoice_header( $invoice ) {
35
    if ( ! empty( $invoice ) ) {
36
        wpinv_get_template( 'invoice/header.php', compact( 'invoice' ) );
37
    }
38
}
39
add_action( 'getpaid_invoice_header', 'getpaid_invoice_header', 10 );
40
41
/**
42
 * Displays actions on the left side of the header.
43
 */
44
function getpaid_invoice_header_left_actions( $invoice ) {
45
    if ( ! empty( $invoice ) ) {
46
        wpinv_get_template( 'invoice/header-left-actions.php', compact( 'invoice' ) );
47
    }
48
}
49
add_action( 'getpaid_invoice_header_left', 'getpaid_invoice_header_left_actions', 10 );
50
51
/**
52
 * Displays actions on the right side of the invoice top bar.
53
 */
54
function getpaid_invoice_header_right_actions( $invoice ) {
55
    if ( ! empty( $invoice ) ) {
56
        wpinv_get_template( 'invoice/header-right-actions.php', compact( 'invoice' ) );
57
    }
58
}
59
add_action( 'getpaid_invoice_header_right', 'getpaid_invoice_header_right_actions', 10 );
60
61
/**
62
 * Displays the invoice title, logo etc.
63
 */
64
function getpaid_invoice_details_top( $invoice ) {
65
    if ( ! empty( $invoice ) ) {
66
        wpinv_get_template( 'invoice/details-top.php', compact( 'invoice' ) );
67
    }
68
}
69
add_action( 'getpaid_invoice_details', 'getpaid_invoice_details_top', 10 );
70
71
/**
72
 * Displays the company logo.
73
 */
74
function getpaid_invoice_logo( $invoice ) {
75
    if ( ! empty( $invoice ) ) {
76
        wpinv_get_template( 'invoice/invoice-logo.php', compact( 'invoice' ) );
77
    }
78
}
79
add_action( 'getpaid_invoice_details_top_left', 'getpaid_invoice_logo' );
80
81
/**
82
 * Displays the type of invoice.
83
 */
84
function getpaid_invoice_type( $invoice ) {
85
    if ( ! empty( $invoice ) ) {
86
        wpinv_get_template( 'invoice/invoice-type.php', compact( 'invoice' ) );
87
    }
88
}
89
add_action( 'getpaid_invoice_details_top_right', 'getpaid_invoice_type' );
90
91
/**
92
 * Displays the invoice details.
93
 */
94
function getpaid_invoice_details_main( $invoice ) {
95
    if ( ! empty( $invoice ) ) {
96
        wpinv_get_template( 'invoice/details.php', compact( 'invoice' ) );
97
    }
98
}
99
add_action( 'getpaid_invoice_details', 'getpaid_invoice_details_main', 50 );
100
101
/**
102
 * Returns a path to the templates directory.
103
 * 
104
 * @return string
105
 */
106
function wpinv_get_templates_dir() {
107
    return getpaid_template()->templates_dir;
108
}
109
110
/**
111
 * Returns a url to the templates directory.
112
 * 
113
 * @return string
114
 */
115
function wpinv_get_templates_url() {
116
    return getpaid_template()->templates_url;
117
}
118
119
/**
120
 * Displays a template.
121
 * 
122
 * First checks if there is a template overide, if not it loads the default template.
123
 * 
124
 * @param string $template_name e.g payment-forms/cart.php The template to locate.
125
 * @param string $template_path The templates directory relative to the theme's root dir. Defaults to 'invoicing'.
126
 * @param string $default_path The root path to the default template. Defaults to invoicing/templates
127
 */
128
function wpinv_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
129
    getpaid_template()->display_template( $template_name, $args, $template_path, $default_path );
130
}
131
132
/**
133
 * Retrieves a given template's html code.
134
 * 
135
 * First checks if there is a template overide, if not it loads the default template.
136
 * 
137
 * @param string $template_name e.g payment-forms/cart.php The template to locate.
138
 * @param array $args An array of args to pass to the template.
139
 * @param string $template_path The templates directory relative to the theme's root dir. Defaults to 'invoicing'.
140
 * @param string $default_path The root path to the default template. Defaults to invoicing/templates
141
 */
142
function wpinv_get_template_html( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
143
	return getpaid_template()->get_template( $template_name, $args, $template_path, $default_path );
144
}
145
146
/**
147
 * Returns the default path from where to look for template overides.
148
 * 
149
 * @return string
150
 */
151
function wpinv_template_path() {
152
    return apply_filters( 'wpinv_template_path', wpinv_get_theme_template_dir_name() );
153
}
154
155
/**
156
 * Returns the directory containing the template overides.
157
 * 
158
 * @return string
159
 */
160
function wpinv_get_theme_template_dir_name() {
161
	return trailingslashit( apply_filters( 'wpinv_templates_dir', 'invoicing' ) );
162
}
163
164
/**
165
 * Locates a template path.
166
 * 
167
 * First checks if there is a template overide, if not it loads the default template.
168
 * 
169
 * @param string $template_name e.g payment-forms/cart.php The template to locate.
170
 * @param string $template_path The template path relative to the theme's root dir. Defaults to 'invoicing'.
171
 * @param string $default_path The root path to the default template. Defaults to invoicing/templates
172
 */
173
function wpinv_locate_template( $template_name, $template_path = '', $default_path = '' ) {
174
    return getpaid_template()->locate_template( $template_name, $template_path, $default_path );
175
}
176
177
function wpinv_get_template_part( $slug, $name = null, $load = true ) {
178
	do_action( 'get_template_part_' . $slug, $slug, $name );
179
180
	// Setup possible parts
181
	$templates = array();
182
	if ( isset( $name ) )
183
		$templates[] = $slug . '-' . $name . '.php';
184
	$templates[] = $slug . '.php';
185
186
	// Allow template parts to be filtered
187
	$templates = apply_filters( 'wpinv_get_template_part', $templates, $slug, $name );
188
189
	// Return the part that is found
190
	return wpinv_locate_tmpl( $templates, $load, false );
191
}
192
193
function wpinv_locate_tmpl( $template_names, $load = false, $require_once = true ) {
194
	// No file found yet
195
	$located = false;
196
197
	// Try to find a template file
198
	foreach ( (array)$template_names as $template_name ) {
199
200
		// Continue if template is empty
201
		if ( empty( $template_name ) )
202
			continue;
203
204
		// Trim off any slashes from the template name
205
		$template_name = ltrim( $template_name, '/' );
206
207
		// try locating this template file by looping through the template paths
208
		foreach( wpinv_get_theme_template_paths() as $template_path ) {
209
210
			if( file_exists( $template_path . $template_name ) ) {
211
				$located = $template_path . $template_name;
212
				break;
213
			}
214
		}
215
216
		if( !empty( $located ) ) {
217
			break;
218
		}
219
	}
220
221
	if ( ( true == $load ) && ! empty( $located ) )
222
		load_template( $located, $require_once );
223
224
	return $located;
225
}
226
227
function wpinv_get_theme_template_paths() {
228
	$template_dir = wpinv_get_theme_template_dir_name();
229
230
	$file_paths = array(
231
		1 => trailingslashit( get_stylesheet_directory() ) . $template_dir,
232
		10 => trailingslashit( get_template_directory() ) . $template_dir,
233
		100 => wpinv_get_templates_dir()
234
	);
235
236
	$file_paths = apply_filters( 'wpinv_template_paths', $file_paths );
237
238
	// sort the file paths based on priority
239
	ksort( $file_paths, SORT_NUMERIC );
240
241
	return array_map( 'trailingslashit', $file_paths );
242
}
243
244
function wpinv_checkout_meta_tags() {
245
246
	$pages   = array();
247
	$pages[] = wpinv_get_option( 'success_page' );
248
	$pages[] = wpinv_get_option( 'failure_page' );
249
	$pages[] = wpinv_get_option( 'invoice_history_page' );
250
	$pages[] = wpinv_get_option( 'invoice_subscription_page' );
251
252
	if( !wpinv_is_checkout() && !is_page( $pages ) ) {
253
		return;
254
	}
255
256
	echo '<meta name="robots" content="noindex,nofollow" />' . "\n";
257
}
258
add_action( 'wp_head', 'wpinv_checkout_meta_tags' );
259
260
function wpinv_add_body_classes( $class ) {
261
	$classes = (array)$class;
262
263
	if( wpinv_is_checkout() ) {
264
		$classes[] = 'wpinv-checkout';
265
		$classes[] = 'wpinv-page';
266
	}
267
268
	if( wpinv_is_success_page() ) {
269
		$classes[] = 'wpinv-success';
270
		$classes[] = 'wpinv-page';
271
	}
272
273
	if( wpinv_is_failed_transaction_page() ) {
274
		$classes[] = 'wpinv-failed-transaction';
275
		$classes[] = 'wpinv-page';
276
	}
277
278
	if( wpinv_is_invoice_history_page() ) {
279
		$classes[] = 'wpinv-history';
280
		$classes[] = 'wpinv-page';
281
	}
282
283
	if( wpinv_is_subscriptions_history_page() ) {
284
		$classes[] = 'wpinv-subscription';
285
		$classes[] = 'wpinv-page';
286
	}
287
288
	if( wpinv_is_test_mode() ) {
289
		$classes[] = 'wpinv-test-mode';
290
		$classes[] = 'wpinv-page';
291
	}
292
293
	return array_unique( $classes );
294
}
295
add_filter( 'body_class', 'wpinv_add_body_classes' );
296
297
function wpinv_html_year_dropdown( $name = 'year', $selected = 0, $years_before = 5, $years_after = 0 ) {
298
    $current     = date( 'Y' );
299
    $start_year  = $current - absint( $years_before );
300
    $end_year    = $current + absint( $years_after );
301
    $selected    = empty( $selected ) ? date( 'Y' ) : $selected;
302
    $options     = array();
303
304
    while ( $start_year <= $end_year ) {
305
        $options[ absint( $start_year ) ] = $start_year;
306
        $start_year++;
307
    }
308
309
    $output = wpinv_html_select( array(
310
        'name'             => $name,
311
        'selected'         => $selected,
312
        'options'          => $options,
313
        'show_option_all'  => false,
314
        'show_option_none' => false
315
    ) );
316
317
    return $output;
318
}
319
320
function wpinv_html_month_dropdown( $name = 'month', $selected = 0 ) {
321
322
    $options = array(
323
        '1'  => __( 'January', 'invoicing' ),
324
        '2'  => __( 'February', 'invoicing' ),
325
        '3'  => __( 'March', 'invoicing' ),
326
        '4'  => __( 'April', 'invoicing' ),
327
        '5'  => __( 'May', 'invoicing' ),
328
        '6'  => __( 'June', 'invoicing' ),
329
        '7'  => __( 'July', 'invoicing' ),
330
        '8'  => __( 'August', 'invoicing' ),
331
        '9'  => __( 'September', 'invoicing' ),
332
        '10' => __( 'October', 'invoicing' ),
333
        '11' => __( 'November', 'invoicing' ),
334
        '12' => __( 'December', 'invoicing' ),
335
    );
336
337
    // If no month is selected, default to the current month
338
    $selected = empty( $selected ) ? date( 'n' ) : $selected;
339
340
    $output = wpinv_html_select( array(
341
        'name'             => $name,
342
        'selected'         => $selected,
343
        'options'          => $options,
344
        'show_option_all'  => false,
345
        'show_option_none' => false
346
    ) );
347
348
    return $output;
349
}
350
351
function wpinv_html_select( $args = array() ) {
352
    $defaults = array(
353
        'options'          => array(),
354
        'name'             => null,
355
        'class'            => '',
356
        'id'               => '',
357
        'selected'         => 0,
358
        'placeholder'      => null,
359
        'multiple'         => false,
360
        'show_option_all'  => _x( 'All', 'all dropdown items', 'invoicing' ),
361
        'show_option_none' => _x( 'None', 'no dropdown items', 'invoicing' ),
362
        'data'             => array(),
363
        'onchange'         => null,
364
        'required'         => false,
365
        'disabled'         => false,
366
        'readonly'         => false,
367
    );
368
369
    $args = wp_parse_args( $args, $defaults );
0 ignored issues
show
Security Variable Injection introduced by
$args can contain request data and is used in variable name context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read from $_GET, and $_GET['vat_class'] is assigned to $vat_class in includes/admin/class-getpaid-post-types-admin.php on line 648
  1. Read from $_GET, and $_GET['vat_class'] is assigned to $vat_class
    in includes/admin/class-getpaid-post-types-admin.php on line 648
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 652
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 351
  2. Path: Read from $_GET, and $_GET['vat_rule'] is assigned to $vat_rule in includes/admin/class-getpaid-post-types-admin.php on line 622
  1. Read from $_GET, and $_GET['vat_rule'] is assigned to $vat_rule
    in includes/admin/class-getpaid-post-types-admin.php on line 622
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 627
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 351
  3. Path: Read from $_GET, and $_GET['type'] is assigned to $type in includes/admin/class-getpaid-post-types-admin.php on line 672
  1. Read from $_GET, and $_GET['type'] is assigned to $type
    in includes/admin/class-getpaid-post-types-admin.php on line 672
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 676
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 351

Used in variable context

  1. wp_parse_args() is called
    in includes/wpinv-template-functions.php on line 423
  2. Enters via parameter $args
    in wordpress/wp-includes/functions.php on line 4413
  3. wp_parse_str() is called
    in wordpress/wp-includes/functions.php on line 4419
  4. Enters via parameter $string
    in wordpress/wp-includes/formatting.php on line 4938
  5. parse_str() is called
    in wordpress/wp-includes/formatting.php on line 4939

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
370
371
    $data_elements = '';
372
    foreach ( $args['data'] as $key => $value ) {
373
        $data_elements .= ' data-' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
374
    }
375
376
    if( $args['multiple'] ) {
377
        $multiple = ' MULTIPLE';
378
    } else {
379
        $multiple = '';
380
    }
381
382
    if( $args['placeholder'] ) {
383
        $placeholder = $args['placeholder'];
384
    } else {
385
        $placeholder = '';
386
    }
387
    
388
    $options = '';
389
    if( !empty( $args['onchange'] ) ) {
390
        $options .= ' onchange="' . esc_attr( $args['onchange'] ) . '"';
391
    }
392
    
393
    if( !empty( $args['required'] ) ) {
394
        $options .= ' required="required"';
395
    }
396
    
397
    if( !empty( $args['disabled'] ) ) {
398
        $options .= ' disabled';
399
    }
400
    
401
    if( !empty( $args['readonly'] ) ) {
402
        $options .= ' readonly';
403
    }
404
405
    $class  = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
406
    $output = '<select name="' . esc_attr( $args['name'] ) . '" id="' . esc_attr( $args['id'] ) . '" class="wpinv-select ' . $class . '"' . $multiple . ' data-placeholder="' . $placeholder . '" ' . trim( $options ) . $data_elements . '>';
407
408
    if ( $args['show_option_all'] ) {
409
        if( $args['multiple'] ) {
410
            $selected = selected( true, in_array( 0, $args['selected'] ), false );
411
        } else {
412
            $selected = selected( $args['selected'], 0, false );
413
        }
414
        $output .= '<option value="all"' . $selected . '>' . esc_html( $args['show_option_all'] ) . '</option>';
415
    }
416
417
    if ( !empty( $args['options'] ) ) {
418
419
        if ( $args['show_option_none'] ) {
420
            if( $args['multiple'] ) {
421
                $selected = selected( true, in_array( "", $args['selected'] ), false );
422
            } else {
423
                $selected = selected( $args['selected'] === "", true, false );
424
            }
425
            $output .= '<option value=""' . $selected . '>' . esc_html( $args['show_option_none'] ) . '</option>';
426
        }
427
428
        foreach( $args['options'] as $key => $option ) {
429
430
            if( $args['multiple'] && is_array( $args['selected'] ) ) {
431
                $selected = selected( true, (bool)in_array( $key, $args['selected'] ), false );
432
            } else {
433
                $selected = selected( $args['selected'], $key, false );
434
            }
435
436
            $output .= '<option value="' . esc_attr( $key ) . '"' . $selected . '>' . esc_html( $option ) . '</option>';
437
        }
438
    }
439
440
    $output .= '</select>';
441
442
    return $output;
443
}
444
445
function wpinv_item_dropdown( $args = array() ) {
446
    $defaults = array(
447
        'name'              => 'wpi_item',
448
        'id'                => 'wpi_item',
449
        'class'             => '',
450
        'multiple'          => false,
451
        'selected'          => 0,
452
        'number'            => -1,
453
        'placeholder'       => __( 'Choose a item', 'invoicing' ),
454
        'data'              => array( 'search-type' => 'item' ),
455
        'show_option_all'   => false,
456
        'show_option_none'  => false,
457
        'show_recurring'    => false,
458
    );
459
460
    $args = wp_parse_args( $args, $defaults );
461
462
    $item_args = array(
463
        'post_type'      => 'wpi_item',
464
        'orderby'        => 'title',
465
        'order'          => 'ASC',
466
        'posts_per_page' => $args['number']
467
    );
468
469
    $item_args  = apply_filters( 'wpinv_item_dropdown_query_args', $item_args, $args, $defaults );
470
471
    $items      = get_posts( $item_args );
472
    $options    = array();
473
    if ( $items ) {
474
        foreach ( $items as $item ) {
475
            $title = esc_html( $item->post_title );
476
            
477
            if ( !empty( $args['show_recurring'] ) ) {
478
                $title .= wpinv_get_item_suffix( $item->ID, false );
479
            }
480
            
481
            $options[ absint( $item->ID ) ] = $title;
482
        }
483
    }
484
485
    // This ensures that any selected items are included in the drop down
486
    if( is_array( $args['selected'] ) ) {
487
        foreach( $args['selected'] as $item ) {
488
            if( ! in_array( $item, $options ) ) {
489
                $title = get_the_title( $item );
490
                if ( !empty( $args['show_recurring'] ) ) {
491
                    $title .= wpinv_get_item_suffix( $item, false );
492
                }
493
                $options[$item] = $title;
494
            }
495
        }
496
    } elseif ( is_numeric( $args['selected'] ) && $args['selected'] !== 0 ) {
497
        if ( ! in_array( $args['selected'], $options ) ) {
498
            $title = get_the_title( $args['selected'] );
499
            if ( !empty( $args['show_recurring'] ) ) {
500
                $title .= wpinv_get_item_suffix( $args['selected'], false );
501
            }
502
            $options[$args['selected']] = get_the_title( $args['selected'] );
503
        }
504
    }
505
506
    $output = wpinv_html_select( array(
507
        'name'             => $args['name'],
508
        'selected'         => $args['selected'],
509
        'id'               => $args['id'],
510
        'class'            => $args['class'],
511
        'options'          => $options,
512
        'multiple'         => $args['multiple'],
513
        'placeholder'      => $args['placeholder'],
514
        'show_option_all'  => $args['show_option_all'],
515
        'show_option_none' => $args['show_option_none'],
516
        'data'             => $args['data'],
517
    ) );
518
519
    return $output;
520
}
521
522
/**
523
 * Returns an array of published items.
524
 */
525
function wpinv_get_published_items_for_dropdown() {
526
527
    $items = get_posts(
528
        array(
529
            'post_type'      => 'wpi_item',
530
            'orderby'        => 'title',
531
            'order'          => 'ASC',
532
            'posts_per_page' => '-1'
533
        )
534
    );
535
536
    $options = array();
537
    if ( $items ) {
538
        foreach ( $items as $item ) {
539
            $options[ $item->ID ] = esc_html( $item->post_title ) . wpinv_get_item_suffix( $item->ID, false );
540
        }
541
    }
542
543
    return $options;
544
}
545
546
function wpinv_html_checkbox( $args = array() ) {
547
    $defaults = array(
548
        'name'     => null,
549
        'current'  => null,
550
        'class'    => 'wpinv-checkbox',
551
        'options'  => array(
552
            'disabled' => false,
553
            'readonly' => false
554
        )
555
    );
556
557
    $args = wp_parse_args( $args, $defaults );
558
559
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
560
    $options = '';
561
    if ( ! empty( $args['options']['disabled'] ) ) {
562
        $options .= ' disabled="disabled"';
563
    } elseif ( ! empty( $args['options']['readonly'] ) ) {
564
        $options .= ' readonly';
565
    }
566
567
    $output = '<input type="checkbox"' . $options . ' name="' . esc_attr( $args['name'] ) . '" id="' . esc_attr( $args['name'] ) . '" class="' . $class . ' ' . esc_attr( $args['name'] ) . '" ' . checked( 1, $args['current'], false ) . ' />';
568
569
    return $output;
570
}
571
572
/**
573
 * Displays a hidden field.
574
 */
575
function getpaid_hidden_field( $name, $value ) {
576
    $name  = sanitize_text_field( $name );
577
    $value = esc_attr( $value );
578
579
    echo "<input type='hidden' name='$name' value='$value' />";
580
}
581
582
/**
583
 * Displays a submit field.
584
 */
585
function getpaid_submit_field( $value, $name = 'submit', $class = 'btn-primary' ) {
586
    $name  = sanitize_text_field( $name );
587
    $value = esc_attr( $value );
588
    $class = esc_attr( $class );
589
590
    echo "<input type='submit' name='$name' value='$value' class='btn $class' />";
591
}
592
593
function wpinv_html_text( $args = array() ) {
594
    // Backwards compatibility
595
    if ( func_num_args() > 1 ) {
596
        $args = func_get_args();
597
598
        $name  = $args[0];
599
        $value = isset( $args[1] ) ? $args[1] : '';
600
        $label = isset( $args[2] ) ? $args[2] : '';
601
        $desc  = isset( $args[3] ) ? $args[3] : '';
602
    }
603
604
    $defaults = array(
605
        'id'           => '',
606
        'name'         => isset( $name )  ? $name  : 'text',
607
        'value'        => isset( $value ) ? $value : null,
608
        'label'        => isset( $label ) ? $label : null,
609
        'desc'         => isset( $desc )  ? $desc  : null,
610
        'placeholder'  => '',
611
        'class'        => 'regular-text',
612
        'disabled'     => false,
613
        'readonly'     => false,
614
        'required'     => false,
615
        'autocomplete' => '',
616
        'data'         => false
617
    );
618
619
    $args = wp_parse_args( $args, $defaults );
620
621
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
622
    $options = '';
623
    if( $args['required'] ) {
624
        $options .= ' required="required"';
625
    }
626
    if( $args['readonly'] ) {
627
        $options .= ' readonly';
628
    }
629
    if( $args['readonly'] ) {
630
        $options .= ' readonly';
631
    }
632
633
    $data = '';
634
    if ( !empty( $args['data'] ) ) {
635
        foreach ( $args['data'] as $key => $value ) {
636
            $data .= 'data-' . wpinv_sanitize_key( $key ) . '="' . esc_attr( $value ) . '" ';
637
        }
638
    }
639
640
    $output = '<span id="wpinv-' . wpinv_sanitize_key( $args['name'] ) . '-wrap">';
641
    $output .= '<label class="wpinv-label" for="' . wpinv_sanitize_key( $args['id'] ) . '">' . esc_html( $args['label'] ) . '</label>';
642
    if ( ! empty( $args['desc'] ) ) {
643
        $output .= '<span class="wpinv-description">' . esc_html( $args['desc'] ) . '</span>';
644
    }
645
646
    $output .= '<input type="text" name="' . esc_attr( $args['name'] ) . '" id="' . esc_attr( $args['id'] )  . '" autocomplete="' . esc_attr( $args['autocomplete'] )  . '" value="' . esc_attr( $args['value'] ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" class="' . $class . '" ' . $data . ' ' . trim( $options ) . '/>';
647
648
    $output .= '</span>';
649
650
    return $output;
651
}
652
653
function wpinv_html_textarea( $args = array() ) {
654
    $defaults = array(
655
        'name'        => 'textarea',
656
        'value'       => null,
657
        'label'       => null,
658
        'desc'        => null,
659
        'class'       => 'large-text',
660
        'disabled'    => false,
661
        'placeholder' => '',
662
    );
663
664
    $args = wp_parse_args( $args, $defaults );
665
666
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
667
    $disabled = '';
668
    if( $args['disabled'] ) {
669
        $disabled = ' disabled="disabled"';
670
    }
671
672
    $output = '<span id="wpinv-' . wpinv_sanitize_key( $args['name'] ) . '-wrap">';
673
    $output .= '<label class="wpinv-label" for="' . wpinv_sanitize_key( $args['name'] ) . '">' . esc_html( $args['label'] ) . '</label>';
674
    $output .= '<textarea name="' . esc_attr( $args['name'] ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" id="' . wpinv_sanitize_key( $args['name'] ) . '" class="' . $class . '"' . $disabled . '>' . esc_attr( $args['value'] ) . '</textarea>';
675
676
    if ( ! empty( $args['desc'] ) ) {
677
        $output .= '<span class="wpinv-description">' . esc_html( $args['desc'] ) . '</span>';
678
    }
679
    $output .= '</span>';
680
681
    return $output;
682
}
683
684
function wpinv_html_ajax_user_search( $args = array() ) {
685
    $defaults = array(
686
        'name'        => 'user_id',
687
        'value'       => null,
688
        'placeholder' => __( 'Enter username', 'invoicing' ),
689
        'label'       => null,
690
        'desc'        => null,
691
        'class'       => '',
692
        'disabled'    => false,
693
        'autocomplete'=> 'off',
694
        'data'        => false
695
    );
696
697
    $args = wp_parse_args( $args, $defaults );
698
699
    $args['class'] = 'wpinv-ajax-user-search ' . $args['class'];
700
701
    $output  = '<span class="wpinv_user_search_wrap">';
702
        $output .= wpinv_html_text( $args );
703
        $output .= '<span class="wpinv_user_search_results hidden"><a class="wpinv-ajax-user-cancel" title="' . __( 'Cancel', 'invoicing' ) . '" aria-label="' . __( 'Cancel', 'invoicing' ) . '" href="#">x</a><span></span></span>';
704
    $output .= '</span>';
705
706
    return $output;
707
}
708
709
/**
710
 * Use our template to display invoices.
711
 * 
712
 * @param string $template the template that is currently being used.
713
 */
714
function wpinv_template( $template ) {
715
    global $post;
716
717
    if ( ! is_admin() && ( is_single() || is_404() ) && ! empty( $post->ID ) && getpaid_is_invoice_post_type( get_post_type( $post->ID ) ) ) {
0 ignored issues
show
Bug introduced by
It seems like get_post_type($post->ID) can also be of type false; however, parameter $post_type of getpaid_is_invoice_post_type() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

717
    if ( ! is_admin() && ( is_single() || is_404() ) && ! empty( $post->ID ) && getpaid_is_invoice_post_type( /** @scrutinizer ignore-type */ get_post_type( $post->ID ) ) ) {
Loading history...
718
719
        // If the user can view this invoice, display it.
720
        if ( wpinv_user_can_view_invoice( $post->ID ) ) {
721
722
            return wpinv_get_template_part( 'wpinv-invoice-print', false, false );
723
724
        // Else display an error message.
725
        } else {
726
727
            return wpinv_get_template_part( 'wpinv-invalid-access', false, false );
728
729
        }
730
731
    }
732
733
    return $template;
734
}
735
add_filter( 'template_include', 'wpinv_template', 10, 1 );
736
737
function wpinv_get_business_address() {
738
    $business_address   = wpinv_store_address();
739
    $business_address   = !empty( $business_address ) ? wpautop( wp_kses_post( $business_address ) ) : '';
740
    
741
    $business_address = $business_address ? '<div class="address">' . $business_address . '</div>' : '';
742
    
743
    return apply_filters( 'wpinv_get_business_address', $business_address );
744
}
745
746
/**
747
 * Displays the company address.
748
 */
749
function wpinv_display_from_address() {
750
    wpinv_get_template( 'invoice/company-address.php' );
751
}
752
add_action( 'getpaid_invoice_details_left', 'wpinv_display_from_address', 10 );
753
754
/**
755
 * Generates a watermark text for an invoice.
756
 * 
757
 * @param WPInv_Invoice $invoice
758
 * @return string
759
 */
760
function wpinv_watermark( $invoice ) {
761
    $watermark = wpinv_get_watermark( $invoice );
762
    return apply_filters( 'wpinv_get_watermark', $watermark, $invoice );
763
}
764
765
/**
766
 * Generates a watermark text for an invoice.
767
 * 
768
 * @param WPInv_Invoice $invoice
769
 * @return string
770
 */
771
function wpinv_get_watermark( $invoice ) {
772
    return $invoice->get_status_nicename();
773
}
774
775
/**
776
 * @deprecated
777
 */
778
function wpinv_display_invoice_details( $invoice ) {
779
    return getpaid_invoice_meta( $invoice );
0 ignored issues
show
Bug introduced by
Are you sure the usage of getpaid_invoice_meta($invoice) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
780
}
781
782
/**
783
 * Displays invoice meta.
784
 */
785
function getpaid_invoice_meta( $invoice ) {
786
787
    $invoice = new WPInv_Invoice( $invoice );
788
789
    // Ensure that we have an invoice.
790
    if ( 0 == $invoice->get_id() ) {
791
        return;
792
    }
793
794
    // Get the invoice meta.
795
    $meta = getpaid_get_invoice_meta( $invoice );
796
797
    // Display the meta.
798
    wpinv_get_template( 'invoice/invoice-meta.php', compact( 'invoice', 'meta' ) );
799
800
}
801
add_action( 'getpaid_invoice_details_right', 'getpaid_invoice_meta', 10 );
802
803
/**
804
 * Retrieves the address markup to use on Invoices.
805
 * 
806
 * @since 1.0.13
807
 * @see `wpinv_get_full_address_format`
808
 * @see `wpinv_get_invoice_address_replacements`
809
 * @param array $billing_details customer's billing details
810
 * @param  string $separator How to separate address lines.
811
 * @return string
812
 */
813
function wpinv_get_invoice_address_markup( $billing_details, $separator = '<br/>' ) {
814
815
    // Retrieve the address markup...
816
    $country= empty( $billing_details['country'] ) ? '' : $billing_details['country'];
817
    $format = wpinv_get_full_address_format( $country );
818
819
    // ... and the replacements.
820
    $replacements = wpinv_get_invoice_address_replacements( $billing_details );
821
822
    $formatted_address = str_ireplace( array_keys( $replacements ), $replacements, $format );
823
    
824
	// Remove unavailable tags.
825
    $formatted_address = preg_replace( "/\{\{\w+\}\}/", '', $formatted_address );
826
827
    // Clean up white space.
828
	$formatted_address = preg_replace( '/  +/', ' ', trim( $formatted_address ) );
829
    $formatted_address = preg_replace( '/\n\n+/', "\n", $formatted_address );
830
    
831
    // Break newlines apart and remove empty lines/trim commas and white space.
832
	$formatted_address = array_filter( array_map( 'wpinv_trim_formatted_address_line', explode( "\n", $formatted_address ) ) );
833
834
    // Add html breaks.
835
	$formatted_address = implode( $separator, $formatted_address );
836
837
	// We're done!
838
	return $formatted_address;
839
    
840
}
841
842
/**
843
 * Displays the billing address.
844
 * 
845
 * @param WPInv_Invoice $invoice
846
 */
847
function wpinv_display_to_address( $invoice = 0 ) {
848
    if ( ! empty( $invoice ) ) {
849
        wpinv_get_template( 'invoice/billing-address.php', compact( 'invoice' ) );
850
    }
851
}
852
add_action( 'getpaid_invoice_details_left', 'wpinv_display_to_address', 40 );
853
854
855
/**
856
 * Displays invoice line items.
857
 */
858
function wpinv_display_line_items( $invoice_id = 0 ) {
859
860
    // Prepare the invoice.
861
    $invoice = new WPInv_Invoice( $invoice_id );
862
863
    // Abort if there is no invoice.
864
    if ( 0 == $invoice->get_id() ) {
865
        return;
866
    }
867
868
    // Line item columns.
869
    $columns = getpaid_invoice_item_columns( $invoice );
870
    $columns = apply_filters( 'getpaid_invoice_line_items_table_columns', $columns, $invoice );
871
872
    wpinv_get_template( 'invoice/line-items.php', compact( 'invoice', 'columns' ) );
873
}
874
add_action( 'getpaid_invoice_line_items', 'wpinv_display_line_items', 10 );
875
876
/**
877
 * Displays invoice subscriptions.
878
 * 
879
 * @param WPInv_Invoice $invoice
880
 */
881
function getpaid_display_invoice_subscriptions( $invoice ) {
882
883
    // Subscriptions.
884
	$subscriptions = getpaid_get_invoice_subscriptions( $invoice );
885
886
    if ( empty( $subscriptions ) || ! $invoice->is_recurring() ) {
887
        return;
888
    }
889
890
    $main_subscription = getpaid_get_invoice_subscription( $invoice );
891
892
    // Display related subscriptions.
893
    if ( is_array( $subscriptions ) ) {
0 ignored issues
show
introduced by
The condition is_array($subscriptions) is always false.
Loading history...
894
        printf( '<h2 class="mt-5 mb-1 h4">%s</h2>', esc_html__( 'Related Subscriptions', 'invoicing' ) );
895
        getpaid_admin_subscription_related_subscriptions_metabox( $main_subscription, false );
896
    }
897
898
    if ( $main_subscription->get_total_payments() > 1 ) {
899
        printf( '<h2 class="mt-5 mb-1 h4">%s</h2>', esc_html__( 'Related Invoices', 'invoicing' ) );
900
        getpaid_admin_subscription_invoice_details_metabox( $main_subscription, false );
901
    }
902
903
}
904
add_action( 'getpaid_invoice_line_items', 'getpaid_display_invoice_subscriptions', 15 );
905
906
/**
907
 * Displays invoice notices on invoices.
908
 */
909
function wpinv_display_invoice_notice() {
910
911
    $label  = wpinv_get_option( 'vat_invoice_notice_label' );
912
    $notice = wpinv_get_option( 'vat_invoice_notice' );
913
914
    if ( empty( $label ) && empty( $notice ) ) {
915
        return;
916
    }
917
918
    echo '<div class="mt-4 mb-4 wpinv-vat-notice">';
919
920
    if ( ! empty( $label ) ) {
921
        $label = sanitize_text_field( $label );
922
        echo "<h5>$label</h5>";
923
    }
924
925
    if ( ! empty( $notice ) ) {
926
        echo '<small class="form-text text-muted">' . wpautop( wptexturize( $notice ) ) . '</small>';
927
    }
928
929
    echo '</div>';
930
}
931
add_action( 'getpaid_invoice_line_items', 'wpinv_display_invoice_notice', 100 );
932
933
/**
934
 * @param WPInv_Invoice $invoice
935
 */
936
function wpinv_display_invoice_notes( $invoice ) {
937
938
    // Retrieve the notes.
939
    $notes = wpinv_get_invoice_notes( $invoice->get_id(), 'customer' );
940
941
    // Abort if we have non.
942
    if ( empty( $notes ) ) {
943
        return;
944
    }
945
946
    // Echo the note.
947
    echo '<div class="getpaid-invoice-notes-wrapper position-relative my-4">';
948
    echo '<h2 class="getpaid-invoice-notes-title mb-1 p-0 h4">' . __( 'Notes', 'invoicing' ) .'</h2>';
949
    echo '<ul class="getpaid-invoice-notes text-break overflow-auto list-unstyled p-0 m-0">';
950
951
    foreach( $notes as $note ) {
952
        wpinv_get_invoice_note_line_item( $note );
953
    }
954
955
    echo '</ul>';
956
    echo '</div>';
957
}
958
add_action( 'getpaid_invoice_line_items', 'wpinv_display_invoice_notes', 60 );
959
960
/**
961
 * Loads scripts on our invoice templates.
962
 */
963
function wpinv_display_style() {
964
965
    // Make sure that all scripts have been loaded.
966
    if ( ! did_action( 'wp_enqueue_scripts' ) ) {
967
        do_action( 'wp_enqueue_scripts' );
968
    }
969
970
    // Register the invoices style.
971
    wp_register_style( 'wpinv-single-style', WPINV_PLUGIN_URL . 'assets/css/invoice.css', array(), filemtime( WPINV_PLUGIN_DIR . 'assets/css/invoice.css' ) );
972
973
    // Load required styles
974
    wp_print_styles( 'wpinv-single-style' );
975
    wp_print_styles( 'ayecode-ui' );
976
977
    // Maybe load custom css.
978
    $custom_css = wpinv_get_option( 'template_custom_css' );
979
980
    if ( isset( $custom_css ) && ! empty( $custom_css ) ) {
981
        $custom_css     = wp_kses( $custom_css, array( '\'', '\"' ) );
0 ignored issues
show
Bug introduced by
array(''', '\"') of type array<integer,string> is incompatible with the type array<mixed,array>|string expected by parameter $allowed_html of wp_kses(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

981
        $custom_css     = wp_kses( $custom_css, /** @scrutinizer ignore-type */ array( '\'', '\"' ) );
Loading history...
982
        $custom_css     = str_replace( '&gt;', '>', $custom_css );
983
        echo '<style type="text/css">';
984
        echo $custom_css;
985
        echo '</style>';
986
    }
987
988
}
989
add_action( 'wpinv_invoice_print_head', 'wpinv_display_style' );
990
add_action( 'wpinv_invalid_invoice_head', 'wpinv_display_style' );
991
992
993
/**
994
 * Displays the checkout page.
995
 */
996
function wpinv_checkout_form() {
997
    global $wpi_checkout_id;
998
999
    // Retrieve the current invoice.
1000
    $invoice_id = getpaid_get_current_invoice_id();
1001
1002
    if ( empty( $invoice_id ) ) {
1003
1004
        return aui()->alert(
1005
            array(
1006
                'type'    => 'warning',
1007
                'content' => __( 'Invalid invoice', 'invoicing' ),
1008
            )
1009
        );
1010
1011
    }
1012
1013
    // Can the user view this invoice?
1014
    if ( ! wpinv_user_can_view_invoice( $invoice_id ) ) {
1015
1016
        return aui()->alert(
1017
            array(
1018
                'type'    => 'warning',
1019
                'content' => __( 'You are not allowed to view this invoice', 'invoicing' ),
1020
            )
1021
        );
1022
1023
    }
1024
1025
    // Ensure that it is not yet paid for.
1026
    $invoice = new WPInv_Invoice( $invoice_id );
1027
1028
    // Maybe mark it as viewed.
1029
    getpaid_maybe_mark_invoice_as_viewed( $invoice );
1030
1031
    if ( $invoice->is_paid() ) {
1032
1033
        return aui()->alert(
1034
            array(
1035
                'type'    => 'success',
1036
                'content' => __( 'This invoice has already been paid.', 'invoicing' ),
1037
            )
1038
        );
1039
1040
    }
1041
1042
    // Set the global invoice id.
1043
    $wpi_checkout_id = $invoice_id;
1044
1045
    // Retrieve appropriate payment form.
1046
    $payment_form = new GetPaid_Payment_Form( $invoice->get_meta( 'force_payment_form' ) );
1047
    $payment_form = $payment_form->exists() ? $payment_form : new GetPaid_Payment_Form( wpinv_get_default_payment_form() );
1048
1049
    if ( ! $payment_form->exists() ) {
1050
1051
        return aui()->alert(
1052
            array(
1053
                'type'    => 'warning',
1054
                'content' => __( 'Error loading the payment form', 'invoicing' ),
1055
            )
1056
        );
1057
1058
    }
1059
1060
    // Set the invoice.
1061
    $payment_form->invoice = $invoice;
1062
1063
    if ( ! $payment_form->is_default() ) {
1064
1065
        $items    = array();
1066
        $item_ids = array();
1067
1068
        foreach ( $invoice->get_items() as $item ) {
1069
            if ( ! in_array( $item->get_id(), $item_ids ) ) {
1070
                $item_ids[] = $item->get_id();
1071
                $items[]    = $item;
1072
            }
1073
        }
1074
1075
        foreach ( $payment_form->get_items() as $item ) {
1076
            if ( ! in_array( $item->get_id(), $item_ids ) ) {
1077
                $item_ids[] = $item->get_id();
1078
                $items[]    = $item;
1079
            }
1080
        }
1081
1082
        $payment_form->set_items( $items );
1083
1084
    } else {
1085
        $payment_form->set_items( $invoice->get_items() );
1086
    }
1087
1088
    // Generate the html.
1089
    return $payment_form->get_html();
1090
1091
}
1092
1093
function wpinv_empty_cart_message() {
1094
	return apply_filters( 'wpinv_empty_cart_message', '<span class="wpinv_empty_cart">' . __( 'Your cart is empty.', 'invoicing' ) . '</span>' );
1095
}
1096
1097
/**
1098
 * Echoes the Empty Cart Message
1099
 *
1100
 * @since 1.0
1101
 * @return void
1102
 */
1103
function wpinv_empty_checkout_cart() {
1104
    echo aui()->alert(
1105
        array(
1106
            'type'    => 'warning',
1107
            'content' => wpinv_empty_cart_message(),
1108
        )
1109
    );
1110
}
1111
add_action( 'wpinv_cart_empty', 'wpinv_empty_checkout_cart' );
1112
1113
/**
1114
 * Filters the receipt page.
1115
 */
1116
function wpinv_filter_success_page_content( $content ) {
1117
1118
    // Maybe abort early.
1119
    if ( is_admin() || ! is_singular() || ! in_the_loop() || ! is_main_query() || is_preview() ) {
1120
        return $content;
1121
    }
1122
1123
    // Ensure this is our page.
1124
    if ( isset( $_GET['payment-confirm'] ) && wpinv_is_success_page() ) {
1125
1126
        $gateway = sanitize_text_field( $_GET['payment-confirm'] );
1127
        return apply_filters( "wpinv_payment_confirm_$gateway", $content );
1128
1129
    }
1130
1131
    return $content;
1132
}
1133
add_filter( 'the_content', 'wpinv_filter_success_page_content', 99999 );
1134
1135
function wpinv_invoice_link( $invoice_id ) {
1136
    $invoice = wpinv_get_invoice( $invoice_id );
1137
1138
    if ( empty( $invoice ) ) {
1139
        return NULL;
1140
    }
1141
1142
    $invoice_link = '<a href="' . esc_url( $invoice->get_view_url() ) . '">' . $invoice->get_number() . '</a>';
1143
1144
    return apply_filters( 'wpinv_get_invoice_link', $invoice_link, $invoice );
1145
}
1146
1147
function wpinv_get_invoice_note_line_item( $note, $echo = true ) {
1148
    if ( empty( $note ) ) {
1149
        return NULL;
1150
    }
1151
1152
    if ( is_int( $note ) ) {
1153
        $note = get_comment( $note );
1154
    }
1155
1156
    if ( !( is_object( $note ) && is_a( $note, 'WP_Comment' ) ) ) {
1157
        return NULL;
1158
    }
1159
1160
    $note_classes   = array( 'note' );
1161
    $note_classes[] = get_comment_meta( $note->comment_ID, '_wpi_customer_note', true ) ? 'customer-note' : '';
0 ignored issues
show
Bug introduced by
$note->comment_ID of type string is incompatible with the type integer expected by parameter $comment_id of get_comment_meta(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1161
    $note_classes[] = get_comment_meta( /** @scrutinizer ignore-type */ $note->comment_ID, '_wpi_customer_note', true ) ? 'customer-note' : '';
Loading history...
1162
    $note_classes[] = $note->comment_author === 'System' ? 'system-note' : '';
1163
    $note_classes   = apply_filters( 'wpinv_invoice_note_class', array_filter( $note_classes ), $note );
1164
    $note_classes   = !empty( $note_classes ) ? implode( ' ', $note_classes ) : '';
1165
1166
    ob_start();
1167
    ?>
1168
    <li rel="<?php echo absint( $note->comment_ID ) ; ?>" class="<?php echo esc_attr( $note_classes ); ?> mb-2">
1169
        <div class="note_content">
1170
1171
            <?php echo wptexturize( wp_kses_post( $note->comment_content ) ); ?>
1172
1173
            <?php if ( ! is_admin() ) : ?>
1174
                <em class="small form-text text-muted mt-0">
1175
                    <?php
1176
                        printf(
1177
                            __( '%1$s - %2$s at %3$s', 'invoicing' ),
1178
                            $note->comment_author,
1179
                            getpaid_format_date_value( $note->comment_date ),
1180
                            date_i18n( get_option( 'time_format' ), strtotime( $note->comment_date ) )
0 ignored issues
show
Bug introduced by
It seems like get_option('time_format') can also be of type false; however, parameter $format of date_i18n() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1180
                            date_i18n( /** @scrutinizer ignore-type */ get_option( 'time_format' ), strtotime( $note->comment_date ) )
Loading history...
1181
                        );
1182
                    ?>
1183
                </em>
1184
            <?php endif; ?>
1185
1186
        </div>
1187
1188
        <?php if ( is_admin() ) : ?>
1189
1190
            <p class="meta px-4 py-2">
1191
                <abbr class="exact-date" title="<?php echo esc_attr( $note->comment_date ); ?>">
1192
                    <?php
1193
                        printf(
1194
                            __( '%1$s - %2$s at %3$s', 'invoicing' ),
1195
                            $note->comment_author,
1196
                            getpaid_format_date_value( $note->comment_date ),
1197
                            date_i18n( get_option( 'time_format' ), strtotime( $note->comment_date ) )
1198
                        );
1199
                    ?>
1200
                </abbr>&nbsp;&nbsp;
1201
                <?php if ( $note->comment_author !== 'System' && wpinv_current_user_can_manage_invoicing() ) { ?>
1202
                    <a href="#" class="delete_note"><?php _e( 'Delete note', 'invoicing' ); ?></a>
1203
                <?php } ?>
1204
            </p>
1205
1206
        <?php endif; ?>
1207
        
1208
    </li>
1209
    <?php
1210
    $note_content = ob_get_clean();
1211
    $note_content = apply_filters( 'wpinv_get_invoice_note_line_item', $note_content, $note, $echo );
1212
1213
    if ( $echo ) {
1214
        echo $note_content;
1215
    } else {
1216
        return $note_content;
1217
    }
1218
}
1219
1220
/**
1221
 * Function to get privacy policy text.
1222
 *
1223
 * @since 1.0.13
1224
 * @return string
1225
 */
1226
function wpinv_get_policy_text() {
1227
    $privacy_page_id = get_option( 'wp_page_for_privacy_policy', 0 );
1228
1229
    $text = wpinv_get_option('invoicing_privacy_checkout_message', sprintf( __( 'Your personal data will be used to process your invoice, payment and for other purposes described in our %s.', 'invoicing' ), '[wpinv_privacy_policy]' ));
1230
1231
    if(!$privacy_page_id){
1232
        $privacy_page_id = wpinv_get_option( 'privacy_page', 0 );
1233
    }
1234
1235
    $privacy_link    = $privacy_page_id ? '<a href="' . esc_url( get_permalink( $privacy_page_id ) ) . '" class="wpinv-privacy-policy-link" target="_blank">' . __( 'privacy policy', 'invoicing' ) . '</a>' : __( 'privacy policy', 'invoicing' );
0 ignored issues
show
Bug introduced by
It seems like get_permalink($privacy_page_id) can also be of type false; however, parameter $url of esc_url() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1235
    $privacy_link    = $privacy_page_id ? '<a href="' . esc_url( /** @scrutinizer ignore-type */ get_permalink( $privacy_page_id ) ) . '" class="wpinv-privacy-policy-link" target="_blank">' . __( 'privacy policy', 'invoicing' ) . '</a>' : __( 'privacy policy', 'invoicing' );
Loading history...
1236
1237
    $find_replace = array(
1238
        '[wpinv_privacy_policy]' => $privacy_link,
1239
    );
1240
1241
    $privacy_text = str_replace( array_keys( $find_replace ), array_values( $find_replace ), $text );
1242
1243
    return wp_kses_post(wpautop($privacy_text));
1244
}
1245
1246
function wpinv_oxygen_fix_conflict() {
1247
    global $ct_ignore_post_types;
1248
1249
    if ( ! is_array( $ct_ignore_post_types ) ) {
1250
        $ct_ignore_post_types = array();
1251
    }
1252
1253
    $post_types = array( 'wpi_discount', 'wpi_invoice', 'wpi_item', 'wpi_payment_form' );
1254
1255
    foreach ( $post_types as $post_type ) {
1256
        $ct_ignore_post_types[] = $post_type;
1257
1258
        // Ignore post type
1259
        add_filter( 'pre_option_oxygen_vsb_ignore_post_type_' . $post_type, '__return_true', 999 );
1260
    }
1261
1262
    remove_filter( 'template_include', 'wpinv_template', 10, 1 );
0 ignored issues
show
Unused Code introduced by
The call to remove_filter() has too many arguments starting with 1. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1262
    /** @scrutinizer ignore-call */ 
1263
    remove_filter( 'template_include', 'wpinv_template', 10, 1 );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
1263
    add_filter( 'template_include', 'wpinv_template', 999, 1 );
1264
}
1265
1266
/**
1267
 * Helper function to display a payment form on the frontend.
1268
 * 
1269
 * @param GetPaid_Payment_Form $form
1270
 */
1271
function getpaid_display_payment_form( $form ) {
1272
1273
    if ( is_numeric( $form ) ) {
0 ignored issues
show
introduced by
The condition is_numeric($form) is always false.
Loading history...
1274
        $form = new GetPaid_Payment_Form( $form );
1275
    }
1276
1277
    $form->display();
1278
1279
}
1280
1281
/**
1282
 * Helper function to display a item payment form on the frontend.
1283
 */
1284
function getpaid_display_item_payment_form( $items ) {
1285
1286
    $form = new GetPaid_Payment_Form( wpinv_get_default_payment_form() );
1287
    $form->set_items( $items );
1288
1289
    if ( 0 == count( $form->get_items() ) ) {
1290
        echo aui()->alert(
1291
			array(
1292
				'type'    => 'warning',
1293
				'content' => __( 'No published items found', 'invoicing' ),
1294
			)
1295
        );
1296
        return;
1297
    }
1298
1299
    $extra_items     = esc_attr( getpaid_convert_items_to_string( $items ) );
1300
    $extra_items_key = md5( NONCE_KEY . AUTH_KEY . $extra_items );
1301
    $extra_items     = "<input type='hidden' name='getpaid-form-items' value='$extra_items' />";
1302
    $extra_items    .= "<input type='hidden' name='getpaid-form-items-key' value='$extra_items_key' />";
1303
1304
    $form->display( $extra_items );
1305
}
1306
1307
/**
1308
 * Helper function to display an invoice payment form on the frontend.
1309
 */
1310
function getpaid_display_invoice_payment_form( $invoice_id ) {
1311
1312
    $invoice = wpinv_get_invoice( $invoice_id );
1313
1314
    if ( empty( $invoice ) ) {
1315
		echo aui()->alert(
1316
			array(
1317
				'type'    => 'warning',
1318
				'content' => __( 'Invoice not found', 'invoicing' ),
1319
			)
1320
        );
1321
        return;
1322
    }
1323
1324
    if ( $invoice->is_paid() ) {
1325
		echo aui()->alert(
1326
			array(
1327
				'type'    => 'warning',
1328
				'content' => __( 'Invoice has already been paid', 'invoicing' ),
1329
			)
1330
        );
1331
        return;
1332
    }
1333
1334
    $form = new GetPaid_Payment_Form( wpinv_get_default_payment_form() );
1335
    $form->set_items( $invoice->get_items() );
1336
1337
    $form->display();
1338
}
1339
1340
/**
1341
 * Helper function to convert item string to array.
1342
 */
1343
function getpaid_convert_items_to_array( $items ) {
1344
    $items    = array_filter( array_map( 'trim', explode( ',', $items ) ) );
1345
    $prepared = array();
1346
1347
    foreach ( $items as $item ) {
1348
        $data = array_map( 'trim', explode( '|', $item ) );
1349
1350
        if ( empty( $data[0] ) || ! is_numeric( $data[0] ) ) {
1351
            continue;
1352
        }
1353
1354
        $quantity = 1;
1355
        if ( isset( $data[1] ) && is_numeric( $data[1] ) ) {
1356
            $quantity = (float) $data[1];
1357
        }
1358
1359
        $prepared[ $data[0] ] = $quantity;
1360
1361
    }
1362
1363
    return $prepared;
1364
}
1365
1366
/**
1367
 * Helper function to convert item array to string.
1368
 */
1369
function getpaid_convert_items_to_string( $items ) {
1370
    $prepared = array();
1371
1372
    foreach ( $items as $item => $quantity ) {
1373
        $prepared[] = "$item|$quantity";
1374
    }
1375
    return implode( ',', $prepared );
1376
}
1377
1378
/**
1379
 * Helper function to display a payment item.
1380
 * 
1381
 * Provide a label and one of $form, $items or $invoice.
1382
 */
1383
function getpaid_get_payment_button( $label, $form = null, $items = null, $invoice = null ) {
1384
    $label = sanitize_text_field( $label );
1385
1386
    if ( ! empty( $form ) ) {
1387
        $form  = esc_attr( $form );
1388
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-form='$form'>$label</button>"; 
1389
    }
1390
	
1391
	if ( ! empty( $items ) ) {
1392
        $items  = esc_attr( $items );
1393
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-item='$items'>$label</button>"; 
1394
    }
1395
    
1396
    if ( ! empty( $invoice ) ) {
1397
        $invoice  = esc_attr( $invoice );
1398
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-invoice='$invoice'>$label</button>"; 
1399
    }
1400
1401
}
1402
1403
/**
1404
 * Display invoice description before line items.
1405
 *
1406
 * @param WPInv_Invoice $invoice
1407
 */
1408
function getpaid_the_invoice_description( $invoice ) {
1409
    $description = $invoice->get_description();
1410
1411
    if ( empty( $description ) ) {
1412
        return;
1413
    }
1414
1415
    $description = wp_kses_post( wpautop( $description ) );
1416
    echo "<small class='getpaid-invoice-description text-dark p-2 form-text' style='margin-bottom: 20px; border-left: 2px solid #2196F3;'><em>$description</em></small>";
1417
}
1418
add_action( 'getpaid_invoice_line_items', 'getpaid_the_invoice_description', 100 );
1419
add_action( 'wpinv_email_billing_details', 'getpaid_the_invoice_description', 100 );
1420
1421
/**
1422
 * Render element on a form.
1423
 *
1424
 * @param array $element
1425
 * @param GetPaid_Payment_Form $form
1426
 */
1427
function getpaid_payment_form_element( $element, $form ) {
1428
1429
    // Set up the args.
1430
    $element_type    = trim( $element['type'] );
1431
    $element['form'] = $form;
1432
    extract( $element );
1433
1434
    // Try to locate the appropriate template.
1435
    $located = wpinv_locate_template( "payment-forms/elements/$element_type.php" );
1436
    
1437
    // Abort if this is not our element.
1438
    if ( empty( $located ) || ! file_exists( $located ) ) {
1439
        return;
1440
    }
1441
1442
    // Generate the class and id of the element.
1443
    $wrapper_class = 'getpaid-payment-form-element-' . trim( esc_attr( $element_type ) );
1444
    $id            = isset( $id ) ? $id : uniqid( 'gp' );
1445
1446
    // Echo the opening wrapper.
1447
    echo "<div class='getpaid-payment-form-element $wrapper_class'>";
1448
1449
    // Fires before displaying a given element type's content.
1450
    do_action( "getpaid_before_payment_form_{$element_type}_element", $element, $form );
1451
1452
    // Include the template for the element.
1453
    include $located;
1454
1455
    // Fires after displaying a given element type's content.
1456
    do_action( "getpaid_payment_form_{$element_type}_element", $element, $form );
1457
1458
    // Echo the closing wrapper.
1459
    echo '</div>';
1460
}
1461
add_action( 'getpaid_payment_form_element', 'getpaid_payment_form_element', 10, 2 );
1462
1463
/**
1464
 * Render an element's edit page.
1465
 *
1466
 * @param WP_Post $post
1467
 */
1468
function getpaid_payment_form_edit_element_template( $post ) {
1469
1470
    // Retrieve all elements.
1471
    $all_elements = wp_list_pluck( wpinv_get_data( 'payment-form-elements' ), 'type' );
1472
1473
    foreach ( $all_elements as $element ) {
1474
1475
        // Try to locate the appropriate template.
1476
        $element = sanitize_key( $element );
1477
        $located = wpinv_locate_template( "payment-forms-admin/edit/$element.php" );
1478
1479
        // Continue if this is not our element.
1480
        if ( empty( $located ) || ! file_exists( $located ) ) {
1481
            continue;
1482
        }
1483
1484
        // Include the template for the element.
1485
        echo "<div v-if=\"active_form_element.type=='$element'\">";
1486
        include $located;
1487
        echo '</div>';
1488
    }
1489
1490
}
1491
add_action( 'getpaid_payment_form_edit_element_template', 'getpaid_payment_form_edit_element_template' );
1492
1493
/**
1494
 * Render an element's preview.
1495
 *
1496
 */
1497
function getpaid_payment_form_render_element_preview_template() {
1498
1499
    // Retrieve all elements.
1500
    $all_elements = wp_list_pluck( wpinv_get_data( 'payment-form-elements' ), 'type' );
1501
1502
    foreach ( $all_elements as $element ) {
1503
1504
        // Try to locate the appropriate template.
1505
        $element = sanitize_key( $element );
1506
        $located = wpinv_locate_template( "payment-forms-admin/previews/$element.php" );
1507
1508
        // Continue if this is not our element.
1509
        if ( empty( $located ) || ! file_exists( $located ) ) {
1510
            continue;
1511
        }
1512
1513
        // Include the template for the element.
1514
        echo "<div v-if=\"form_element.type=='$element'\">";
1515
        include $located;
1516
        echo '</div>';
1517
    }
1518
1519
}
1520
add_action( 'wpinv_payment_form_render_element_template', 'getpaid_payment_form_render_element_preview_template' );
1521
1522
/**
1523
 * Shows a list of gateways that support recurring payments.
1524
 */
1525
function wpinv_get_recurring_gateways_text() {
1526
    $gateways = array();
1527
1528
    foreach ( wpinv_get_payment_gateways() as $key => $gateway ) {
1529
        if ( wpinv_gateway_support_subscription( $key ) ) {
1530
            $gateways[] = sanitize_text_field( $gateway['admin_label'] );
1531
        }
1532
    }
1533
1534
    if ( empty( $gateways ) ) {
1535
        return "<span class='form-text text-danger'>" . __( 'No active gateways support subscription payments.', 'invoicing' ) ."</span>";
1536
    }
1537
1538
    return "<span class='form-text text-muted'>" . wp_sprintf( __( 'Subscription payments only supported by: %s', 'invoicing' ), implode( ', ', $gateways ) ) ."</span>";
1539
1540
}
1541
1542
/**
1543
 * Returns the template.
1544
 * 
1545
 * @return GetPaid_Template
1546
 */
1547
function getpaid_template() {
1548
    return getpaid()->get( 'template' );
1549
}
1550
1551
/**
1552
 * Displays pagination links.
1553
 * 
1554
 * @param array args
0 ignored issues
show
Bug introduced by
The type args was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1555
 * @return string
1556
 */
1557
function getpaid_paginate_links( $args ) {
1558
    return str_replace( 'page-link dots', 'page-link text-dark', aui()->pagination( $args ) );
1559
}
1560
1561
/**
1562
 * Displays the states select markup.
1563
 * 
1564
 * @param string country
1565
 * @param string state
0 ignored issues
show
Bug introduced by
The type state was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1566
 * @return string
1567
 */
1568
function getpaid_get_states_select_markup( $country, $state, $placeholder, $label, $help_text, $required = false, $wrapper_class = 'col-12', $field_name = 'wpinv_state' ) {
1569
1570
    $states = wpinv_get_country_states( $country );
1571
    $uniqid = uniqid( '_' );
1572
1573
    if ( ! empty( $states ) ) {
1574
1575
        return aui()->select( array(
1576
            'options'          => $states,
1577
            'name'             => esc_attr( $field_name ),
1578
            'id'               => sanitize_html_class( $field_name ) . $uniqid,
1579
            'value'            => sanitize_text_field( $state ),
1580
            'placeholder'      => $placeholder,
1581
            'required'         => $required,
1582
            'label'            => wp_kses_post( $label ),
1583
            'label_type'       => 'vertical',
1584
            'help_text'        => $help_text,
1585
            'class'            => 'getpaid-address-field wpinv_state',
1586
            'wrap_class'       => "$wrapper_class getpaid-address-field-wrapper__state",
1587
            'label_class'      => 'getpaid-address-field-label getpaid-address-field-label__state',
1588
            'extra_attributes' => array(
1589
                'autocomplete' => "address-level1",
1590
            ),
1591
        ));
1592
1593
    }
1594
1595
    return aui()->input(
1596
        array(
1597
            'name'        => esc_attr( $field_name ),
1598
            'id'          => sanitize_html_class( $field_name ) . $uniqid,
1599
            'placeholder' => $placeholder,
1600
            'required'    => $required,
1601
            'label'       => wp_kses_post( $label ),
1602
            'label_type'  => 'vertical',
1603
            'help_text'   => $help_text,
1604
            'value'       => sanitize_text_field( $state ),
1605
            'class'       => 'getpaid-address-field wpinv_state',
1606
            'wrap_class'  => "$wrapper_class getpaid-address-field-wrapper__state",
1607
            'label_class' => 'getpaid-address-field-label getpaid-address-field-label__state',
1608
            'extra_attributes' => array(
1609
                'autocomplete' => "address-level1",
1610
            ),
1611
        )
1612
    );
1613
1614
}
1615
1616
/**
1617
 * Retrieves an element's grid width.
1618
 * 
1619
 * @param array $element
1620
 * @return string
1621
 */
1622
function getpaid_get_form_element_grid_class( $element ) {
1623
1624
    $class = "col-12";
1625
    $width = empty( $element['grid_width'] ) ? 'full' : $element['grid_width'];
1626
1627
    if ( $width == 'half' ) {
1628
        $class .= " col-md-6";
1629
    }
1630
1631
    if ( $width == 'third' ) {
1632
        $class .= " col-md-4";
1633
    }
1634
1635
    return $class;
1636
}
1637
1638
/**
1639
 * Retrieves the payment form embed URL.
1640
 *
1641
 * @param int $payment_form payment form.
1642
 * @param string $items form items.
1643
 *
1644
 * @return string
1645
 */
1646
function getpaid_embed_url( $payment_form = false, $items = false ) {
1647
1648
    return add_query_arg(
1649
        array(
1650
            'getpaid_embed' => 1,
1651
            'form'          => $payment_form ? absint( $payment_form ) : false,
1652
            'item'          => $items ? urlencode( $items ) : false
1653
        ),
1654
        home_url( 'index.php' )
1655
    );
1656
1657
}
1658
1659
/**
1660
 * Embeds a payment form.
1661
 *
1662
 * @return string
1663
 */
1664
function getpaid_filter_embed_template( $template ) {
1665
1666
    if ( isset( $_GET['getpaid_embed'] ) ) {
1667
        wpinv_get_template( 'payment-forms/embed.php' );
1668
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1669
    }
1670
1671
    return $template;
1672
}
1673
add_filter( 'template_include', 'getpaid_filter_embed_template' );
1674
1675
/**
1676
 * Prints embed styles.
1677
 */
1678
function getpaid_print_embed_styles() {
1679
1680
    // Make sure that all scripts have been loaded.
1681
    if ( ! did_action( 'wp_enqueue_scripts' ) ) {
1682
        do_action( 'wp_enqueue_scripts' );
1683
    }
1684
1685
    wp_print_styles( 'ayecode-ui' );
1686
1687
}
1688
add_action( 'getpaid_payment_form_embed_head', 'getpaid_print_embed_styles' );
1689
1690
/**
1691
 * Prints embed scripts.
1692
 */
1693
function getpaid_print_embed_scripts() {
1694
1695
    // Make sure that all scripts have been loaded.
1696
    if ( ! did_action( 'wp_enqueue_scripts' ) ) {
1697
        do_action( 'wp_enqueue_scripts' );
1698
    }
1699
1700
    wp_print_styles( 'ayecode-ui' );
1701
    wp_print_scripts(
1702
        array(
1703
            'wpinv-front-script'
1704
        )
1705
    );
1706
1707
}
1708
add_action( 'getpaid_payment_form_embed_bottom', 'getpaid_print_embed_scripts' );
1709