Passed
Pull Request — master (#398)
by Brian
05:25
created

getpaid_template()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 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, watermark, 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
    return getpaid_template()->display_template( $template_name, $args, $template_path, $default_path );
0 ignored issues
show
Bug introduced by
Are you sure the usage of getpaid_template()->disp...te_path, $default_path) targeting GetPaid_Template::display_template() 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...
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_dropdown( $name = 'wpinv_discounts', $selected = 0, $status = '' ) {
298
    $args = array( 'nopaging' => true );
299
300
    if ( ! empty( $status ) )
301
        $args['post_status'] = $status;
302
303
    $discounts = wpinv_get_discounts( $args );
304
    $options   = array();
305
306
    if ( $discounts ) {
307
        foreach ( $discounts as $discount ) {
308
            $options[ absint( $discount->ID ) ] = esc_html( get_the_title( $discount->ID ) );
309
        }
310
    } else {
311
        $options[0] = __( 'No discounts found', 'invoicing' );
312
    }
313
314
    $output = wpinv_html_select( array(
315
        'name'             => $name,
316
        'selected'         => $selected,
317
        'options'          => $options,
318
        'show_option_all'  => false,
319
        'show_option_none' => false,
320
    ) );
321
322
    return $output;
323
}
324
325
function wpinv_html_year_dropdown( $name = 'year', $selected = 0, $years_before = 5, $years_after = 0 ) {
326
    $current     = date( 'Y' );
327
    $start_year  = $current - absint( $years_before );
328
    $end_year    = $current + absint( $years_after );
329
    $selected    = empty( $selected ) ? date( 'Y' ) : $selected;
330
    $options     = array();
331
332
    while ( $start_year <= $end_year ) {
333
        $options[ absint( $start_year ) ] = $start_year;
334
        $start_year++;
335
    }
336
337
    $output = wpinv_html_select( array(
338
        'name'             => $name,
339
        'selected'         => $selected,
340
        'options'          => $options,
341
        'show_option_all'  => false,
342
        'show_option_none' => false
343
    ) );
344
345
    return $output;
346
}
347
348
function wpinv_html_month_dropdown( $name = 'month', $selected = 0 ) {
349
350
    $options = array(
351
        '1'  => __( 'January', 'invoicing' ),
352
        '2'  => __( 'February', 'invoicing' ),
353
        '3'  => __( 'March', 'invoicing' ),
354
        '4'  => __( 'April', 'invoicing' ),
355
        '5'  => __( 'May', 'invoicing' ),
356
        '6'  => __( 'June', 'invoicing' ),
357
        '7'  => __( 'July', 'invoicing' ),
358
        '8'  => __( 'August', 'invoicing' ),
359
        '9'  => __( 'September', 'invoicing' ),
360
        '10' => __( 'October', 'invoicing' ),
361
        '11' => __( 'November', 'invoicing' ),
362
        '12' => __( 'December', 'invoicing' ),
363
    );
364
365
    // If no month is selected, default to the current month
366
    $selected = empty( $selected ) ? date( 'n' ) : $selected;
367
368
    $output = wpinv_html_select( array(
369
        'name'             => $name,
370
        'selected'         => $selected,
371
        'options'          => $options,
372
        'show_option_all'  => false,
373
        'show_option_none' => false
374
    ) );
375
376
    return $output;
377
}
378
379
function wpinv_html_select( $args = array() ) {
380
    $defaults = array(
381
        'options'          => array(),
382
        'name'             => null,
383
        'class'            => '',
384
        'id'               => '',
385
        'selected'         => 0,
386
        'placeholder'      => null,
387
        'multiple'         => false,
388
        'show_option_all'  => _x( 'All', 'all dropdown items', 'invoicing' ),
389
        'show_option_none' => _x( 'None', 'no dropdown items', 'invoicing' ),
390
        'data'             => array(),
391
        'onchange'         => null,
392
        'required'         => false,
393
        'disabled'         => false,
394
        'readonly'         => false,
395
    );
396
397
    $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 552
  1. Read from $_GET, and $_GET['vat_class'] is assigned to $vat_class
    in includes/admin/class-getpaid-post-types-admin.php on line 552
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 556
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 379
  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 522
  1. Read from $_GET, and $_GET['vat_rule'] is assigned to $vat_rule
    in includes/admin/class-getpaid-post-types-admin.php on line 522
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 527
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 379
  3. Path: Read from $_GET, and $_GET['type'] is assigned to $type in includes/admin/class-getpaid-post-types-admin.php on line 577
  1. Read from $_GET, and $_GET['type'] is assigned to $type
    in includes/admin/class-getpaid-post-types-admin.php on line 577
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 581
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 379

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...
398
399
    $data_elements = '';
400
    foreach ( $args['data'] as $key => $value ) {
401
        $data_elements .= ' data-' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
402
    }
403
404
    if( $args['multiple'] ) {
405
        $multiple = ' MULTIPLE';
406
    } else {
407
        $multiple = '';
408
    }
409
410
    if( $args['placeholder'] ) {
411
        $placeholder = $args['placeholder'];
412
    } else {
413
        $placeholder = '';
414
    }
415
    
416
    $options = '';
417
    if( !empty( $args['onchange'] ) ) {
418
        $options .= ' onchange="' . esc_attr( $args['onchange'] ) . '"';
419
    }
420
    
421
    if( !empty( $args['required'] ) ) {
422
        $options .= ' required="required"';
423
    }
424
    
425
    if( !empty( $args['disabled'] ) ) {
426
        $options .= ' disabled';
427
    }
428
    
429
    if( !empty( $args['readonly'] ) ) {
430
        $options .= ' readonly';
431
    }
432
433
    $class  = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
434
    $output = '<select name="' . esc_attr( $args['name'] ) . '" id="' . esc_attr( $args['id'] ) . '" class="wpinv-select ' . $class . '"' . $multiple . ' data-placeholder="' . $placeholder . '" ' . trim( $options ) . $data_elements . '>';
435
436
    if ( $args['show_option_all'] ) {
437
        if( $args['multiple'] ) {
438
            $selected = selected( true, in_array( 0, $args['selected'] ), false );
439
        } else {
440
            $selected = selected( $args['selected'], 0, false );
441
        }
442
        $output .= '<option value="all"' . $selected . '>' . esc_html( $args['show_option_all'] ) . '</option>';
443
    }
444
445
    if ( !empty( $args['options'] ) ) {
446
447
        if ( $args['show_option_none'] ) {
448
            if( $args['multiple'] ) {
449
                $selected = selected( true, in_array( "", $args['selected'] ), false );
450
            } else {
451
                $selected = selected( $args['selected'] === "", true, false );
452
            }
453
            $output .= '<option value=""' . $selected . '>' . esc_html( $args['show_option_none'] ) . '</option>';
454
        }
455
456
        foreach( $args['options'] as $key => $option ) {
457
458
            if( $args['multiple'] && is_array( $args['selected'] ) ) {
459
                $selected = selected( true, (bool)in_array( $key, $args['selected'] ), false );
460
            } else {
461
                $selected = selected( $args['selected'], $key, false );
462
            }
463
464
            $output .= '<option value="' . esc_attr( $key ) . '"' . $selected . '>' . esc_html( $option ) . '</option>';
465
        }
466
    }
467
468
    $output .= '</select>';
469
470
    return $output;
471
}
472
473
function wpinv_item_dropdown( $args = array() ) {
474
    $defaults = array(
475
        'name'              => 'wpi_item',
476
        'id'                => 'wpi_item',
477
        'class'             => '',
478
        'multiple'          => false,
479
        'selected'          => 0,
480
        'number'            => 100,
481
        'placeholder'       => __( 'Choose a item', 'invoicing' ),
482
        'data'              => array( 'search-type' => 'item' ),
483
        'show_option_all'   => false,
484
        'show_option_none'  => false,
485
        'show_recurring'    => false,
486
    );
487
488
    $args = wp_parse_args( $args, $defaults );
489
490
    $item_args = array(
491
        'post_type'      => 'wpi_item',
492
        'orderby'        => 'title',
493
        'order'          => 'ASC',
494
        'posts_per_page' => $args['number']
495
    );
496
497
    $item_args  = apply_filters( 'wpinv_item_dropdown_query_args', $item_args, $args, $defaults );
498
499
    $items      = get_posts( $item_args );
500
    $options    = array();
501
    if ( $items ) {
502
        foreach ( $items as $item ) {
503
            $title = esc_html( $item->post_title );
504
            
505
            if ( !empty( $args['show_recurring'] ) ) {
506
                $title .= wpinv_get_item_suffix( $item->ID, false );
507
            }
508
            
509
            $options[ absint( $item->ID ) ] = $title;
510
        }
511
    }
512
513
    // This ensures that any selected items are included in the drop down
514
    if( is_array( $args['selected'] ) ) {
515
        foreach( $args['selected'] as $item ) {
516
            if( ! in_array( $item, $options ) ) {
517
                $title = get_the_title( $item );
518
                if ( !empty( $args['show_recurring'] ) ) {
519
                    $title .= wpinv_get_item_suffix( $item, false );
520
                }
521
                $options[$item] = $title;
522
            }
523
        }
524
    } elseif ( is_numeric( $args['selected'] ) && $args['selected'] !== 0 ) {
525
        if ( ! in_array( $args['selected'], $options ) ) {
526
            $title = get_the_title( $args['selected'] );
527
            if ( !empty( $args['show_recurring'] ) ) {
528
                $title .= wpinv_get_item_suffix( $args['selected'], false );
529
            }
530
            $options[$args['selected']] = get_the_title( $args['selected'] );
531
        }
532
    }
533
534
    $output = wpinv_html_select( array(
535
        'name'             => $args['name'],
536
        'selected'         => $args['selected'],
537
        'id'               => $args['id'],
538
        'class'            => $args['class'],
539
        'options'          => $options,
540
        'multiple'         => $args['multiple'],
541
        'placeholder'      => $args['placeholder'],
542
        'show_option_all'  => $args['show_option_all'],
543
        'show_option_none' => $args['show_option_none'],
544
        'data'             => $args['data'],
545
    ) );
546
547
    return $output;
548
}
549
550
/**
551
 * Returns an array of published items.
552
 */
553
function wpinv_get_published_items_for_dropdown() {
554
555
    $items = get_posts(
556
        array(
557
            'post_type'      => 'wpi_item',
558
            'orderby'        => 'title',
559
            'order'          => 'ASC',
560
            'posts_per_page' => '-1'
561
        )
562
    );
563
564
    $options = array();
565
    if ( $items ) {
566
        foreach ( $items as $item ) {
567
            $options[ $item->ID ] = esc_html( $item->post_title ) . wpinv_get_item_suffix( $item->ID, false );
568
        }
569
    }
570
571
    return $options;
572
}
573
574
function wpinv_html_checkbox( $args = array() ) {
575
    $defaults = array(
576
        'name'     => null,
577
        'current'  => null,
578
        'class'    => 'wpinv-checkbox',
579
        'options'  => array(
580
            'disabled' => false,
581
            'readonly' => false
582
        )
583
    );
584
585
    $args = wp_parse_args( $args, $defaults );
586
587
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
588
    $options = '';
589
    if ( ! empty( $args['options']['disabled'] ) ) {
590
        $options .= ' disabled="disabled"';
591
    } elseif ( ! empty( $args['options']['readonly'] ) ) {
592
        $options .= ' readonly';
593
    }
594
595
    $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 ) . ' />';
596
597
    return $output;
598
}
599
600
/**
601
 * Displays a hidden field.
602
 */
603
function getpaid_hidden_field( $name, $value ) {
604
    $name  = sanitize_text_field( $name );
605
    $value = esc_attr( $value );
606
607
    echo "<input type='hidden' name='$name' value='$value' />";
608
}
609
610
function wpinv_html_text( $args = array() ) {
611
    // Backwards compatibility
612
    if ( func_num_args() > 1 ) {
613
        $args = func_get_args();
614
615
        $name  = $args[0];
616
        $value = isset( $args[1] ) ? $args[1] : '';
617
        $label = isset( $args[2] ) ? $args[2] : '';
618
        $desc  = isset( $args[3] ) ? $args[3] : '';
619
    }
620
621
    $defaults = array(
622
        'id'           => '',
623
        'name'         => isset( $name )  ? $name  : 'text',
624
        'value'        => isset( $value ) ? $value : null,
625
        'label'        => isset( $label ) ? $label : null,
626
        'desc'         => isset( $desc )  ? $desc  : null,
627
        'placeholder'  => '',
628
        'class'        => 'regular-text',
629
        'disabled'     => false,
630
        'readonly'     => false,
631
        'required'     => false,
632
        'autocomplete' => '',
633
        'data'         => false
634
    );
635
636
    $args = wp_parse_args( $args, $defaults );
637
638
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
639
    $options = '';
640
    if( $args['required'] ) {
641
        $options .= ' required="required"';
642
    }
643
    if( $args['readonly'] ) {
644
        $options .= ' readonly';
645
    }
646
    if( $args['readonly'] ) {
647
        $options .= ' readonly';
648
    }
649
650
    $data = '';
651
    if ( !empty( $args['data'] ) ) {
652
        foreach ( $args['data'] as $key => $value ) {
653
            $data .= 'data-' . wpinv_sanitize_key( $key ) . '="' . esc_attr( $value ) . '" ';
654
        }
655
    }
656
657
    $output = '<span id="wpinv-' . wpinv_sanitize_key( $args['name'] ) . '-wrap">';
658
    $output .= '<label class="wpinv-label" for="' . wpinv_sanitize_key( $args['id'] ) . '">' . esc_html( $args['label'] ) . '</label>';
659
    if ( ! empty( $args['desc'] ) ) {
660
        $output .= '<span class="wpinv-description">' . esc_html( $args['desc'] ) . '</span>';
661
    }
662
663
    $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 ) . '/>';
664
665
    $output .= '</span>';
666
667
    return $output;
668
}
669
670
function wpinv_html_date_field( $args = array() ) {
671
    if( empty( $args['class'] ) ) {
672
        $args['class'] = 'wpiDatepicker';
673
    } elseif( ! strpos( $args['class'], 'wpiDatepicker' ) ) {
674
        $args['class'] .= ' wpiDatepicker';
675
    }
676
677
    return wpinv_html_text( $args );
678
}
679
680
function wpinv_html_textarea( $args = array() ) {
681
    $defaults = array(
682
        'name'        => 'textarea',
683
        'value'       => null,
684
        'label'       => null,
685
        'desc'        => null,
686
        'class'       => 'large-text',
687
        'disabled'    => false,
688
        'placeholder' => '',
689
    );
690
691
    $args = wp_parse_args( $args, $defaults );
692
693
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
694
    $disabled = '';
695
    if( $args['disabled'] ) {
696
        $disabled = ' disabled="disabled"';
697
    }
698
699
    $output = '<span id="wpinv-' . wpinv_sanitize_key( $args['name'] ) . '-wrap">';
700
    $output .= '<label class="wpinv-label" for="' . wpinv_sanitize_key( $args['name'] ) . '">' . esc_html( $args['label'] ) . '</label>';
701
    $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>';
702
703
    if ( ! empty( $args['desc'] ) ) {
704
        $output .= '<span class="wpinv-description">' . esc_html( $args['desc'] ) . '</span>';
705
    }
706
    $output .= '</span>';
707
708
    return $output;
709
}
710
711
function wpinv_html_ajax_user_search( $args = array() ) {
712
    $defaults = array(
713
        'name'        => 'user_id',
714
        'value'       => null,
715
        'placeholder' => __( 'Enter username', 'invoicing' ),
716
        'label'       => null,
717
        'desc'        => null,
718
        'class'       => '',
719
        'disabled'    => false,
720
        'autocomplete'=> 'off',
721
        'data'        => false
722
    );
723
724
    $args = wp_parse_args( $args, $defaults );
725
726
    $args['class'] = 'wpinv-ajax-user-search ' . $args['class'];
727
728
    $output  = '<span class="wpinv_user_search_wrap">';
729
        $output .= wpinv_html_text( $args );
730
        $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>';
731
    $output .= '</span>';
732
733
    return $output;
734
}
735
736
/**
737
 * @deprecated.
738
 */
739
function wpinv_ip_geolocation() {}
740
741
/**
742
 * Use our template to display invoices.
743
 * 
744
 * @param string $template the template that is currently being used.
745
 */
746
function wpinv_template( $template ) {
747
    global $post;
748
749
    if ( ! is_admin() && ( is_single() || is_404() ) && ! empty( $post->ID ) && getpaid_is_invoice_post_type( get_post_type( $post->ID ) ) ) {
750
751
        // If the user can view this invoice, display it.
752
        if ( wpinv_user_can_view_invoice( $post->ID ) ) {
753
754
            return wpinv_get_template_part( 'wpinv-invoice-print', false, false );
755
756
        // Else display an error message.
757
        } else {
758
759
            return wpinv_get_template_part( 'wpinv-invalid-access', false, false );
760
761
        }
762
763
    }
764
765
    return $template;
766
}
767
add_filter( 'template_include', 'wpinv_template', 10, 1 );
768
769
function wpinv_get_business_address() {
770
    $business_address   = wpinv_store_address();
771
    $business_address   = !empty( $business_address ) ? wpautop( wp_kses_post( $business_address ) ) : '';
772
    
773
    $business_address = $business_address ? '<div class="address">' . $business_address . '</div>' : '';
774
    
775
    return apply_filters( 'wpinv_get_business_address', $business_address );
776
}
777
778
/**
779
 * Displays the company address.
780
 */
781
function wpinv_display_from_address() {
782
    wpinv_get_template( 'invoice/company-address.php' );
783
}
784
add_action( 'getpaid_invoice_details_left', 'wpinv_display_from_address', 10 );
785
786
function wpinv_watermark( $id = 0 ) {
787
    $output = wpinv_get_watermark( $id );
788
    return apply_filters( 'wpinv_get_watermark', $output, $id );
789
}
790
791
function wpinv_get_watermark( $id ) {
792
    if ( !$id > 0 ) {
793
        return NULL;
794
    }
795
796
    $invoice = wpinv_get_invoice( $id );
797
    
798
    if ( !empty( $invoice ) && "wpi_invoice" === $invoice->post_type ) {
0 ignored issues
show
Bug Best Practice introduced by
The property post_type does not exist on WPInv_Invoice. Since you implemented __get, consider adding a @property annotation.
Loading history...
799
        if ( $invoice->is_paid() ) {
800
            return __( 'Paid', 'invoicing' );
801
        }
802
        if ( $invoice->is_refunded() ) {
803
            return __( 'Refunded', 'invoicing' );
804
        }
805
        if ( $invoice->has_status( array( 'wpi-cancelled' ) ) ) {
806
            return __( 'Cancelled', 'invoicing' );
807
        }
808
    }
809
    
810
    return NULL;
811
}
812
813
/**
814
 * @deprecated
815
 */
816
function wpinv_display_invoice_details( $invoice ) {
817
    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...
818
}
819
820
/**
821
 * Displays invoice meta.
822
 */
823
function getpaid_invoice_meta( $invoice ) {
824
825
    $invoice = new WPInv_Invoice( $invoice );
826
827
    // Ensure that we have an invoice.
828
    if ( 0 == $invoice->get_id() ) {
829
        return;
830
    }
831
832
    // Load the invoice meta.
833
    $meta    = array(
834
835
        'number' => array(
836
            'label' => sprintf(
837
                __( '%s Number', 'invoicing' ),
838
                ucfirst( $invoice->get_type() )
839
            ),
840
            'value' => sanitize_text_field( $invoice->get_number() ),
841
        ),
842
843
        'status' => array(
844
            'label' => sprintf(
845
                __( '%s Status', 'invoicing' ),
846
                ucfirst( $invoice->get_type() )
847
            ),
848
            'value' => sanitize_text_field( $invoice->get_status_nicename() ),
849
        ),
850
851
        'date' => array(
852
            'label' => sprintf(
853
                __( '%s Date', 'invoicing' ),
854
                ucfirst( $invoice->get_type() )
855
            ),
856
            'value' => getpaid_format_date( $invoice->get_created_date() ),
857
        ),
858
859
        'date_paid' => array(
860
            'label' => __( 'Paid On', 'invoicing' ),
861
            'value' => getpaid_format_date( $invoice->get_completed_date() ),
862
        ),
863
864
        'gateway'   => array(
865
            'label' => __( 'Payment Method', 'invoicing' ),
866
            'value' => sanitize_text_field( $invoice->get_gateway_title() ),
867
        ),
868
869
        'transaction_id' => array(
870
            'label' => __( 'Transaction ID', 'invoicing' ),
871
            'value' => sanitize_text_field( $invoice->get_transaction_id() ),
872
        ),
873
874
        'due_date'  => array(
875
            'label' => __( 'Due Date', 'invoicing' ),
876
            'value' => getpaid_format_date( $invoice->get_due_date() ),
877
        ),
878
879
        'vat_number' => array(
880
            'label' => sprintf(
881
                __( '%s Number', 'invoicing' ),
882
                getpaid_tax()->get_vat_name()
883
            ),
884
            'value' => sanitize_text_field( $invoice->get_vat_number() ),
885
        ),
886
887
    );
888
889
    // If it is not paid, remove the date of payment.
890
    if ( ! $invoice->is_paid() ) {
891
        unset( $meta[ 'date_paid' ] );
892
        unset( $meta[ 'transaction_id' ] );
893
    }
894
895
    if ( ! $invoice->is_paid() || 'none' == $invoice->get_gateway() ) {
896
        unset( $meta[ 'gateway' ] );
897
    }
898
899
    // Only display the due date if due dates are enabled.
900
    if ( ! $invoice->needs_payment() || ! wpinv_get_option( 'overdue_active' ) ) {
901
        unset( $meta[ 'due_date' ] );
902
    }
903
904
    // Only display the vat number if taxes are enabled.
905
    if ( ! wpinv_use_taxes() ) {
906
        unset( $meta[ 'vat_number' ] );
907
    }
908
909
    if ( $invoice->is_recurring() ) {
910
911
        // Link to the parent invoice.
912
        if ( $invoice->is_renewal() ) {
913
914
            $meta[ 'parent' ] = array(
915
916
                'label' => sprintf(
917
                    __( 'Parent %s', 'invoicing' ),
918
                    ucfirst( $invoice->get_type() )
919
                ),
920
921
                'value' => wpinv_invoice_link( $invoice->get_parent_id() ),
922
923
            );
924
925
        }
926
927
        $subscription = wpinv_get_subscription( $invoice );
928
929
        if ( ! empty ( $subscription ) ) {
930
931
            // Display the renewal date.
932
            if ( $subscription->is_active() && 'cancelled' != $subscription->status ) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $subscription->is_active() targeting WPInv_Subscription::is_active() 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...
933
934
                $meta[ 'renewal_date' ] = array(
935
936
                    'label' => __( 'Renews On', 'invoicing' ),
937
                    'value' => getpaid_format_date( $subscription->expiration ),
938
        
939
                );
940
941
            }
942
943
            if ( $invoice->is_parent() ) {
944
945
                // Display the recurring amount.
946
                $meta[ 'recurring_total' ] = array(
947
948
                    'label' => __( 'Recurring Amount', 'invoicing' ),
949
                    'value' => wpinv_price( wpinv_format_amount( $subscription->recurring_amount ), $invoice->get_currency() ),
950
        
951
                );
952
953
            }
954
            
955
        }
956
    }
957
958
    // Add the invoice total to the meta.
959
    $meta[ 'invoice_total' ] = array(
960
961
        'label' => __( 'Total Amount', 'invoicing' ),
962
        'value' => wpinv_price( wpinv_format_amount( $invoice->get_total() ), $invoice->get_currency() ),
963
964
    );
965
966
    // Provide a way for third party plugins to filter the meta.
967
    $meta = apply_filters( 'getpaid_invoice_meta_data', $meta, $invoice );
968
969
    wpinv_get_template( 'invoice/invoice-meta.php', compact( 'invoice', 'meta' ) );
970
971
}
972
add_action( 'getpaid_invoice_details_right', 'getpaid_invoice_meta', 10 );
973
974
/**
975
 * Retrieves the address markup to use on Invoices.
976
 * 
977
 * @since 1.0.13
978
 * @see `wpinv_get_full_address_format`
979
 * @see `wpinv_get_invoice_address_replacements`
980
 * @param array $billing_details customer's billing details
981
 * @param  string $separator How to separate address lines.
982
 * @return string
983
 */
984
function wpinv_get_invoice_address_markup( $billing_details, $separator = '<br/>' ) {
985
986
    // Retrieve the address markup...
987
    $country= empty( $billing_details['country'] ) ? '' : $billing_details['country'];
988
    $format = wpinv_get_full_address_format( $country );
989
990
    // ... and the replacements.
991
    $replacements = wpinv_get_invoice_address_replacements( $billing_details );
992
993
    $formatted_address = str_ireplace( array_keys( $replacements ), $replacements, $format );
994
    
995
	// Remove unavailable tags.
996
    $formatted_address = preg_replace( "/\{\{\w+\}\}/", '', $formatted_address );
997
998
    // Clean up white space.
999
	$formatted_address = preg_replace( '/  +/', ' ', trim( $formatted_address ) );
1000
    $formatted_address = preg_replace( '/\n\n+/', "\n", $formatted_address );
1001
    
1002
    // Break newlines apart and remove empty lines/trim commas and white space.
1003
	$formatted_address = array_filter( array_map( 'wpinv_trim_formatted_address_line', explode( "\n", $formatted_address ) ) );
1004
1005
    // Add html breaks.
1006
	$formatted_address = implode( $separator, $formatted_address );
1007
1008
	// We're done!
1009
	return $formatted_address;
1010
    
1011
}
1012
1013
/**
1014
 * Displays the billing address.
1015
 * 
1016
 * @param WPInv_Invoice $invoice
1017
 */
1018
function wpinv_display_to_address( $invoice = 0 ) {
1019
    if ( ! empty( $invoice ) ) {
1020
        wpinv_get_template( 'invoice/billing-address.php', compact( 'invoice' ) );
1021
    }
1022
}
1023
add_action( 'getpaid_invoice_details_left', 'wpinv_display_to_address', 40 );
1024
1025
1026
/**
1027
 * Displays invoice line items.
1028
 */
1029
function wpinv_display_line_items( $invoice_id = 0 ) {
1030
1031
    // Prepare the invoice.
1032
    $invoice = new WPInv_Invoice( $invoice_id );
1033
1034
    // Abort if there is no invoice.
1035
    if ( 0 == $invoice->get_id() ) {
1036
        return;
1037
    }
1038
1039
    // Line item columns.
1040
    $columns = getpaid_invoice_item_columns( $invoice );
1041
    $columns = apply_filters( 'getpaid_invoice_line_items_table_columns', $columns, $invoice );
1042
1043
    wpinv_get_template( 'invoice/line-items.php', compact( 'invoice', 'columns' ) );
1044
}
1045
add_action( 'getpaid_invoice_line_items', 'wpinv_display_line_items', 10 );
1046
1047
/**
1048
 * Displays invoice notices on invoices.
1049
 */
1050
function wpinv_display_invoice_notice() {
1051
1052
    $label  = wpinv_get_option( 'vat_invoice_notice_label' );
1053
    $notice = wpinv_get_option( 'vat_invoice_notice' );
1054
1055
    if ( empty( $label ) && empty( $notice ) ) {
1056
        return;
1057
    }
1058
1059
    echo '<div class="mt-4 mb-4 wpinv-vat-notice">';
1060
1061
    if ( ! empty( $label ) ) {
1062
        $label = sanitize_text_field( $label );
1063
        echo "<h5>$label</h5>";
1064
    }
1065
1066
    if ( ! empty( $notice ) ) {
1067
        echo '<small class="form-text text-muted">' . wpautop( wptexturize( $notice ) ) . '</small>';
1068
    }
1069
1070
    echo '</div>';
1071
}
1072
add_action( 'getpaid_invoice_line_items', 'wpinv_display_invoice_notice', 100 );
1073
1074
/**
1075
 * @param WPInv_Invoice $invoice
1076
 */
1077
function wpinv_display_invoice_notes( $invoice ) {
1078
1079
    // Retrieve the notes.
1080
    $notes = wpinv_get_invoice_notes( $invoice->get_id(), 'customer' );
1081
1082
    // Abort if we have non.
1083
    if ( empty( $notes ) ) {
1084
        return;
1085
    }
1086
1087
    // Echo the note.
1088
    echo '<div class="getpaid-invoice-notes-wrapper border position-relative w-100 mb-4 p-0">';
1089
    echo '<h3 class="getpaid-invoice-notes-title text-dark bg-light border-bottom m-0 d-block">' . __( 'Notes', 'invoicing' ) .'</h3>';
1090
    echo '<ul class="getpaid-invoice-notes mt-4 p-0">';
1091
1092
    foreach( $notes as $note ) {
1093
        wpinv_get_invoice_note_line_item( $note );
1094
    }
1095
1096
    echo '</ul>';
1097
    echo '</div>';
1098
}
1099
add_action( 'getpaid_invoice_line_items', 'wpinv_display_invoice_notes', 60 );
1100
1101
/**
1102
 * Loads scripts on our invoice templates.
1103
 */
1104
function wpinv_display_style() {
1105
1106
    // Make sure that all scripts have been loaded.
1107
    if ( ! did_action( 'wp_enqueue_scripts' ) ) {
1108
        do_action( 'wp_enqueue_scripts' );
1109
    }
1110
1111
    // Register the invoices style.
1112
    wp_register_style( 'wpinv-single-style', WPINV_PLUGIN_URL . 'assets/css/invoice.css', array(), filemtime( WPINV_PLUGIN_DIR . 'assets/css/invoice.css' ) );
1113
1114
    // Load required styles
1115
    wp_print_styles( 'open-sans' );
1116
    wp_print_styles( 'wpinv-single-style' );
1117
    wp_print_styles( 'ayecode-ui' );
1118
1119
    // Maybe load custom css.
1120
    $custom_css = wpinv_get_option( 'template_custom_css' );
1121
1122
    if ( isset( $custom_css ) && ! empty( $custom_css ) ) {
1123
        $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

1123
        $custom_css     = wp_kses( $custom_css, /** @scrutinizer ignore-type */ array( '\'', '\"' ) );
Loading history...
1124
        $custom_css     = str_replace( '&gt;', '>', $custom_css );
1125
        echo '<style type="text/css">';
1126
        echo $custom_css;
1127
        echo '</style>';
1128
    }
1129
1130
}
1131
add_action( 'wpinv_invoice_print_head', 'wpinv_display_style' );
1132
add_action( 'wpinv_invalid_invoice_head', 'wpinv_display_style' );
1133
1134
1135
/**
1136
 * Displays the checkout page.
1137
 */
1138
function wpinv_checkout_form() {
1139
    global $wpi_checkout_id;
1140
1141
    // Retrieve the current invoice.
1142
    $invoice_id = getpaid_get_current_invoice_id();
1143
1144
    if ( empty( $invoice_id ) ) {
1145
1146
        return aui()->alert(
1147
            array(
1148
                'type'    => 'warning',
1149
                'content' => __( 'Invalid invoice', 'invoicing' ),
1150
            )
1151
        );
1152
1153
    }
1154
1155
    // Can the user view this invoice?
1156
    if ( ! wpinv_user_can_view_invoice( $invoice_id ) ) {
1157
1158
        return aui()->alert(
1159
            array(
1160
                'type'    => 'warning',
1161
                'content' => __( 'You are not allowed to view this invoice', 'invoicing' ),
1162
            )
1163
        );
1164
1165
    }
1166
1167
    // Ensure that it is not yet paid for.
1168
    $invoice = new WPInv_Invoice( $invoice_id );
1169
1170
    // Maybe mark it as viewed.
1171
    getpaid_maybe_mark_invoice_as_viewed( $invoice );
1172
1173
    if ( $invoice->is_paid() ) {
1174
1175
        return aui()->alert(
1176
            array(
1177
                'type'    => 'success',
1178
                'content' => __( 'This invoice has already been paid.', 'invoicing' ),
1179
            )
1180
        );
1181
1182
    }
1183
1184
    // Set the global invoice id.
1185
    $wpi_checkout_id = $invoice_id;
1186
1187
    // We'll display this invoice via the default form.
1188
    $form = new GetPaid_Payment_Form( wpinv_get_default_payment_form() );
1189
1190
    if ( 0 == $form->get_id() ) {
1191
1192
        return aui()->alert(
1193
            array(
1194
                'type'    => 'warning',
1195
                'content' => __( 'Error loading the payment form', 'invoicing' ),
1196
            )
1197
        );
1198
1199
    }
1200
1201
    // Set the invoice.
1202
    $form->invoice = $invoice;
1203
    $form->set_items( $invoice->get_items() );
1204
1205
    // Generate the html.
1206
    return $form->get_html();
1207
1208
}
1209
1210
function wpinv_empty_cart_message() {
1211
	return apply_filters( 'wpinv_empty_cart_message', '<span class="wpinv_empty_cart">' . __( 'Your cart is empty.', 'invoicing' ) . '</span>' );
1212
}
1213
1214
/**
1215
 * Echoes the Empty Cart Message
1216
 *
1217
 * @since 1.0
1218
 * @return void
1219
 */
1220
function wpinv_empty_checkout_cart() {
1221
    echo aui()->alert(
1222
        array(
1223
            'type'    => 'warning',
1224
            'content' => wpinv_empty_cart_message(),
1225
        )
1226
    );
1227
}
1228
add_action( 'wpinv_cart_empty', 'wpinv_empty_checkout_cart' );
1229
1230
function wpinv_receipt_billing_address( $invoice_id = 0 ) {
1231
    $invoice = wpinv_get_invoice( $invoice_id );
1232
1233
    if ( empty( $invoice ) ) {
1234
        return NULL;
1235
    }
1236
1237
    $billing_details = $invoice->get_user_info();
1238
    $address_row = wpinv_get_invoice_address_markup( $billing_details );
1239
1240
    ob_start();
1241
    ?>
1242
    <table class="table table-bordered table-sm wpi-billing-details">
1243
        <tbody>
1244
            <tr class="wpi-receipt-name">
1245
                <th class="text-left"><?php _e( 'Name', 'invoicing' ); ?></th>
1246
                <td><?php echo esc_html( trim( $billing_details['first_name'] . ' ' . $billing_details['last_name'] ) ) ;?></td>
1247
            </tr>
1248
            <tr class="wpi-receipt-email">
1249
                <th class="text-left"><?php _e( 'Email', 'invoicing' ); ?></th>
1250
                <td><?php echo $billing_details['email'] ;?></td>
1251
            </tr>
1252
            <tr class="wpi-receipt-address">
1253
                <th class="text-left"><?php _e( 'Address', 'invoicing' ); ?></th>
1254
                <td><?php echo $address_row ;?></td>
1255
            </tr>
1256
            <?php if ( $billing_details['phone'] ) { ?>
1257
            <tr class="wpi-receipt-phone">
1258
                <th class="text-left"><?php _e( 'Phone', 'invoicing' ); ?></th>
1259
                <td><?php echo esc_html( $billing_details['phone'] ) ;?></td>
1260
            </tr>
1261
            <?php } ?>
1262
        </tbody>
1263
    </table>
1264
    <?php
1265
    $output = ob_get_clean();
1266
    
1267
    $output = apply_filters( 'wpinv_receipt_billing_address', $output, $invoice_id );
1268
1269
    echo $output;
1270
}
1271
1272
/**
1273
 * Filters the receipt page.
1274
 */
1275
function wpinv_filter_success_page_content( $content ) {
1276
1277
    // Ensure this is our page.
1278
    if ( isset( $_GET['payment-confirm'] ) && wpinv_is_success_page() ) {
1279
1280
        $gateway = sanitize_text_field( $_GET['payment-confirm'] );
1281
        return apply_filters( "wpinv_payment_confirm_$gateway", $content );
1282
1283
    }
1284
1285
    return $content;
1286
}
1287
add_filter( 'the_content', 'wpinv_filter_success_page_content', 99999 );
1288
1289
function wpinv_invoice_link( $invoice_id ) {
1290
    $invoice = wpinv_get_invoice( $invoice_id );
1291
1292
    if ( empty( $invoice ) ) {
1293
        return NULL;
1294
    }
1295
1296
    $invoice_link = '<a href="' . esc_url( $invoice->get_view_url() ) . '">' . $invoice->get_number() . '</a>';
1297
1298
    return apply_filters( 'wpinv_get_invoice_link', $invoice_link, $invoice );
1299
}
1300
1301
function wpinv_invoice_subscription_details( $invoice ) {
1302
    if ( !empty( $invoice ) && $invoice->is_recurring() && ! wpinv_is_subscription_payment( $invoice ) ) {
1303
        $subscription = wpinv_get_subscription( $invoice, true );
0 ignored issues
show
Unused Code introduced by
The call to wpinv_get_subscription() has too many arguments starting with true. ( Ignorable by Annotation )

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

1303
        $subscription = /** @scrutinizer ignore-call */ wpinv_get_subscription( $invoice, true );

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...
1304
1305
        if ( empty( $subscription ) ) {
1306
            return;
1307
        }
1308
1309
        $frequency = WPInv_Subscriptions::wpinv_get_pretty_subscription_frequency($subscription->period, $subscription->frequency);
1310
        $billing = wpinv_price(wpinv_format_amount($subscription->recurring_amount), $invoice->get_currency() ) . ' / ' . $frequency;
1311
        $initial = wpinv_price(wpinv_format_amount($subscription->initial_amount), $invoice->get_currency() );
1312
1313
        $payments = $subscription->get_child_payments();
1314
        ?>
1315
        <div class="wpinv-subscriptions-details">
1316
            <h3 class="wpinv-subscriptions-t"><?php echo apply_filters( 'wpinv_subscription_details_title', __( 'Subscription Details', 'invoicing' ) ); ?></h3>
1317
            <table class="table">
1318
                <thead>
1319
                    <tr>
1320
                        <th><?php _e( 'Billing Cycle', 'invoicing' ) ;?></th>
1321
                        <th><?php _e( 'Start Date', 'invoicing' ) ;?></th>
1322
                        <th><?php _e( 'Expiration Date', 'invoicing' ) ;?></th>
1323
                        <th class="text-center"><?php _e( 'Times Billed', 'invoicing' ) ;?></th>
1324
                        <th class="text-center"><?php _e( 'Status', 'invoicing' ) ;?></th>
1325
                    </tr>
1326
                </thead>
1327
                <tbody>
1328
                    <tr>
1329
                        <td><?php printf(_x('%s then %s', 'Initial subscription amount then billing cycle and amount', 'invoicing'), $initial, $billing); ?></td>
1330
                        <td><?php echo date_i18n(get_option('date_format'), strtotime($subscription->created, current_time('timestamp'))); ?></td>
0 ignored issues
show
Bug introduced by
It seems like get_option('date_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

1330
                        <td><?php echo date_i18n(/** @scrutinizer ignore-type */ get_option('date_format'), strtotime($subscription->created, current_time('timestamp'))); ?></td>
Loading history...
1331
                        <td><?php echo date_i18n(get_option('date_format'), strtotime($subscription->expiration, current_time('timestamp'))); ?></td>
1332
                        <td class="text-center"><?php echo $subscription->get_times_billed() . ' / ' . (($subscription->bill_times == 0) ? __( 'Until Cancelled', 'invoicing' ) : $subscription->bill_times); ?></td>
1333
                        <td class="text-center wpi-sub-status"><?php echo $subscription->get_status_label(); ?></td>
1334
                    </tr>
1335
                </tbody>
1336
            </table>
1337
        </div>
1338
        <?php if ( !empty( $payments ) ) { ?>
1339
        <div class="wpinv-renewal-payments">
1340
            <h3 class="wpinv-renewals-t"><?php echo apply_filters( 'wpinv_renewal_payments_title', __( 'Renewal Payments', 'invoicing' ) ); ?></h3>
1341
            <table class="table">
1342
                <thead>
1343
                    <tr>
1344
                        <th>#</th>
1345
                        <th><?php _e( 'Invoice', 'invoicing' ) ;?></th>
1346
                        <th><?php _e( 'Date', 'invoicing' ) ;?></th>
1347
                        <th class="text-right"><?php _e( 'Amount', 'invoicing' ) ;?></th>
1348
                    </tr>
1349
                </thead>
1350
                <tbody>
1351
                    <?php
1352
                        $i = 1;
1353
                        foreach ( $payments as $payment ) {
1354
                            $invoice_id = $payment->ID;
1355
                    ?>
1356
                    <tr>
1357
                        <th scope="row"><?php echo $i;?></th>
1358
                        <td><?php echo wpinv_invoice_link( $invoice_id ) ;?></td>
1359
                        <td><?php echo$invoice->get_date_created(); ?></td>
1360
                        <td class="text-right"><?php echo wpinv_price( wpinv_format_amount( $invoice->get_total() ), $invoice->get_currency() ); ?></td>
1361
                    </tr>
1362
                    <?php $i++; } ?>
1363
                </tbody>
1364
            </table>
1365
        </div>
1366
        <?php } ?>
1367
        <?php
1368
    }
1369
}
1370
add_action( 'getpaid_invoice_line_items', 'wpinv_invoice_subscription_details', 20 );
1371
1372
function wpinv_cart_total_label( $label, $invoice ) {
1373
    if ( empty( $invoice ) ) {
1374
        return $label;
1375
    }
1376
1377
    $prefix_label = '';
1378
    if ( $invoice->is_parent() && $item_id = $invoice->get_recurring() ) {
0 ignored issues
show
Unused Code introduced by
The assignment to $item_id is dead and can be removed.
Loading history...
1379
        $prefix_label   = '<span class="label label-primary label-recurring">' . __( 'Recurring Payment', 'invoicing' ) . '</span> ' . wpinv_subscription_payment_desc( $invoice );
1380
    } else if ( $invoice->is_renewal() ) {
1381
        $prefix_label   = '<span class="label label-primary label-renewal">' . __( 'Renewal Payment', 'invoicing' ) . '</span> ';        
1382
    }
1383
1384
    if ( $prefix_label != '' ) {
1385
        $label  = '<span class="wpinv-cart-sub-desc">' . $prefix_label . '</span> ' . $label;
1386
    }
1387
1388
    return $label;
1389
}
1390
add_filter( 'wpinv_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
1391
add_filter( 'wpinv_email_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
1392
add_filter( 'wpinv_print_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
1393
1394
function wpinv_get_invoice_note_line_item( $note, $echo = true ) {
1395
    if ( empty( $note ) ) {
1396
        return NULL;
1397
    }
1398
1399
    if ( is_int( $note ) ) {
1400
        $note = get_comment( $note );
1401
    }
1402
1403
    if ( !( is_object( $note ) && is_a( $note, 'WP_Comment' ) ) ) {
1404
        return NULL;
1405
    }
1406
1407
    $note_classes   = array( 'note' );
1408
    $note_classes[] = get_comment_meta( $note->comment_ID, '_wpi_customer_note', true ) ? 'customer-note' : '';
1409
    $note_classes[] = $note->comment_author === 'System' ? 'system-note' : '';
1410
    $note_classes   = apply_filters( 'wpinv_invoice_note_class', array_filter( $note_classes ), $note );
1411
    $note_classes   = !empty( $note_classes ) ? implode( ' ', $note_classes ) : '';
1412
1413
    ob_start();
1414
    ?>
1415
    <li rel="<?php echo absint( $note->comment_ID ) ; ?>" class="<?php echo esc_attr( $note_classes ); ?> mt-4 pl-3 pr-3">
1416
        <div class="note_content bg-light border position-relative p-4">
1417
1418
            <?php echo wpautop( wptexturize( wp_kses_post( $note->comment_content ) ) ); ?>
1419
1420
            <?php if ( ! is_admin() ) : ?>
1421
                <em class="meta position-absolute form-text">
1422
                    <?php
1423
                        printf(
1424
                            __( '%1$s - %2$s at %3$s', 'invoicing' ),
1425
                            $note->comment_author,
1426
                            date_i18n( get_option( 'date_format' ), strtotime( $note->comment_date ) ),
0 ignored issues
show
Bug introduced by
It seems like get_option('date_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

1426
                            date_i18n( /** @scrutinizer ignore-type */ get_option( 'date_format' ), strtotime( $note->comment_date ) ),
Loading history...
1427
                            date_i18n( get_option( 'time_format' ), strtotime( $note->comment_date ) )
1428
                        );
1429
                    ?>
1430
                </em>
1431
            <?php endif; ?>
1432
1433
        </div>
1434
1435
        <?php if ( is_admin() ) : ?>
1436
1437
            <p class="meta px-4 py-2">
1438
                <abbr class="exact-date" title="<?php echo esc_attr( $note->comment_date ); ?>"><?php printf( __( '%1$s - %2$s at %3$s', 'invoicing' ), $note->comment_author, date_i18n( get_option( 'date_format' ), strtotime( $note->comment_date ) ), date_i18n( get_option( 'time_format' ), strtotime( $note->comment_date ) ) ); ?></abbr>&nbsp;&nbsp;
1439
                <?php if ( $note->comment_author !== 'System' && wpinv_current_user_can_manage_invoicing() ) { ?>
1440
                    <a href="#" class="delete_note"><?php _e( 'Delete note', 'invoicing' ); ?></a>
1441
                <?php } ?>
1442
            </p>
1443
1444
        <?php endif; ?>
1445
        
1446
    </li>
1447
    <?php
1448
    $note_content = ob_get_clean();
1449
    $note_content = apply_filters( 'wpinv_get_invoice_note_line_item', $note_content, $note, $echo );
1450
1451
    if ( $echo ) {
1452
        echo $note_content;
1453
    } else {
1454
        return $note_content;
1455
    }
1456
}
1457
1458
function wpinv_invalid_invoice_content() {
1459
    global $post;
1460
1461
    $invoice = wpinv_get_invoice( $post->ID );
1462
1463
    $error = __( 'This invoice is only viewable by clicking on the invoice link that was sent to you via email.', 'invoicing' );
1464
    if ( !empty( $invoice->get_id() ) && $invoice->has_status( array_keys( wpinv_get_invoice_statuses() ) ) ) {
1465
        if ( is_user_logged_in() ) {
1466
            if ( wpinv_require_login_to_checkout() ) {
1467
                if ( isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
1468
                    $error = __( 'You are not allowed to view this invoice.', 'invoicing' );
1469
                }
1470
            }
1471
        } else {
1472
            if ( wpinv_require_login_to_checkout() ) {
1473
                if ( isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
1474
                    $error = __( 'You must be logged in to view this invoice.', 'invoicing' );
1475
                }
1476
            }
1477
        }
1478
    } else {
1479
        $error = __( 'This invoice is deleted or does not exist.', 'invoicing' );
1480
    }
1481
    ?>
1482
    <div class="row wpinv-row-invalid">
1483
        <div class="col-md-6 col-md-offset-3 wpinv-message error">
1484
            <h3><?php _e( 'Access Denied', 'invoicing' ); ?></h3>
1485
            <p class="wpinv-msg-text"><?php echo $error; ?></p>
1486
        </div>
1487
    </div>
1488
    <?php
1489
}
1490
add_action( 'wpinv_invalid_invoice_content', 'wpinv_invalid_invoice_content' );
1491
1492
/**
1493
 * Function to get privacy policy text.
1494
 *
1495
 * @since 1.0.13
1496
 * @return string
1497
 */
1498
function wpinv_get_policy_text() {
1499
    $privacy_page_id = get_option( 'wp_page_for_privacy_policy', 0 );
1500
1501
    $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]' ));
1502
1503
    if(!$privacy_page_id){
1504
        $privacy_page_id = wpinv_get_option( 'privacy_page', 0 );
1505
    }
1506
1507
    $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

1507
    $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...
1508
1509
    $find_replace = array(
1510
        '[wpinv_privacy_policy]' => $privacy_link,
1511
    );
1512
1513
    $privacy_text = str_replace( array_keys( $find_replace ), array_values( $find_replace ), $text );
1514
1515
    return wp_kses_post(wpautop($privacy_text));
1516
}
1517
1518
1519
/**
1520
 * Allows the user to set their own price for an invoice item
1521
 */
1522
function wpinv_checkout_cart_item_name_your_price( $cart_item, $key ) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

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

1522
function wpinv_checkout_cart_item_name_your_price( $cart_item, /** @scrutinizer ignore-unused */ $key ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1523
    
1524
    //Ensure we have an item id
1525
    if(! is_array( $cart_item ) || empty( $cart_item['id'] ) ) {
1526
        return;
1527
    }
1528
1529
    //Fetch the item
1530
    $item_id = $cart_item['id'];
1531
    $item    = new WPInv_Item( $item_id );
1532
    
1533
    if(! $item->supports_dynamic_pricing() || !$item->get_is_dynamic_pricing() ) {
1534
        return;
1535
    }
1536
1537
    //Fetch the dynamic pricing "strings"
1538
    $suggested_price_text = esc_html( wpinv_get_option( 'suggested_price_text', __( 'Suggested Price:', 'invoicing' ) ) );
1539
    $minimum_price_text   = esc_html( wpinv_get_option( 'minimum_price_text', __( 'Minimum Price:', 'invoicing' ) ) );
1540
    $name_your_price_text = esc_html( wpinv_get_option( 'name_your_price_text', __( 'Name Your Price', 'invoicing' ) ) );
1541
1542
    //Display a "name_your_price" button
1543
    echo " &mdash; <a href='#' class='wpinv-name-your-price-frontend small'>$name_your_price_text</a></div>";
1544
1545
    //Display a name_your_price form
1546
    echo '<div class="name-your-price-miniform">';
1547
    
1548
    //Maybe display the recommended price
1549
    if( $item->get_price() > 0 && !empty( $suggested_price_text ) ) {
1550
        $suggested_price = $item->get_the_price();
1551
        echo "<div>$suggested_price_text &mdash; $suggested_price</div>";
1552
    }
1553
1554
    //Display the update price form
1555
    $symbol         = wpinv_currency_symbol();
1556
    $position       = wpinv_currency_position();
1557
    $minimum        = esc_attr( $item->get_minimum_price() );
1558
    $price          = esc_attr( $cart_item['item_price'] );
1559
    $update         = esc_attr__( "Update", 'invoicing' );
1560
1561
    //Ensure it supports dynamic prici
1562
    if( $price < $minimum ) {
1563
        $price = $minimum;
1564
    }
1565
1566
    echo '<label>';
1567
    echo $position != 'right' ? $symbol . '&nbsp;' : '';
0 ignored issues
show
Bug introduced by
Are you sure $symbol of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

1567
    echo $position != 'right' ? /** @scrutinizer ignore-type */ $symbol . '&nbsp;' : '';
Loading history...
1568
    echo "<input type='number' min='$minimum' placeholder='$price' value='$price' class='wpi-field-price' />";
1569
    echo $position == 'right' ? '&nbsp;' . $symbol : '' ;
1570
    echo "</label>";
1571
    echo "<input type='hidden' value='$item_id' class='wpi-field-item' />";
1572
    echo "<a class='btn btn-success wpinv-submit wpinv-update-dynamic-price-frontend'>$update</a>";
1573
1574
    //Maybe display the minimum price
1575
    if( $item->get_minimum_price() > 0 && !empty( $minimum_price_text ) ) {
1576
        $minimum_price = wpinv_price( wpinv_format_amount( $item->get_minimum_price() ) );
1577
        echo "<div>$minimum_price_text &mdash; $minimum_price</div>";
1578
    }
1579
1580
    echo "</div>";
1581
1582
}
1583
add_action( 'wpinv_checkout_cart_item_price_after', 'wpinv_checkout_cart_item_name_your_price', 10, 2 );
1584
1585
function wpinv_oxygen_fix_conflict() {
1586
    global $ct_ignore_post_types;
1587
1588
    if ( ! is_array( $ct_ignore_post_types ) ) {
1589
        $ct_ignore_post_types = array();
1590
    }
1591
1592
    $post_types = array( 'wpi_discount', 'wpi_invoice', 'wpi_item' );
1593
1594
    foreach ( $post_types as $post_type ) {
1595
        $ct_ignore_post_types[] = $post_type;
1596
1597
        // Ignore post type
1598
        add_filter( 'pre_option_oxygen_vsb_ignore_post_type_' . $post_type, '__return_true', 999 );
1599
    }
1600
1601
    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

1601
    /** @scrutinizer ignore-call */ 
1602
    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...
1602
    add_filter( 'template_include', 'wpinv_template', 999, 1 );
1603
}
1604
1605
/**
1606
 * Helper function to display a payment form on the frontend.
1607
 * 
1608
 * @param GetPaid_Payment_Form $form
1609
 */
1610
function getpaid_display_payment_form( $form ) {
1611
1612
    if ( is_numeric( $form ) ) {
0 ignored issues
show
introduced by
The condition is_numeric($form) is always false.
Loading history...
1613
        $form = new GetPaid_Payment_Form( $form );
1614
    }
1615
1616
    $form->display();
1617
1618
}
1619
1620
/**
1621
 * Helper function to display a item payment form on the frontend.
1622
 */
1623
function getpaid_display_item_payment_form( $items ) {
1624
    global $invoicing;
1625
1626
    foreach ( array_keys( $items ) as $id ) {
1627
	    if ( 'publish' != get_post_status( $id ) ) {
1628
		    unset( $items[ $id ] );
1629
	    }
1630
    }
1631
1632
    if ( empty( $items ) ) {
1633
		return aui()->alert(
1634
			array(
1635
				'type'    => 'warning',
1636
				'content' => __( 'No published items found', 'invoicing' ),
1637
			)
1638
		);
1639
    }
1640
1641
    $item_key = getpaid_convert_items_to_string( $items );
1642
1643
    // Get the form elements and items.
1644
    $form     = wpinv_get_default_payment_form();
1645
	$elements = $invoicing->form_elements->get_form_elements( $form );
1646
	$items    = $invoicing->form_elements->convert_normal_items( $items );
1647
1648
	ob_start();
1649
	echo "<form class='wpinv_payment_form'>";
1650
	do_action( 'wpinv_payment_form_top' );
1651
    echo "<input type='hidden' name='form_id' value='$form'/>";
1652
    echo "<input type='hidden' name='form_items' value='$item_key'/>";
1653
	wp_nonce_field( 'wpinv_payment_form', 'wpinv_payment_form' );
1654
	wp_nonce_field( 'vat_validation', '_wpi_nonce' );
1655
1656
	foreach ( $elements as $element ) {
1657
		do_action( 'wpinv_frontend_render_payment_form_element', $element, $items, $form );
1658
		do_action( "wpinv_frontend_render_payment_form_{$element['type']}", $element, $items, $form );
1659
	}
1660
1661
	echo "<div class='wpinv_payment_form_errors alert alert-danger d-none'></div>";
1662
	do_action( 'wpinv_payment_form_bottom' );
1663
	echo '</form>';
1664
1665
	$content = ob_get_clean();
1666
	return str_replace( 'sr-only', '', $content );
1667
}
1668
1669
/**
1670
 * Helper function to display an invoice payment form on the frontend.
1671
 */
1672
function getpaid_display_invoice_payment_form( $invoice_id ) {
1673
    global $invoicing;
1674
1675
    $invoice = wpinv_get_invoice( $invoice_id );
1676
1677
    if ( empty( $invoice ) ) {
1678
		return aui()->alert(
1679
			array(
1680
				'type'    => 'warning',
1681
				'content' => __( 'Invoice not found', 'invoicing' ),
1682
			)
1683
		);
1684
    }
1685
1686
    if ( $invoice->is_paid() ) {
1687
		return aui()->alert(
1688
			array(
1689
				'type'    => 'warning',
1690
				'content' => __( 'Invoice has already been paid', 'invoicing' ),
1691
			)
1692
		);
1693
    }
1694
1695
    // Get the form elements and items.
1696
    $form     = wpinv_get_default_payment_form();
1697
	$elements = $invoicing->form_elements->get_form_elements( $form );
1698
	$items    = $invoicing->form_elements->convert_checkout_items( $invoice->cart_details, $invoice );
0 ignored issues
show
Bug Best Practice introduced by
The property cart_details does not exist on WPInv_Invoice. Since you implemented __get, consider adding a @property annotation.
Loading history...
1699
1700
	ob_start();
1701
	echo "<form class='wpinv_payment_form'>";
1702
	do_action( 'wpinv_payment_form_top' );
1703
    echo "<input type='hidden' name='form_id' value='$form'/>";
1704
    echo "<input type='hidden' name='invoice_id' value='$invoice_id'/>";
1705
	wp_nonce_field( 'wpinv_payment_form', 'wpinv_payment_form' );
1706
	wp_nonce_field( 'vat_validation', '_wpi_nonce' );
1707
1708
	foreach ( $elements as $element ) {
1709
		do_action( 'wpinv_frontend_render_payment_form_element', $element, $items, $form );
1710
		do_action( "wpinv_frontend_render_payment_form_{$element['type']}", $element, $items, $form );
1711
	}
1712
1713
	echo "<div class='wpinv_payment_form_errors alert alert-danger d-none'></div>";
1714
	do_action( 'wpinv_payment_form_bottom' );
1715
	echo '</form>';
1716
1717
	$content = ob_get_clean();
1718
	return str_replace( 'sr-only', '', $content );
1719
}
1720
1721
/**
1722
 * Helper function to convert item string to array.
1723
 */
1724
function getpaid_convert_items_to_array( $items ) {
1725
    $items    = array_filter( array_map( 'trim', explode( ',', $items ) ) );
1726
    $prepared = array();
1727
1728
    foreach ( $items as $item ) {
1729
        $data = array_map( 'trim', explode( '|', $item ) );
1730
1731
        if ( empty( $data[0] ) || ! is_numeric( $data[0] ) ) {
1732
            continue;
1733
        }
1734
1735
        $quantity = 1;
1736
        if ( isset( $data[1] ) && is_numeric( $data[1] ) ) {
1737
            $quantity = $data[1];
1738
        }
1739
1740
        $prepared[ $data[0] ] = $quantity;
1741
1742
    }
1743
1744
    return $prepared;
1745
}
1746
1747
/**
1748
 * Helper function to convert item array to string.
1749
 */
1750
function getpaid_convert_items_to_string( $items ) {
1751
    $prepared = array();
1752
1753
    foreach ( $items as $item => $quantity ) {
1754
        $prepared[] = "$item|$quantity";
1755
    }
1756
    return implode( ',', $prepared );
1757
}
1758
1759
/**
1760
 * Helper function to display a payment item.
1761
 * 
1762
 * Provide a label and one of $form, $items or $invoice.
1763
 */
1764
function getpaid_get_payment_button( $label, $form = null, $items = null, $invoice = null ) {
1765
    $label = sanitize_text_field( $label );
1766
    $nonce = wp_create_nonce('getpaid_ajax_form');
1767
1768
    if ( ! empty( $form ) ) {
1769
        $form  = esc_attr( $form );
1770
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-form='$form'>$label</button>"; 
1771
    }
1772
	
1773
	if ( ! empty( $items ) ) {
1774
        $items  = esc_attr( $items );
1775
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-item='$items'>$label</button>"; 
1776
    }
1777
    
1778
    if ( ! empty( $invoice ) ) {
1779
        $invoice  = esc_attr( $invoice );
1780
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-invoice='$invoice'>$label</button>"; 
1781
    }
1782
1783
}
1784
1785
/**
1786
 * Display invoice description before line items.
1787
 *
1788
 * @param WPInv_Invoice $invoice
1789
 */
1790
function getpaid_the_invoice_description( $invoice ) {
1791
    $description = $invoice->get_description();
1792
1793
    if ( empty( $description ) ) {
1794
        return;
1795
    }
1796
1797
    $description = wp_kses_post( $description );
1798
    echo "<small class='getpaid-invoice-description text-dark p-2 form-text'><em>$description</em></small>";
1799
}
1800
add_action( 'getpaid_invoice_line_items', 'getpaid_the_invoice_description', 100 );
1801
1802
/**
1803
 * Render element on a form.
1804
 *
1805
 * @param array $element
1806
 * @param GetPaid_Payment_Form $form
1807
 */
1808
function getpaid_payment_form_element( $element, $form ) {
1809
1810
    // Set up the args.
1811
    $element_type    = trim( $element['type'] );
1812
    $element['form'] = $form;
1813
    extract( $element );
1814
1815
    // Try to locate the appropriate template.
1816
    $located = wpinv_locate_template( "payment-forms/elements/$element_type.php" );
1817
    
1818
    // Abort if this is not our element.
1819
    if ( empty( $located ) || ! file_exists( $located ) ) {
1820
        return;
1821
    }
1822
1823
    // Generate the class and id of the element.
1824
    $wrapper_class = 'getpaid-payment-form-element-' . trim( esc_attr( $element_type ) );
1825
    $id            = isset( $id ) ? $id : uniqid( 'gp' );
1826
1827
    // Echo the opening wrapper.
1828
    echo "<div class='getpaid-payment-form-element $wrapper_class'>";
1829
1830
    // Fires before displaying a given element type's content.
1831
    do_action( "getpaid_before_payment_form_{$element_type}_element", $element, $form );
1832
1833
    // Include the template for the element.
1834
    include $located;
1835
1836
    // Fires after displaying a given element type's content.
1837
    do_action( "getpaid_payment_form_{$element_type}_element", $element, $form );
1838
1839
    // Echo the closing wrapper.
1840
    echo '</div>';
1841
}
1842
add_action( 'getpaid_payment_form_element', 'getpaid_payment_form_element', 10, 2 );
1843
1844
/**
1845
 * Shows a list of gateways that support recurring payments.
1846
 */
1847
function wpinv_get_recurring_gateways_text() {
1848
    $gateways = array();
1849
1850
    foreach ( wpinv_get_payment_gateways() as $key => $gateway ) {
1851
        if ( wpinv_gateway_support_subscription( $key ) ) {
1852
            $gateways[] = sanitize_text_field( $gateway['admin_label'] );
1853
        }
1854
    }
1855
1856
    if ( empty( $gateways ) ) {
1857
        return "<span class='form-text text-danger'>" . __( 'No active gateways support subscription payments.', 'invoicing' ) ."</span>";
1858
    }
1859
1860
    return "<span class='form-text text-muted'>" . wp_sprintf( __( 'Subscription payments only supported by: %s', 'invoicing' ), implode( ', ', $gateways ) ) ."</span>";
1861
1862
}
1863
1864
/**
1865
 * Returns the template.
1866
 * 
1867
 * @return GetPaid_Template
1868
 */
1869
function getpaid_template() {
1870
    return getpaid()->get( 'template' );
1871
}
1872