Completed
Push — master ( f597b6...60f62d )
by Brian
03:50 queued 03:47
created

getpaid_invoice_footer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
9
// MUST have WordPress.
10
if ( !defined( 'WPINC' ) ) {
11
    exit( 'Do NOT access this file directly: ' . basename( __FILE__ ) );
12
}
13
14
if ( !is_admin() ) {
15
    add_filter( 'template_include', 'wpinv_template', 10, 1 );
16
}
17
18
function wpinv_template_path() {
19
    return apply_filters( 'wpinv_template_path', wpinv_get_theme_template_dir_name() );
20
}
21
22
/**
23
 * Displays an invoice.
24
 * 
25
 * @param WPInv_Invoice $invoice.
26
 */
27
function getpaid_invoice( $invoice ) {
28
    if ( ! empty( $invoice ) ) {
29
        wpinv_get_template( 'invoice/invoice.php', compact( 'invoice' ) );
30
    }
31
}
32
add_action( 'getpaid_invoice', 'getpaid_invoice' );
33
34
/**
35
 * Displays the invoice footer.
36
 */
37
function getpaid_invoice_footer( $invoice ) {
38
    if ( ! empty( $invoice ) ) {
39
        wpinv_get_template( 'invoice/footer.php', compact( 'invoice' ) );
40
    }
41
}
42
add_action( 'getpaid_invoice_footer', 'getpaid_invoice_footer', 10 );
43
44
/**
45
 * Displays the invoice top bar.
46
 */
47
function getpaid_invoice_header( $invoice ) {
48
    if ( ! empty( $invoice ) ) {
49
        wpinv_get_template( 'invoice/header.php', compact( 'invoice' ) );
50
    }
51
}
52
add_action( 'getpaid_invoice_header', 'getpaid_invoice_header', 10 );
53
54
/**
55
 * Displays actions on the left side of the header.
56
 */
57
function getpaid_invoice_header_left_actions( $invoice ) {
58
    if ( ! empty( $invoice ) ) {
59
        wpinv_get_template( 'invoice/header-left-actions.php', compact( 'invoice' ) );
60
    }
61
}
62
add_action( 'getpaid_invoice_header_left', 'getpaid_invoice_header_left_actions', 10 );
63
64
/**
65
 * Displays actions on the right side of the invoice top bar.
66
 */
67
function getpaid_invoice_header_right_actions( $invoice ) {
68
    if ( ! empty( $invoice ) ) {
69
        wpinv_get_template( 'invoice/header-right-actions.php', compact( 'invoice' ) );
70
    }
71
}
72
add_action( 'getpaid_invoice_header_right', 'getpaid_invoice_header_right_actions', 10 );
73
74
/**
75
 * Displays the invoice title, watermark, logo etc.
76
 */
77
function getpaid_invoice_details_top( $invoice ) {
78
    if ( ! empty( $invoice ) ) {
79
        wpinv_get_template( 'invoice/details-top.php', compact( 'invoice' ) );
80
    }
81
}
82
add_action( 'getpaid_invoice_details', 'getpaid_invoice_details_top', 10 );
83
84
/**
85
 * Displays the company logo.
86
 */
87
function getpaid_invoice_logo( $invoice ) {
88
    if ( ! empty( $invoice ) ) {
89
        wpinv_get_template( 'invoice/invoice-logo.php', compact( 'invoice' ) );
90
    }
91
}
92
add_action( 'getpaid_invoice_details_top_left', 'getpaid_invoice_logo' );
93
94
/**
95
 * Displays the type of invoice.
96
 */
97
function getpaid_invoice_type( $invoice ) {
98
    if ( ! empty( $invoice ) ) {
99
        wpinv_get_template( 'invoice/invoice-type.php', compact( 'invoice' ) );
100
    }
101
}
102
add_action( 'getpaid_invoice_details_top_right', 'getpaid_invoice_type' );
103
104
/**
105
 * Displays the invoice details.
106
 */
107
function getpaid_invoice_details_main( $invoice ) {
108
    if ( ! empty( $invoice ) ) {
109
        wpinv_get_template( 'invoice/details.php', compact( 'invoice' ) );
110
    }
111
}
112
add_action( 'getpaid_invoice_details', 'getpaid_invoice_details_main', 300 );
113
114
function wpinv_before_invoice_content( $content ) {
115
    global $post;
116
117
    if ( !empty( $post ) && $post->post_type == 'wpi_invoice' && is_singular( 'wpi_invoice' ) && is_main_query() ) {
118
        ob_start();
119
        do_action( 'wpinv_before_invoice_content', $post->ID );
120
        $content = ob_get_clean() . $content;
121
    }
122
123
    return $content;
124
}
125
add_filter( 'the_content', 'wpinv_before_invoice_content' );
126
127
function wpinv_after_invoice_content( $content ) {
128
    global $post;
129
130
    if ( !empty( $post ) && $post->post_type == 'wpi_invoice' && is_singular( 'wpi_invoice' ) && is_main_query() ) {
131
        ob_start();
132
        do_action( 'wpinv_after_invoice_content', $post->ID );
133
        $content .= ob_get_clean();
134
    }
135
136
    return $content;
137
}
138
add_filter( 'the_content', 'wpinv_after_invoice_content' );
139
140
function wpinv_get_templates_dir() {
141
    return WPINV_PLUGIN_DIR . 'templates';
142
}
143
144
function wpinv_get_templates_url() {
145
    return WPINV_PLUGIN_URL . 'templates';
146
}
147
148
function wpinv_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
149
    if ( ! empty( $args ) && is_array( $args ) ) {
150
		extract( $args );
151
	}
152
153
	$located = wpinv_locate_template( $template_name, $template_path, $default_path );
154
	// Allow 3rd party plugin filter template file from their plugin.
155
	$located = apply_filters( 'wpinv_get_template', $located, $template_name, $args, $template_path, $default_path );
156
157
	if ( ! file_exists( $located ) ) {
158
        _doing_it_wrong( __FUNCTION__, sprintf( '<code>%s</code> does not exist.', $located ), '2.1' );
159
		return;
160
	}
161
162
	do_action( 'wpinv_before_template_part', $template_name, $template_path, $located, $args );
163
164
	include( $located );
165
166
	do_action( 'wpinv_after_template_part', $template_name, $template_path, $located, $args );
167
}
168
169
function wpinv_get_template_html( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
170
	ob_start();
171
	wpinv_get_template( $template_name, $args, $template_path, $default_path );
172
	return ob_get_clean();
173
}
174
175
function wpinv_locate_template( $template_name, $template_path = '', $default_path = '' ) {
176
    if ( ! $template_path ) {
177
        $template_path = wpinv_template_path();
178
    }
179
180
    if ( ! $default_path ) {
181
        $default_path = WPINV_PLUGIN_DIR . 'templates/';
182
    }
183
184
    // Look within passed path within the theme - this is priority.
185
    $template = locate_template(
186
        array(
187
            trailingslashit( $template_path ) . $template_name,
188
            $template_name
189
        )
190
    );
191
192
    // Get default templates/
193
    if ( !$template && $default_path ) {
194
        $template = trailingslashit( $default_path ) . $template_name;
195
    }
196
197
    // Return what we found.
198
    return apply_filters( 'wpinv_locate_template', $template, $template_name, $template_path );
199
}
200
201
function wpinv_get_template_part( $slug, $name = null, $load = true ) {
202
	do_action( 'get_template_part_' . $slug, $slug, $name );
203
204
	// Setup possible parts
205
	$templates = array();
206
	if ( isset( $name ) )
207
		$templates[] = $slug . '-' . $name . '.php';
208
	$templates[] = $slug . '.php';
209
210
	// Allow template parts to be filtered
211
	$templates = apply_filters( 'wpinv_get_template_part', $templates, $slug, $name );
212
213
	// Return the part that is found
214
	return wpinv_locate_tmpl( $templates, $load, false );
215
}
216
217
function wpinv_locate_tmpl( $template_names, $load = false, $require_once = true ) {
218
	// No file found yet
219
	$located = false;
220
221
	// Try to find a template file
222
	foreach ( (array)$template_names as $template_name ) {
223
224
		// Continue if template is empty
225
		if ( empty( $template_name ) )
226
			continue;
227
228
		// Trim off any slashes from the template name
229
		$template_name = ltrim( $template_name, '/' );
230
231
		// try locating this template file by looping through the template paths
232
		foreach( wpinv_get_theme_template_paths() as $template_path ) {
233
234
			if( file_exists( $template_path . $template_name ) ) {
235
				$located = $template_path . $template_name;
236
				break;
237
			}
238
		}
239
240
		if( !empty( $located ) ) {
241
			break;
242
		}
243
	}
244
245
	if ( ( true == $load ) && ! empty( $located ) )
246
		load_template( $located, $require_once );
247
248
	return $located;
249
}
250
251
function wpinv_get_theme_template_paths() {
252
	$template_dir = wpinv_get_theme_template_dir_name();
253
254
	$file_paths = array(
255
		1 => trailingslashit( get_stylesheet_directory() ) . $template_dir,
256
		10 => trailingslashit( get_template_directory() ) . $template_dir,
257
		100 => wpinv_get_templates_dir()
258
	);
259
260
	$file_paths = apply_filters( 'wpinv_template_paths', $file_paths );
261
262
	// sort the file paths based on priority
263
	ksort( $file_paths, SORT_NUMERIC );
264
265
	return array_map( 'trailingslashit', $file_paths );
266
}
267
268
function wpinv_get_theme_template_dir_name() {
269
	return trailingslashit( apply_filters( 'wpinv_templates_dir', 'invoicing' ) );
270
}
271
272
function wpinv_checkout_meta_tags() {
273
274
	$pages   = array();
275
	$pages[] = wpinv_get_option( 'success_page' );
276
	$pages[] = wpinv_get_option( 'failure_page' );
277
	$pages[] = wpinv_get_option( 'invoice_history_page' );
278
	$pages[] = wpinv_get_option( 'invoice_subscription_page' );
279
280
	if( !wpinv_is_checkout() && !is_page( $pages ) ) {
281
		return;
282
	}
283
284
	echo '<meta name="robots" content="noindex,nofollow" />' . "\n";
285
}
286
add_action( 'wp_head', 'wpinv_checkout_meta_tags' );
287
288
function wpinv_add_body_classes( $class ) {
289
	$classes = (array)$class;
290
291
	if( wpinv_is_checkout() ) {
292
		$classes[] = 'wpinv-checkout';
293
		$classes[] = 'wpinv-page';
294
	}
295
296
	if( wpinv_is_success_page() ) {
297
		$classes[] = 'wpinv-success';
298
		$classes[] = 'wpinv-page';
299
	}
300
301
	if( wpinv_is_failed_transaction_page() ) {
302
		$classes[] = 'wpinv-failed-transaction';
303
		$classes[] = 'wpinv-page';
304
	}
305
306
	if( wpinv_is_invoice_history_page() ) {
307
		$classes[] = 'wpinv-history';
308
		$classes[] = 'wpinv-page';
309
	}
310
311
	if( wpinv_is_subscriptions_history_page() ) {
312
		$classes[] = 'wpinv-subscription';
313
		$classes[] = 'wpinv-page';
314
	}
315
316
	if( wpinv_is_test_mode() ) {
317
		$classes[] = 'wpinv-test-mode';
318
		$classes[] = 'wpinv-page';
319
	}
320
321
	return array_unique( $classes );
322
}
323
add_filter( 'body_class', 'wpinv_add_body_classes' );
324
325
function wpinv_html_dropdown( $name = 'wpinv_discounts', $selected = 0, $status = '' ) {
326
    $args = array( 'nopaging' => true );
327
328
    if ( ! empty( $status ) )
329
        $args['post_status'] = $status;
330
331
    $discounts = wpinv_get_discounts( $args );
332
    $options   = array();
333
334
    if ( $discounts ) {
335
        foreach ( $discounts as $discount ) {
336
            $options[ absint( $discount->ID ) ] = esc_html( get_the_title( $discount->ID ) );
337
        }
338
    } else {
339
        $options[0] = __( 'No discounts found', 'invoicing' );
340
    }
341
342
    $output = wpinv_html_select( array(
343
        'name'             => $name,
344
        'selected'         => $selected,
345
        'options'          => $options,
346
        'show_option_all'  => false,
347
        'show_option_none' => false,
348
    ) );
349
350
    return $output;
351
}
352
353
function wpinv_html_year_dropdown( $name = 'year', $selected = 0, $years_before = 5, $years_after = 0 ) {
354
    $current     = date( 'Y' );
355
    $start_year  = $current - absint( $years_before );
356
    $end_year    = $current + absint( $years_after );
357
    $selected    = empty( $selected ) ? date( 'Y' ) : $selected;
358
    $options     = array();
359
360
    while ( $start_year <= $end_year ) {
361
        $options[ absint( $start_year ) ] = $start_year;
362
        $start_year++;
363
    }
364
365
    $output = wpinv_html_select( array(
366
        'name'             => $name,
367
        'selected'         => $selected,
368
        'options'          => $options,
369
        'show_option_all'  => false,
370
        'show_option_none' => false
371
    ) );
372
373
    return $output;
374
}
375
376
function wpinv_html_month_dropdown( $name = 'month', $selected = 0 ) {
377
378
    $options = array(
379
        '1'  => __( 'January', 'invoicing' ),
380
        '2'  => __( 'February', 'invoicing' ),
381
        '3'  => __( 'March', 'invoicing' ),
382
        '4'  => __( 'April', 'invoicing' ),
383
        '5'  => __( 'May', 'invoicing' ),
384
        '6'  => __( 'June', 'invoicing' ),
385
        '7'  => __( 'July', 'invoicing' ),
386
        '8'  => __( 'August', 'invoicing' ),
387
        '9'  => __( 'September', 'invoicing' ),
388
        '10' => __( 'October', 'invoicing' ),
389
        '11' => __( 'November', 'invoicing' ),
390
        '12' => __( 'December', 'invoicing' ),
391
    );
392
393
    // If no month is selected, default to the current month
394
    $selected = empty( $selected ) ? date( 'n' ) : $selected;
395
396
    $output = wpinv_html_select( array(
397
        'name'             => $name,
398
        'selected'         => $selected,
399
        'options'          => $options,
400
        'show_option_all'  => false,
401
        'show_option_none' => false
402
    ) );
403
404
    return $output;
405
}
406
407
function wpinv_html_select( $args = array() ) {
408
    $defaults = array(
409
        'options'          => array(),
410
        'name'             => null,
411
        'class'            => '',
412
        'id'               => '',
413
        'selected'         => 0,
414
        'placeholder'      => null,
415
        'multiple'         => false,
416
        'show_option_all'  => _x( 'All', 'all dropdown items', 'invoicing' ),
417
        'show_option_none' => _x( 'None', 'no dropdown items', 'invoicing' ),
418
        'data'             => array(),
419
        'onchange'         => null,
420
        'required'         => false,
421
        'disabled'         => false,
422
        'readonly'         => false,
423
    );
424
425
    $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['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 407
  2. 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 407
  3. 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 407

Used in variable context

  1. wp_parse_args() is called
    in includes/wpinv-template-functions.php on line 425
  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...
426
427
    $data_elements = '';
428
    foreach ( $args['data'] as $key => $value ) {
429
        $data_elements .= ' data-' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
430
    }
431
432
    if( $args['multiple'] ) {
433
        $multiple = ' MULTIPLE';
434
    } else {
435
        $multiple = '';
436
    }
437
438
    if( $args['placeholder'] ) {
439
        $placeholder = $args['placeholder'];
440
    } else {
441
        $placeholder = '';
442
    }
443
    
444
    $options = '';
445
    if( !empty( $args['onchange'] ) ) {
446
        $options .= ' onchange="' . esc_attr( $args['onchange'] ) . '"';
447
    }
448
    
449
    if( !empty( $args['required'] ) ) {
450
        $options .= ' required="required"';
451
    }
452
    
453
    if( !empty( $args['disabled'] ) ) {
454
        $options .= ' disabled';
455
    }
456
    
457
    if( !empty( $args['readonly'] ) ) {
458
        $options .= ' readonly';
459
    }
460
461
    $class  = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
462
    $output = '<select name="' . esc_attr( $args['name'] ) . '" id="' . esc_attr( $args['id'] ) . '" class="wpinv-select ' . $class . '"' . $multiple . ' data-placeholder="' . $placeholder . '" ' . trim( $options ) . $data_elements . '>';
463
464
    if ( $args['show_option_all'] ) {
465
        if( $args['multiple'] ) {
466
            $selected = selected( true, in_array( 0, $args['selected'] ), false );
467
        } else {
468
            $selected = selected( $args['selected'], 0, false );
469
        }
470
        $output .= '<option value="all"' . $selected . '>' . esc_html( $args['show_option_all'] ) . '</option>';
471
    }
472
473
    if ( !empty( $args['options'] ) ) {
474
475
        if ( $args['show_option_none'] ) {
476
            if( $args['multiple'] ) {
477
                $selected = selected( true, in_array( "", $args['selected'] ), false );
478
            } else {
479
                $selected = selected( $args['selected'] === "", true, false );
480
            }
481
            $output .= '<option value=""' . $selected . '>' . esc_html( $args['show_option_none'] ) . '</option>';
482
        }
483
484
        foreach( $args['options'] as $key => $option ) {
485
486
            if( $args['multiple'] && is_array( $args['selected'] ) ) {
487
                $selected = selected( true, (bool)in_array( $key, $args['selected'] ), false );
488
            } else {
489
                $selected = selected( $args['selected'], $key, false );
490
            }
491
492
            $output .= '<option value="' . esc_attr( $key ) . '"' . $selected . '>' . esc_html( $option ) . '</option>';
493
        }
494
    }
495
496
    $output .= '</select>';
497
498
    return $output;
499
}
500
501
function wpinv_item_dropdown( $args = array() ) {
502
    $defaults = array(
503
        'name'              => 'wpi_item',
504
        'id'                => 'wpi_item',
505
        'class'             => '',
506
        'multiple'          => false,
507
        'selected'          => 0,
508
        'number'            => 100,
509
        'placeholder'       => __( 'Choose a item', 'invoicing' ),
510
        'data'              => array( 'search-type' => 'item' ),
511
        'show_option_all'   => false,
512
        'show_option_none'  => false,
513
        'show_recurring'    => false,
514
    );
515
516
    $args = wp_parse_args( $args, $defaults );
517
518
    $item_args = array(
519
        'post_type'      => 'wpi_item',
520
        'orderby'        => 'title',
521
        'order'          => 'ASC',
522
        'posts_per_page' => $args['number']
523
    );
524
525
    $item_args  = apply_filters( 'wpinv_item_dropdown_query_args', $item_args, $args, $defaults );
526
527
    $items      = get_posts( $item_args );
528
    $options    = array();
529
    if ( $items ) {
530
        foreach ( $items as $item ) {
531
            $title = esc_html( $item->post_title );
532
            
533
            if ( !empty( $args['show_recurring'] ) ) {
534
                $title .= wpinv_get_item_suffix( $item->ID, false );
535
            }
536
            
537
            $options[ absint( $item->ID ) ] = $title;
538
        }
539
    }
540
541
    // This ensures that any selected items are included in the drop down
542
    if( is_array( $args['selected'] ) ) {
543
        foreach( $args['selected'] as $item ) {
544
            if( ! in_array( $item, $options ) ) {
545
                $title = get_the_title( $item );
546
                if ( !empty( $args['show_recurring'] ) ) {
547
                    $title .= wpinv_get_item_suffix( $item, false );
548
                }
549
                $options[$item] = $title;
550
            }
551
        }
552
    } elseif ( is_numeric( $args['selected'] ) && $args['selected'] !== 0 ) {
553
        if ( ! in_array( $args['selected'], $options ) ) {
554
            $title = get_the_title( $args['selected'] );
555
            if ( !empty( $args['show_recurring'] ) ) {
556
                $title .= wpinv_get_item_suffix( $args['selected'], false );
557
            }
558
            $options[$args['selected']] = get_the_title( $args['selected'] );
559
        }
560
    }
561
562
    $output = wpinv_html_select( array(
563
        'name'             => $args['name'],
564
        'selected'         => $args['selected'],
565
        'id'               => $args['id'],
566
        'class'            => $args['class'],
567
        'options'          => $options,
568
        'multiple'         => $args['multiple'],
569
        'placeholder'      => $args['placeholder'],
570
        'show_option_all'  => $args['show_option_all'],
571
        'show_option_none' => $args['show_option_none'],
572
        'data'             => $args['data'],
573
    ) );
574
575
    return $output;
576
}
577
578
/**
579
 * Returns an array of published items.
580
 */
581
function wpinv_get_published_items_for_dropdown() {
582
583
    $items = get_posts(
584
        array(
585
            'post_type'      => 'wpi_item',
586
            'orderby'        => 'title',
587
            'order'          => 'ASC',
588
            'posts_per_page' => '-1'
589
        )
590
    );
591
592
    $options = array();
593
    if ( $items ) {
594
        foreach ( $items as $item ) {
595
            $options[ $item->ID ] = esc_html( $item->post_title ) . wpinv_get_item_suffix( $item->ID, false );
596
        }
597
    }
598
599
    return $options;
600
}
601
602
function wpinv_html_checkbox( $args = array() ) {
603
    $defaults = array(
604
        'name'     => null,
605
        'current'  => null,
606
        'class'    => 'wpinv-checkbox',
607
        'options'  => array(
608
            'disabled' => false,
609
            'readonly' => false
610
        )
611
    );
612
613
    $args = wp_parse_args( $args, $defaults );
614
615
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
616
    $options = '';
617
    if ( ! empty( $args['options']['disabled'] ) ) {
618
        $options .= ' disabled="disabled"';
619
    } elseif ( ! empty( $args['options']['readonly'] ) ) {
620
        $options .= ' readonly';
621
    }
622
623
    $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 ) . ' />';
624
625
    return $output;
626
}
627
628
function wpinv_html_text( $args = array() ) {
629
    // Backwards compatibility
630
    if ( func_num_args() > 1 ) {
631
        $args = func_get_args();
632
633
        $name  = $args[0];
634
        $value = isset( $args[1] ) ? $args[1] : '';
635
        $label = isset( $args[2] ) ? $args[2] : '';
636
        $desc  = isset( $args[3] ) ? $args[3] : '';
637
    }
638
639
    $defaults = array(
640
        'id'           => '',
641
        'name'         => isset( $name )  ? $name  : 'text',
642
        'value'        => isset( $value ) ? $value : null,
643
        'label'        => isset( $label ) ? $label : null,
644
        'desc'         => isset( $desc )  ? $desc  : null,
645
        'placeholder'  => '',
646
        'class'        => 'regular-text',
647
        'disabled'     => false,
648
        'readonly'     => false,
649
        'required'     => false,
650
        'autocomplete' => '',
651
        'data'         => false
652
    );
653
654
    $args = wp_parse_args( $args, $defaults );
655
656
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
657
    $options = '';
658
    if( $args['required'] ) {
659
        $options .= ' required="required"';
660
    }
661
    if( $args['readonly'] ) {
662
        $options .= ' readonly';
663
    }
664
    if( $args['readonly'] ) {
665
        $options .= ' readonly';
666
    }
667
668
    $data = '';
669
    if ( !empty( $args['data'] ) ) {
670
        foreach ( $args['data'] as $key => $value ) {
671
            $data .= 'data-' . wpinv_sanitize_key( $key ) . '="' . esc_attr( $value ) . '" ';
672
        }
673
    }
674
675
    $output = '<span id="wpinv-' . wpinv_sanitize_key( $args['name'] ) . '-wrap">';
676
    $output .= '<label class="wpinv-label" for="' . wpinv_sanitize_key( $args['id'] ) . '">' . esc_html( $args['label'] ) . '</label>';
677
    if ( ! empty( $args['desc'] ) ) {
678
        $output .= '<span class="wpinv-description">' . esc_html( $args['desc'] ) . '</span>';
679
    }
680
681
    $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 ) . '/>';
682
683
    $output .= '</span>';
684
685
    return $output;
686
}
687
688
function wpinv_html_date_field( $args = array() ) {
689
    if( empty( $args['class'] ) ) {
690
        $args['class'] = 'wpiDatepicker';
691
    } elseif( ! strpos( $args['class'], 'wpiDatepicker' ) ) {
692
        $args['class'] .= ' wpiDatepicker';
693
    }
694
695
    return wpinv_html_text( $args );
696
}
697
698
function wpinv_html_textarea( $args = array() ) {
699
    $defaults = array(
700
        'name'        => 'textarea',
701
        'value'       => null,
702
        'label'       => null,
703
        'desc'        => null,
704
        'class'       => 'large-text',
705
        'disabled'    => false,
706
        'placeholder' => '',
707
    );
708
709
    $args = wp_parse_args( $args, $defaults );
710
711
    $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['class'] ) ) );
712
    $disabled = '';
713
    if( $args['disabled'] ) {
714
        $disabled = ' disabled="disabled"';
715
    }
716
717
    $output = '<span id="wpinv-' . wpinv_sanitize_key( $args['name'] ) . '-wrap">';
718
    $output .= '<label class="wpinv-label" for="' . wpinv_sanitize_key( $args['name'] ) . '">' . esc_html( $args['label'] ) . '</label>';
719
    $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>';
720
721
    if ( ! empty( $args['desc'] ) ) {
722
        $output .= '<span class="wpinv-description">' . esc_html( $args['desc'] ) . '</span>';
723
    }
724
    $output .= '</span>';
725
726
    return $output;
727
}
728
729
function wpinv_html_ajax_user_search( $args = array() ) {
730
    $defaults = array(
731
        'name'        => 'user_id',
732
        'value'       => null,
733
        'placeholder' => __( 'Enter username', 'invoicing' ),
734
        'label'       => null,
735
        'desc'        => null,
736
        'class'       => '',
737
        'disabled'    => false,
738
        'autocomplete'=> 'off',
739
        'data'        => false
740
    );
741
742
    $args = wp_parse_args( $args, $defaults );
743
744
    $args['class'] = 'wpinv-ajax-user-search ' . $args['class'];
745
746
    $output  = '<span class="wpinv_user_search_wrap">';
747
        $output .= wpinv_html_text( $args );
748
        $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>';
749
    $output .= '</span>';
750
751
    return $output;
752
}
753
754
function wpinv_ip_geolocation() {
755
    global $wpinv_euvat;
756
    
757
    $ip         = !empty( $_GET['ip'] ) ? sanitize_text_field( $_GET['ip'] ) : '';    
758
    $content    = '';
759
    $iso        = '';
760
    $country    = '';
761
    $region     = '';
762
    $city       = '';
763
    $longitude  = '';
764
    $latitude   = '';
765
    $credit     = '';
766
    $address    = '';
767
    
768
    if ( wpinv_get_option( 'vat_ip_lookup' ) == 'geoip2' && $geoip2_city = $wpinv_euvat->geoip2_city_record( $ip ) ) {
769
        try {
770
            $iso        = $geoip2_city->country->isoCode;
771
            $country    = $geoip2_city->country->name;
772
            $region     = !empty( $geoip2_city->subdivisions ) && !empty( $geoip2_city->subdivisions[0]->name ) ? $geoip2_city->subdivisions[0]->name : '';
773
            $city       = $geoip2_city->city->name;
774
            $longitude  = $geoip2_city->location->longitude;
775
            $latitude   = $geoip2_city->location->latitude;
776
            $credit     = __( 'Geolocated using the information by MaxMind, available from <a href="http://www.maxmind.com" target="_blank">www.maxmind.com</a>', 'invoicing' );
777
        } catch( Exception $e ) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
778
    }
779
    
780
    if ( !( $iso && $longitude && $latitude ) && function_exists( 'simplexml_load_file' ) ) {
781
        try {
782
            $load_xml = simplexml_load_file( 'http://www.geoplugin.net/xml.gp?ip=' . $ip );
783
            
784
            if ( !empty( $load_xml ) && isset( $load_xml->geoplugin_countryCode ) && !empty( $load_xml->geoplugin_latitude ) && !empty( $load_xml->geoplugin_longitude ) ) {
785
                $iso        = $load_xml->geoplugin_countryCode;
786
                $country    = $load_xml->geoplugin_countryName;
787
                $region     = !empty( $load_xml->geoplugin_regionName ) ? $load_xml->geoplugin_regionName : '';
788
                $city       = !empty( $load_xml->geoplugin_city ) ? $load_xml->geoplugin_city : '';
789
                $longitude  = $load_xml->geoplugin_longitude;
790
                $latitude   = $load_xml->geoplugin_latitude;
791
                $credit     = $load_xml->geoplugin_credit;
0 ignored issues
show
Unused Code introduced by
The assignment to $credit is dead and can be removed.
Loading history...
792
                $credit     = __( 'Geolocated using the information by geoPlugin, available from <a href="http://www.geoplugin.com" target="_blank">www.geoplugin.com</a>', 'invoicing' ) . '<br>' . $load_xml->geoplugin_credit;
793
            }
794
        } catch( Exception $e ) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
795
    }
796
    
797
    if ( $iso && $longitude && $latitude ) {
798
        if ( $city ) {
799
            $address .= $city . ', ';
800
        }
801
        
802
        if ( $region ) {
803
            $address .= $region . ', ';
804
        }
805
        
806
        $address .= $country . ' (' . $iso . ')';
807
        $content = '<p>'. sprintf( __( '<b>Address:</b> %s', 'invoicing' ), $address ) . '</p>';
808
        $content .= '<p>'. $credit . '</p>';
809
    } else {
810
        $content = '<p>'. sprintf( __( 'Unable to find geolocation for the IP address: %s', 'invoicing' ), $ip ) . '</p>';
811
    }
812
    ?>
813
<!DOCTYPE html>
814
<html><head><title><?php echo sprintf( __( 'IP: %s', 'invoicing' ), $ip );?></title><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-rc.1/leaflet.css" /><style>html,body{height:100%;margin:0;padding:0;width:100%}body{text-align:center;background:#fff;color:#222;font-size:small;}body,p{font-family: arial,sans-serif}#map{margin:auto;width:100%;height:calc(100% - 120px);min-height:240px}</style></head>
815
<body>
816
    <?php if ( $latitude && $latitude ) { ?>
817
    <div id="map"></div>
818
        <script src="//cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-rc.1/leaflet.js"></script>
819
        <script type="text/javascript">
820
        var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
821
            osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
822
            osm = L.tileLayer(osmUrl, {maxZoom: 18, attribution: osmAttrib}),
823
            latlng = new L.LatLng(<?php echo $latitude;?>, <?php echo $longitude;?>);
824
825
        var map = new L.Map('map', {center: latlng, zoom: 12, layers: [osm]});
826
827
        var marker = new L.Marker(latlng);
828
        map.addLayer(marker);
829
830
        marker.bindPopup("<p><?php esc_attr_e( $address );?></p>");
831
    </script>
832
    <?php } ?>
833
    <div style="height:100px"><?php echo $content; ?></div>
834
</body></html>
835
<?php
836
    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...
837
}
838
add_action( 'wp_ajax_wpinv_ip_geolocation', 'wpinv_ip_geolocation' );
839
add_action( 'wp_ajax_nopriv_wpinv_ip_geolocation', 'wpinv_ip_geolocation' );
840
841
// Set up the template for the invoice.
842
function wpinv_template( $template ) {
843
    global $post;
844
845
    if ( ( is_single() || is_404() ) && ! empty( $post->ID ) && getpaid_is_invoice_post_type( get_post_type( $post->ID ) ) ) {
846
847
        // If the user can view this invoice, display it.
848
        if ( wpinv_user_can_view_invoice( $post->ID ) ) {
849
            return wpinv_get_template_part( 'wpinv-invoice-print', false, false );
850
851
        // Else display an error message.
852
        } else {
853
            return wpinv_get_template_part( 'wpinv-invalid-access', false, false );
854
        }
855
856
    }
857
858
    return $template;
859
}
860
861
function wpinv_get_business_address() {
862
    $business_address   = wpinv_store_address();
863
    $business_address   = !empty( $business_address ) ? wpautop( wp_kses_post( $business_address ) ) : '';
864
    
865
    /*
866
    $default_country    = wpinv_get_default_country();
867
    $default_state      = wpinv_get_default_state();
868
    
869
    $address_fields = array();
870
    if ( !empty( $default_state ) ) {
871
        $address_fields[] = wpinv_state_name( $default_state, $default_country );
872
    }
873
    
874
    if ( !empty( $default_country ) ) {
875
        $address_fields[] = wpinv_country_name( $default_country );
876
    }
877
    
878
    if ( !empty( $address_fields ) ) {
879
        $address_fields = implode( ", ", $address_fields );
880
                
881
        $business_address .= wpautop( wp_kses_post( $address_fields ) );
882
    }
883
    */
884
    
885
    $business_address = $business_address ? '<div class="address">' . $business_address . '</div>' : '';
886
    
887
    return apply_filters( 'wpinv_get_business_address', $business_address );
888
}
889
890
/**
891
 * Displays the company address.
892
 */
893
function wpinv_display_from_address() {
894
    wpinv_get_template( 'invoice/company-address.php' );
895
}
896
add_action( 'getpaid_invoice_details_left', 'wpinv_display_from_address', 10 );
897
898
function wpinv_watermark( $id = 0 ) {
899
    $output = wpinv_get_watermark( $id );
900
    return apply_filters( 'wpinv_get_watermark', $output, $id );
901
}
902
903
function wpinv_get_watermark( $id ) {
904
    if ( !$id > 0 ) {
905
        return NULL;
906
    }
907
908
    $invoice = wpinv_get_invoice( $id );
909
    
910
    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...
911
        if ( $invoice->is_paid() ) {
912
            return __( 'Paid', 'invoicing' );
913
        }
914
        if ( $invoice->is_refunded() ) {
915
            return __( 'Refunded', 'invoicing' );
916
        }
917
        if ( $invoice->has_status( array( 'wpi-cancelled' ) ) ) {
918
            return __( 'Cancelled', 'invoicing' );
919
        }
920
    }
921
    
922
    return NULL;
923
}
924
925
/**
926
 * @deprecated
927
 */
928
function wpinv_display_invoice_details( $invoice ) {
929
    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...
930
}
931
932
/**
933
 * Displays invoice meta.
934
 */
935
function getpaid_invoice_meta( $invoice ) {
936
937
    $invoice = new WPInv_Invoice( $invoice );
938
939
    // Ensure that we have an invoice.
940
    if ( 0 == $invoice->get_id() ) {
941
        return;
942
    }
943
944
    // Load the invoice meta.
945
    $meta    = array(
946
947
        'number' => array(
948
            'label' => sprintf(
949
                __( '%s Number', 'invoicing' ),
950
                ucfirst( $invoice->get_type() )
951
            ),
952
            'value' => sanitize_text_field( $invoice->get_number() ),
953
        ),
954
955
        'status' => array(
956
            'label' => sprintf(
957
                __( '%s Status', 'invoicing' ),
958
                ucfirst( $invoice->get_type() )
959
            ),
960
            'value' => sanitize_text_field( $invoice->get_status_nicename() ),
961
        ),
962
963
        'date' => array(
964
            'label' => sprintf(
965
                __( '%s Date', 'invoicing' ),
966
                ucfirst( $invoice->get_type() )
967
            ),
968
            'value' => getpaid_format_date( $invoice->get_created_date() ),
969
        ),
970
971
        'date_paid' => array(
972
            'label' => __( 'Paid On', 'invoicing' ),
973
            'value' => getpaid_format_date( $invoice->get_completed_date() ),
974
        ),
975
976
        'due_date'  => array(
977
            'label' => __( 'Due Date', 'invoicing' ),
978
            'value' => getpaid_format_date( $invoice->get_due_date() ),
979
        ),
980
981
        'vat_number' => array(
982
            'label' => sprintf(
983
                __( '%s Number', 'invoicing' ),
984
                $GLOBALS['wpinv_euvat']->get_vat_name()
985
            ),
986
            'value' => sanitize_text_field( $invoice->get_vat_number() ),
987
        ),
988
989
    );
990
991
    // If it is not paid, remove the date of payment.
992
    if ( ! $invoice->is_paid() ) {
993
        unset( $meta[ 'date_paid' ] );
994
    }
995
996
    // Only display the due date if due dates are enabled.
997
    if ( ! $invoice->needs_payment() || ! wpinv_get_option( 'overdue_active' ) ) {
998
        unset( $meta[ 'due_date' ] );
999
    }
1000
1001
    // Only display the vat number if taxes are enabled.
1002
    if ( ! wpinv_use_taxes() ) {
1003
        unset( $meta[ 'vat_number' ] );
1004
    }
1005
1006
    if ( $invoice->is_recurring() ) {
1007
1008
        // Link to the parent invoice.
1009
        if ( $invoice->is_renewal() ) {
1010
1011
            $meta[ 'parent' ] = array(
1012
1013
                'label' => sprintf(
1014
                    __( 'Parent %s', 'invoicing' ),
1015
                    ucfirst( $invoice->get_type() )
1016
                ),
1017
1018
                'value' => wpinv_invoice_link( $invoice->get_parent_id() ),
1019
1020
            );
1021
1022
        }
1023
1024
        $subscription = wpinv_get_subscription( $invoice );
1025
1026
        if ( ! empty ( $subscription ) ) {
1027
1028
            // Display the renewal date.
1029
            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...
1030
1031
                $meta[ 'renewal_date' ] = array(
1032
1033
                    'label' => __( 'Renews On', 'invoicing' ),
1034
                    'value' => getpaid_format_date( $subscription->expiration ),
1035
        
1036
                );
1037
1038
            }
1039
1040
            if ( $invoice->is_parent() ) {
1041
1042
                // Display the recurring amount.
1043
                $meta[ 'recurring_total' ] = array(
1044
1045
                    'label' => __( 'Recurring Amount', 'invoicing' ),
1046
                    'value' => wpinv_price( wpinv_format_amount( $subscription->recurring_amount ), $invoice->get_currency() ),
1047
        
1048
                );
1049
1050
            }
1051
            
1052
        }
1053
    }
1054
1055
    // Add the invoice total to the meta.
1056
    $meta[ 'invoice_total' ] = array(
1057
1058
        'label' => __( 'Total Amount', 'invoicing' ),
1059
        'value' => wpinv_price( wpinv_format_amount( $invoice->get_total() ), $invoice->get_currency() ),
1060
1061
    );
1062
1063
    // Provide a way for third party plugins to filter the meta.
1064
    $meta = apply_filters( 'getpaid_invoice_meta_data', $meta, $invoice );
1065
1066
    wpinv_get_template( 'invoice/invoice-meta.php', compact( 'invoice', 'meta' ) );
1067
1068
}
1069
add_action( 'getpaid_invoice_details_right', 'getpaid_invoice_meta', 10 );
1070
1071
/**
1072
 * Retrieves the address markup to use on Invoices.
1073
 * 
1074
 * @since 1.0.13
1075
 * @see `wpinv_get_full_address_format`
1076
 * @see `wpinv_get_invoice_address_replacements`
1077
 * @param array $billing_details customer's billing details
1078
 * @param  string $separator How to separate address lines.
1079
 * @return string
1080
 */
1081
function wpinv_get_invoice_address_markup( $billing_details, $separator = '<br/>' ) {
1082
1083
    // Retrieve the address markup...
1084
    $country= empty( $billing_details['country'] ) ? '' : $billing_details['country'];
1085
    $format = wpinv_get_full_address_format( $country );
1086
1087
    // ... and the replacements.
1088
    $replacements = wpinv_get_invoice_address_replacements( $billing_details );
1089
1090
    $formatted_address = str_ireplace( array_keys( $replacements ), $replacements, $format );
1091
    
1092
	// Remove unavailable tags.
1093
    $formatted_address = preg_replace( "/\{\{\w+\}\}/", '', $formatted_address );
1094
1095
    // Clean up white space.
1096
	$formatted_address = preg_replace( '/  +/', ' ', trim( $formatted_address ) );
1097
    $formatted_address = preg_replace( '/\n\n+/', "\n", $formatted_address );
1098
    
1099
    // Break newlines apart and remove empty lines/trim commas and white space.
1100
	$formatted_address = array_filter( array_map( 'wpinv_trim_formatted_address_line', explode( "\n", $formatted_address ) ) );
1101
1102
    // Add html breaks.
1103
	$formatted_address = implode( $separator, $formatted_address );
1104
1105
	// We're done!
1106
	return $formatted_address;
1107
    
1108
}
1109
1110
/**
1111
 * Displays the billing address.
1112
 * 
1113
 * @param WPInv_Invoice $invoice
1114
 */
1115
function wpinv_display_to_address( $invoice = 0 ) {
1116
    if ( ! empty( $invoice ) ) {
1117
        wpinv_get_template( 'invoice/billing-address.php', compact( 'invoice' ) );
1118
    }
1119
}
1120
add_action( 'getpaid_invoice_details_left', 'wpinv_display_to_address', 40 );
1121
1122
1123
/**
1124
 * Displays invoice line items.
1125
 */
1126
function wpinv_display_line_items( $invoice_id = 0 ) {
1127
1128
    // Prepare the invoice.
1129
    $invoice = new WPInv_Invoice( $invoice_id );
1130
1131
    // Abort if there is no invoice.
1132
    if ( 0 == $invoice->get_id() ) {
1133
        return;
1134
    }
1135
1136
    // Line item columns.
1137
    $columns = apply_filters(
1138
        'getpaid_invoice_line_items_table_columns',
1139
        array(
1140
            'name'     => __( 'Item', 'invoicing' ),
1141
            'price'    => __( 'Price', 'invoicing' ),
1142
            'quantity' => __( 'Quantity', 'invoicing' ),
1143
            'subtotal' => __( 'Subtotal', 'invoicing' ),
1144
        ),
1145
        $invoice
1146
    );
1147
1148
    // Quantities.
1149
    if ( isset( $columns[ 'quantity' ] ) ) {
1150
1151
        if ( 'amount' == $invoice->get_template() ) {
1152
            unset( $columns[ 'quantity' ] );
1153
        }
1154
1155
        if ( 'hours' == $invoice->get_template() ) {
1156
            $columns[ 'quantity' ] = __( 'Hours', 'invoicing' );
1157
        }
1158
1159
        if ( ! wpinv_item_quantities_enabled() ) {
1160
            unset( $columns[ 'quantity' ] );
1161
        }
1162
1163
    }
1164
1165
    // Price.
1166
    if ( isset( $columns[ 'price' ] ) ) {
1167
1168
        if ( 'amount' == $invoice->get_template() ) {
1169
            $columns[ 'price' ] = __( 'Amount', 'invoicing' );
1170
        }
1171
1172
        if ( 'hours' == $invoice->get_template() ) {
1173
            $columns[ 'price' ] = __( 'Rate', 'invoicing' );
1174
        }
1175
1176
    }
1177
1178
    // Sub total.
1179
    if ( isset( $columns[ 'subtotal' ] ) ) {
1180
1181
        if ( 'amount' == $invoice->get_template() ) {
1182
            unset( $columns[ 'subtotal' ] );
1183
        }
1184
1185
    }
1186
1187
    wpinv_get_template( 'invoice/line-items.php', compact( 'invoice', 'columns' ) );
1188
}
1189
add_action( 'getpaid_invoice_line_items', 'wpinv_display_line_items' );
1190
1191
/**
1192
 * @param WPInv_Invoice $invoice
1193
 */
1194
function wpinv_display_invoice_notes( $invoice ) {
1195
1196
    $notes = wpinv_get_invoice_notes( $invoice->ID, 'customer' );
1197
1198
    if ( empty( $notes ) ) {
1199
        return;
1200
    }
1201
1202
    echo '<div class="wpi_invoice_notes_container">';
1203
    echo '<h2>' . __( 'Invoice Notes', 'invoicing' ) .'</h2>';
1204
    echo '<ul class="wpi_invoice_notes">';
1205
1206
    foreach( $notes as $note ) {
1207
        wpinv_get_invoice_note_line_item( $note );
1208
    }
1209
1210
    echo '</ul>';
1211
    echo '</div>';
1212
}
1213
add_action( 'wpinv_invoice_print_after_line_items', 'wpinv_display_invoice_notes' );
1214
1215
function wpinv_display_invoice_totals( $invoice_id = 0 ) {
1216
    $use_taxes = wpinv_use_taxes();
1217
1218
    do_action( 'wpinv_before_display_totals_table', $invoice_id ); 
1219
    ?>
1220
    <table class="table table-sm table-bordered table-responsive">
1221
        <tbody>
1222
            <?php do_action( 'wpinv_before_display_totals' ); ?>
1223
            <tr class="row-sub-total">
1224
                <td class="rate"><strong><?php _e( 'Sub Total', 'invoicing' ); ?></strong></td>
1225
                <td class="total"><strong><?php _e( wpinv_subtotal( $invoice_id, true ) ) ?></strong></td>
1226
            </tr>
1227
            <?php do_action( 'wpinv_after_display_totals' ); ?>
1228
            <?php if ( wpinv_discount( $invoice_id, false ) > 0 ) { ?>
1229
                <tr class="row-discount">
1230
                    <td class="rate"><?php wpinv_get_discount_label( wpinv_discount_code( $invoice_id ) ); ?></td>
1231
                    <td class="total"><?php echo wpinv_discount( $invoice_id, true, true ); ?></td>
1232
                </tr>
1233
            <?php do_action( 'wpinv_after_display_discount' ); ?>
1234
            <?php } ?>
1235
            <?php if ( $use_taxes ) { ?>
1236
            <tr class="row-tax">
1237
                <td class="rate"><?php _e( 'Tax', 'invoicing' ); ?></td>
1238
                <td class="total"><?php _e( wpinv_tax( $invoice_id, true ) ) ?></td>
1239
            </tr>
1240
            <?php do_action( 'wpinv_after_display_tax' ); ?>
1241
            <?php } ?>
1242
            <?php if ( $fees = wpinv_get_fees( $invoice_id ) ) { ?>
1243
                <?php foreach ( $fees as $fee ) { ?>
1244
                    <tr class="row-fee">
1245
                        <td class="rate"><?php echo $fee['label']; ?></td>
1246
                        <td class="total"><?php echo $fee['amount_display']; ?></td>
1247
                    </tr>
1248
                <?php } ?>
1249
            <?php } ?>
1250
            <tr class="table-active row-total">
1251
                <td class="rate"><strong><?php _e( 'Total', 'invoicing' ) ?></strong></td>
1252
                <td class="total"><strong><?php _e( wpinv_payment_total( $invoice_id, true ) ) ?></strong></td>
1253
            </tr>
1254
            <?php do_action( 'wpinv_after_totals' ); ?>
1255
        </tbody>
1256
1257
    </table>
1258
1259
    <?php do_action( 'wpinv_after_totals_table' );
1260
}
1261
1262
function wpinv_display_payments_info( $invoice_id = 0, $echo = true ) {
1263
    $invoice = wpinv_get_invoice( $invoice_id );
1264
1265
    ob_start();
1266
    do_action( 'wpinv_before_display_payments_info', $invoice_id );
1267
    if ( ( $gateway_title = $invoice->get_gateway_title() ) || $invoice->is_paid() || $invoice->is_refunded() ) {
1268
        ?>
1269
        <div class="wpi-payment-info">
1270
            <p class="wpi-payment-gateway"><?php echo wp_sprintf( __( 'Payment via %s', 'invoicing' ), $gateway_title ? $gateway_title : __( 'Manually', 'invoicing' ) ); ?></p>
1271
            <?php if ( $gateway_title ) { ?>
1272
            <p class="wpi-payment-transid"><?php echo wp_sprintf( __( 'Transaction ID: %s', 'invoicing' ), $invoice->get_transaction_id() ); ?></p>
1273
            <?php } ?>
1274
        </div>
1275
        <?php
1276
    }
1277
    do_action( 'wpinv_after_display_payments_info', $invoice_id );
1278
    $outout = ob_get_clean();
1279
1280
    if ( $echo ) {
1281
        echo $outout;
1282
    } else {
1283
        return $outout;
1284
    }
1285
}
1286
1287
/**
1288
 * Loads scripts on our invoice templates.
1289
 */
1290
function wpinv_display_style() {
1291
1292
    // Make sure that all scripts have been loaded.
1293
    if ( ! did_action( 'wp_enqueue_scripts' ) ) {
1294
        do_action( 'wp_enqueue_scripts' );
1295
    }
1296
1297
    // Register the invoices style.
1298
    wp_register_style( 'wpinv-single-style', WPINV_PLUGIN_URL . 'assets/css/invoice.css', array(), filemtime( WPINV_PLUGIN_DIR . 'assets/css/invoice.css' ) );
1299
1300
    // Load required styles
1301
    wp_print_styles( 'open-sans' );
1302
    wp_print_styles( 'wpinv-single-style' );
1303
    wp_print_styles( 'ayecode-ui' );
1304
1305
    // Maybe load custom css.
1306
    $custom_css = wpinv_get_option( 'template_custom_css' );
1307
1308
    if ( isset( $custom_css ) && ! empty( $custom_css ) ) {
1309
        $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

1309
        $custom_css     = wp_kses( $custom_css, /** @scrutinizer ignore-type */ array( '\'', '\"' ) );
Loading history...
1310
        $custom_css     = str_replace( '&gt;', '>', $custom_css );
1311
        echo '<style type="text/css">';
1312
        echo $custom_css;
1313
        echo '</style>';
1314
    }
1315
1316
}
1317
add_action( 'wpinv_invoice_print_head', 'wpinv_display_style' );
1318
add_action( 'wpinv_invalid_invoice_head', 'wpinv_display_style' );
1319
1320
function wpinv_checkout_billing_details() {
1321
    $invoice_id = (int)wpinv_get_invoice_cart_id();
1322
    if (empty($invoice_id)) {
1323
        wpinv_error_log( 'Invoice id not found', 'ERROR', __FILE__, __LINE__ );
1324
        return null;
1325
    }
1326
1327
    $invoice = wpinv_get_invoice_cart( $invoice_id );
1328
    if (empty($invoice)) {
1329
        wpinv_error_log( 'Invoice not found', 'ERROR', __FILE__, __LINE__ );
1330
        return null;
1331
    }
1332
    $user_id        = $invoice->get_user_id();
1333
    $user_info      = $invoice->get_user_info();
1334
    $address_info   = wpinv_get_user_address( $user_id );
1335
1336
    if ( empty( $user_info['first_name'] ) && !empty( $user_info['first_name'] ) ) {
1337
        $user_info['first_name'] = $user_info['first_name'];
1338
        $user_info['last_name'] = $user_info['last_name'];
1339
    }
1340
1341
    if ( ( ( empty( $user_info['country'] ) && !empty( $address_info['country'] ) ) || ( empty( $user_info['state'] ) && !empty( $address_info['state'] ) && $user_info['country'] == $address_info['country'] ) ) ) {
1342
        $user_info['country']   = $address_info['country'];
1343
        $user_info['state']     = $address_info['state'];
1344
        $user_info['city']      = $address_info['city'];
1345
        $user_info['zip']       = $address_info['zip'];
1346
    }
1347
1348
    $address_fields = array(
1349
        'user_id',
1350
        'company',
1351
        'vat_number',
1352
        'email',
1353
        'phone',
1354
        'address'
1355
    );
1356
1357
    foreach ( $address_fields as $field ) {
1358
        if ( empty( $user_info[$field] ) ) {
1359
            $user_info[$field] = $address_info[$field];
1360
        }
1361
    }
1362
1363
    return apply_filters( 'wpinv_checkout_billing_details', $user_info, $invoice );
1364
}
1365
1366
function wpinv_admin_get_line_items($invoice = array()) {
1367
    $item_quantities    = wpinv_item_quantities_enabled();
1368
    $use_taxes          = wpinv_use_taxes();
1369
1370
    if ( empty( $invoice ) ) {
1371
        return NULL;
1372
    }
1373
1374
    $cart_items = $invoice->get_cart_details();
1375
    if ( empty( $cart_items ) ) {
1376
        return NULL;
1377
    }
1378
1379
    ob_start();
1380
1381
    do_action( 'wpinv_admin_before_line_items', $cart_items, $invoice );
1382
1383
    $count = 0;
1384
    foreach ( $cart_items as $key => $cart_item ) {
1385
        $item_id    = $cart_item['id'];
1386
        $wpi_item   = $item_id > 0 ? new WPInv_Item( $item_id ) : NULL;
1387
1388
        if (empty($wpi_item)) {
1389
            continue;
1390
        }
1391
1392
        $item_price     = wpinv_price( wpinv_format_amount( $cart_item['item_price'] ), $invoice->get_currency() );
1393
        $quantity       = !empty( $cart_item['quantity'] ) && $cart_item['quantity'] > 0 ? $cart_item['quantity'] : 1;
1394
        $item_subtotal  = wpinv_price( wpinv_format_amount( $cart_item['subtotal'] ), $invoice->get_currency() );
1395
        $can_remove     = true;
1396
1397
        $summary = apply_filters( 'wpinv_admin_invoice_line_item_summary', '', $cart_item, $wpi_item, $invoice );
1398
1399
        $item_tax       = '';
1400
        $tax_rate       = '';
1401
        if ( $invoice->is_taxable() && $cart_item['tax'] > 0 && $cart_item['subtotal'] > 0 ) {
1402
            $item_tax = wpinv_price( wpinv_format_amount( $cart_item['tax'] ), $invoice->get_currency() );
1403
            $tax_rate = !empty( $cart_item['vat_rate'] ) ? $cart_item['vat_rate'] : ( $cart_item['tax'] / $cart_item['subtotal'] ) * 100;
1404
            $tax_rate = $tax_rate > 0 ? (float)wpinv_round_amount( $tax_rate, 4 ) : '';
1405
            $tax_rate = $tax_rate != '' ? ' <span class="tax-rate">(' . $tax_rate . '%)</span>' : '';
1406
        }
1407
        $line_item_tax = $item_tax . $tax_rate;
1408
1409
        if ( $line_item_tax === '' ) {
1410
            $line_item_tax = 0; // Zero tax
1411
        }
1412
1413
        $line_item = '<tr class="item item-' . ( ($count % 2 == 0) ? 'even' : 'odd' ) . '" data-item-id="' . $item_id . '">';
1414
            $line_item .= '<td class="id">' . $item_id . '</td>';
1415
            $line_item .= '<td class="title"><a href="' . get_edit_post_link( $item_id ) . '" target="_blank">' . $cart_item['name'] . '</a>' . wpinv_get_item_suffix( $wpi_item );
1416
            if ( $summary !== '' ) {
1417
                $line_item .= '<span class="meta">' . wpautop( wp_kses_post( $summary ) ) . '</span>';
1418
            }
1419
            $line_item .= '</td>';
1420
            $line_item .= '<td class="price">' . $item_price . '</td>';
1421
            
1422
            if ( $item_quantities ) {
1423
                if ( count( $cart_items ) == 1 && $quantity <= 1 ) {
1424
                    $can_remove = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $can_remove is dead and can be removed.
Loading history...
1425
                }
1426
                $line_item .= '<td class="qty" data-quantity="' . $quantity . '">&nbsp;&times;&nbsp;' . $quantity . '</td>';
1427
            } else {
1428
                if ( count( $cart_items ) == 1 ) {
1429
                    $can_remove = false;
1430
                }
1431
            }
1432
            $line_item .= '<td class="total">' . $item_subtotal . '</td>';
1433
            
1434
            if ( $use_taxes ) {
1435
                $line_item .= '<td class="tax">' . $line_item_tax . '</td>';
1436
            }
1437
            $line_item .= '<td class="action">';
1438
            if ( !$invoice->is_paid() && !$invoice->is_refunded() ) {
1439
                $line_item .= '<i class="fa fa-remove wpinv-item-remove"></i>';
1440
            }
1441
            $line_item .= '</td>';
1442
        $line_item .= '</tr>';
1443
1444
        echo apply_filters( 'wpinv_admin_line_item', $line_item, $cart_item, $invoice );
1445
1446
        $count++;
1447
    } 
1448
1449
    do_action( 'wpinv_admin_after_line_items', $cart_items, $invoice );
1450
1451
    return ob_get_clean();
1452
}
1453
1454
function wpinv_checkout_form() {
1455
    global $wpi_checkout_id, $invoicing;
1456
1457
    // Set current invoice id.
1458
    $wpi_checkout_id = wpinv_get_invoice_cart_id();
1459
    $form_action     = esc_url( wpinv_get_checkout_uri() );
0 ignored issues
show
Bug introduced by
It seems like wpinv_get_checkout_uri() 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

1459
    $form_action     = esc_url( /** @scrutinizer ignore-type */ wpinv_get_checkout_uri() );
Loading history...
1460
    $payment_form    = wpinv_get_default_payment_form();
1461
1462
    ob_start();
1463
	    do_action( 'wpinv_checkout_content_before' );
1464
1465
        if ( wpinv_get_cart_contents() ) {
1466
1467
            // Get the form elements and items.
1468
	        $elements = $invoicing->form_elements->get_form_elements( $payment_form );
1469
	        $items    = $invoicing->form_elements->convert_checkout_items( wpinv_get_cart_contents(), wpinv_get_invoice_cart() );
1470
            ?>
1471
            <form class="wpinv_payment_form" action="<?php echo $form_action; ?>" method="POST">
1472
                <?php do_action( 'wpinv_main_checkout_form_top' ); ?>
1473
                <input type='hidden' name='form_id' value='<?php echo esc_attr( $payment_form ); ?>'/>
1474
                <input type='hidden' name='invoice_id' value='<?php echo esc_attr( $wpi_checkout_id ); ?>'/>
1475
                    <?php
1476
                        wp_nonce_field( 'wpinv_payment_form', 'wpinv_payment_form' );
1477
                        wp_nonce_field( 'vat_validation', '_wpi_nonce' );
1478
1479
                        foreach ( $elements as $element ) {
1480
                            do_action( 'wpinv_frontend_render_payment_form_element', $element, $items, $payment_form );
1481
                            do_action( "wpinv_frontend_render_payment_form_{$element['type']}", $element, $items, $payment_form );
1482
                        }
1483
                    ?>
1484
                <div class='wpinv_payment_form_errors alert alert-danger d-none'></div>
1485
                <?php do_action( 'wpinv_main_checkout_form_bottom' ); ?>
1486
            </form>
1487
        <?php
1488
1489
        } else {
1490
            do_action( 'wpinv_cart_empty' );
1491
        }
1492
        echo '</div><!--end #wpinv_checkout_wrap-->';
1493
	    do_action( 'wpinv_checkout_content_after' );
1494
        $content = ob_get_clean();
1495
1496
		return str_replace( 'sr-only', '', $content );
1497
}
1498
1499
function wpinv_checkout_cart( $cart_details = array(), $echo = true ) {
1500
    global $ajax_cart_details;
1501
    $ajax_cart_details = $cart_details;
1502
1503
    ob_start();
1504
    do_action( 'wpinv_before_checkout_cart' );
1505
    echo '<div id="wpinv_checkout_cart_form" method="post">';
1506
        echo '<div id="wpinv_checkout_cart_wrap">';
1507
            wpinv_get_template_part( 'wpinv-checkout-cart' );
1508
        echo '</div>';
1509
    echo '</div>';
1510
    do_action( 'wpinv_after_checkout_cart' );
1511
    $content = ob_get_clean();
1512
1513
    if ( $echo ) {
1514
        echo $content;
1515
    } else {
1516
        return $content;
1517
    }
1518
}
1519
add_action( 'wpinv_checkout_cart', 'wpinv_checkout_cart', 10 );
1520
1521
function wpinv_empty_cart_message() {
1522
	return apply_filters( 'wpinv_empty_cart_message', '<span class="wpinv_empty_cart">' . __( 'Your cart is empty.', 'invoicing' ) . '</span>' );
1523
}
1524
1525
/**
1526
 * Echoes the Empty Cart Message
1527
 *
1528
 * @since 1.0
1529
 * @return void
1530
 */
1531
function wpinv_empty_checkout_cart() {
1532
    echo aui()->alert(
1533
        array(
1534
            'type'    => 'warning',
1535
            'content' => wpinv_empty_cart_message(),
1536
        )
1537
    );
1538
}
1539
add_action( 'wpinv_cart_empty', 'wpinv_empty_checkout_cart' );
1540
1541
function wpinv_update_cart_button() {
1542
    if ( !wpinv_item_quantities_enabled() )
1543
        return;
1544
?>
1545
    <input type="submit" name="wpinv_update_cart_submit" class="wpinv-submit wpinv-no-js button" value="<?php _e( 'Update Cart', 'invoicing' ); ?>"/>
1546
    <input type="hidden" name="wpi_action" value="update_cart"/>
1547
<?php
1548
}
1549
1550
function wpinv_checkout_cart_columns() {
1551
    $default = 3;
1552
    if ( wpinv_item_quantities_enabled() ) {
1553
        $default++;
1554
    }
1555
    
1556
    if ( wpinv_use_taxes() ) {
1557
        $default++;
1558
    }
1559
1560
    return apply_filters( 'wpinv_checkout_cart_columns', $default );
1561
}
1562
1563
function wpinv_display_cart_messages() {
1564
    global $wpi_session;
1565
1566
    $messages = $wpi_session->get( 'wpinv_cart_messages' );
1567
1568
    if ( $messages ) {
1569
        foreach ( $messages as $message_id => $message ) {
1570
            // Try and detect what type of message this is
1571
            if ( strpos( strtolower( $message ), 'error' ) ) {
1572
                $type = 'error';
1573
            } elseif ( strpos( strtolower( $message ), 'success' ) ) {
1574
                $type = 'success';
1575
            } else {
1576
                $type = 'info';
1577
            }
1578
1579
            $classes = apply_filters( 'wpinv_' . $type . '_class', array( 'wpinv_errors', 'wpinv-alert', 'wpinv-alert-' . $type ) );
1580
1581
            echo '<div class="' . implode( ' ', $classes ) . '">';
1582
                // Loop message codes and display messages
1583
                    echo '<p class="wpinv_error" id="wpinv_msg_' . $message_id . '">' . $message . '</p>';
1584
            echo '</div>';
1585
        }
1586
1587
        // Remove all of the cart saving messages
1588
        $wpi_session->set( 'wpinv_cart_messages', null );
1589
    }
1590
}
1591
add_action( 'wpinv_before_checkout_cart', 'wpinv_display_cart_messages' );
1592
1593
function wpinv_discount_field() {
1594
    if ( isset( $_GET['wpi-gateway'] ) && wpinv_is_ajax_disabled() ) {
1595
        return; // Only show before a payment method has been selected if ajax is disabled
1596
    }
1597
1598
    if ( !wpinv_is_checkout() ) {
1599
        return;
1600
    }
1601
1602
    if ( wpinv_has_active_discounts() && wpinv_get_cart_total() ) {
1603
    ?>
1604
    <div id="wpinv-discount-field" class="panel panel-default">
1605
        <div class="panel-body">
1606
            <p>
1607
                <label class="wpinv-label" for="wpinv_discount_code"><strong><?php _e( 'Discount', 'invoicing' ); ?></strong></label>
1608
                <span class="wpinv-description"><?php _e( 'Enter a discount code if you have one.', 'invoicing' ); ?></span>
1609
            </p>
1610
            <div class="form-group row">
1611
                <div class="col-sm-4">
1612
                    <input class="wpinv-input form-control" type="text" id="wpinv_discount_code" name="wpinv_discount_code" placeholder="<?php _e( 'Enter discount code', 'invoicing' ); ?>"/>
1613
                </div>
1614
                <div class="col-sm-3">
1615
                    <button id="wpi-apply-discount" type="button" class="btn btn-success btn-sm"><?php _e( 'Apply Discount', 'invoicing' ); ?></button>
1616
                </div>
1617
                <div style="clear:both"></div>
1618
                <div class="col-sm-12 wpinv-discount-msg">
1619
                    <div class="alert alert-success"><i class="fa fa-check-circle"></i><span class="wpi-msg"></span></div>
1620
                    <div class="alert alert-error"><i class="fa fa-warning"></i><span class="wpi-msg"></span></div>
1621
                </div>
1622
            </div>
1623
        </div>
1624
    </div>
1625
<?php
1626
    }
1627
}
1628
add_action( 'wpinv_after_checkout_cart', 'wpinv_discount_field', -10 );
1629
1630
function wpinv_agree_to_terms_js() {
1631
    if ( wpinv_get_option( 'show_agree_to_terms', false ) ) {
1632
?>
1633
<script type="text/javascript">
1634
    jQuery(document).ready(function($){
1635
        $( document.body ).on('click', '.wpinv_terms_links', function(e) {
1636
            //e.preventDefault();
1637
            $('#wpinv_terms').slideToggle();
1638
            $('.wpinv_terms_links').toggle();
1639
            return false;
1640
        });
1641
    });
1642
</script>
1643
<?php
1644
    }
1645
}
1646
add_action( 'wpinv_checkout_form_top', 'wpinv_agree_to_terms_js' );
1647
1648
function wpinv_payment_mode_select( $title ) {
1649
    $gateways = wpinv_get_enabled_payment_gateways( true );
1650
    $gateways = apply_filters( 'wpinv_payment_gateways_on_cart', $gateways );
1651
    $invoice = wpinv_get_invoice( 0, true );
1652
1653
    do_action('wpinv_payment_mode_top');
1654
    $invoice_id = $invoice ? (int)$invoice->ID : 0;
1655
    $chosen_gateway = wpinv_get_chosen_gateway( $invoice_id );
1656
    ?>
1657
    <div id="wpinv_payment_mode_select" data-gateway="<?php echo $chosen_gateway; ?>" <?php echo ( ( $invoice && $invoice->is_free() ) ? 'style="display:none;" data-free="1"' : '' ); ?>>
1658
            <?php do_action( 'wpinv_payment_mode_before_gateways_wrap' ); ?>
1659
            <div id="wpinv-payment-mode-wrap" class="panel panel-default">
1660
                <div class="panel-heading wpi-payment_methods_title">
1661
                    <h6 class="panel-title"><?php echo sanitize_text_field( $title ); ?></h6>
1662
                </div>
1663
                <div class="panel-body wpi-payment_methods">
1664
                    <?php
1665
                    do_action( 'wpinv_payment_mode_before_gateways' );
1666
1667
                    if ( !empty( $gateways ) ) {
1668
                        foreach ( $gateways as $gateway_id => $gateway ) {
1669
                            $checked       = checked( $gateway_id, $chosen_gateway, false );
1670
                            $button_label  = wpinv_get_gateway_button_label( $gateway_id );
1671
                            $gateway_label = wpinv_get_gateway_checkout_label( $gateway_id );
1672
                            $description   = wpinv_get_gateway_description( $gateway_id );
1673
                            ?>
1674
                            <div class="pt-2 pb-2">
1675
                                <div class="radio">
1676
                                    <label><input type="radio" data-button-text="<?php echo esc_attr( $button_label );?>" value="<?php echo esc_attr( $gateway_id ) ;?>" <?php echo $checked ;?> id="wpi_gateway_<?php echo esc_attr( $gateway_id );?>" name="wpi-gateway" class="wpi-pmethod"><?php echo esc_html( $gateway_label ); ?></label>
1677
                                </div>
1678
                                <div style="display:none;" class="payment_box wpi_gateway_<?php echo esc_attr( $gateway_id );?>" role="alert">
1679
                                    <?php if ( !empty( $description ) ) { ?>
1680
                                        <div class="wpi-gateway-desc"><?php _e( $description, 'invoicing' ); ?></div>
1681
                                    <?php } ?>
1682
                                    <?php do_action( 'wpinv_' . $gateway_id . '_cc_form', $invoice_id ) ;?>
1683
                                </div>
1684
                            </div>
1685
                            <?php
1686
                        }
1687
                    } else {
1688
                        echo '<div class="alert alert-danger">'. __( 'No payment gateway active', 'invoicing' ) .'</div>';
1689
                    }
1690
1691
                    do_action( 'wpinv_payment_mode_after_gateways' );
1692
                    ?>
1693
                </div>
1694
            </div>
1695
            <?php do_action( 'wpinv_payment_mode_after_gateways_wrap' ); ?>
1696
    </div>
1697
    <?php
1698
    do_action('wpinv_payment_mode_bottom');
1699
}
1700
add_action( 'wpinv_payment_mode_select', 'wpinv_payment_mode_select' );
1701
1702
function wpinv_checkout_billing_info() {
1703
    if ( wpinv_is_checkout() ) {
1704
        $billing_details    = wpinv_checkout_billing_details();
1705
        $selected_country   = !empty( $billing_details['country'] ) ? $billing_details['country'] : wpinv_default_billing_country();
1706
        ?>
1707
        <div id="wpinv-fields" class="clearfix">
1708
            <div id="wpi-billing" class="wpi-billing clearfix panel panel-default">
1709
                <div class="panel-heading"><h3 class="panel-title"><?php _e( 'Billing Details', 'invoicing' );?></h3></div>
1710
                <div id="wpinv-fields-box" class="panel-body">
1711
                    <?php do_action( 'wpinv_checkout_billing_fields_first', $billing_details ); ?>
1712
                    <p class="wpi-cart-field wpi-col2 wpi-colf">
1713
                        <label for="wpinv_first_name" class="wpi-label"><?php _e( 'First Name', 'invoicing' );?><?php if ( wpinv_get_option( 'fname_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1714
                        <?php
1715
                        echo wpinv_html_text( array(
1716
                                'id'            => 'wpinv_first_name',
1717
                                'name'          => 'wpinv_first_name',
1718
                                'value'         => $billing_details['first_name'],
1719
                                'class'         => 'wpi-input form-control',
1720
                                'placeholder'   => __( 'First name', 'invoicing' ),
1721
                                'required'      => (bool)wpinv_get_option( 'fname_mandatory' ),
1722
                            ) );
1723
                        ?>
1724
                    </p>
1725
                    <p class="wpi-cart-field wpi-col2 wpi-coll">
1726
                        <label for="wpinv_last_name" class="wpi-label"><?php _e( 'Last Name', 'invoicing' );?><?php if ( wpinv_get_option( 'lname_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1727
                        <?php
1728
                        echo wpinv_html_text( array(
1729
                                'id'            => 'wpinv_last_name',
1730
                                'name'          => 'wpinv_last_name',
1731
                                'value'         => $billing_details['last_name'],
1732
                                'class'         => 'wpi-input form-control',
1733
                                'placeholder'   => __( 'Last name', 'invoicing' ),
1734
                                'required'      => (bool)wpinv_get_option( 'lname_mandatory' ),
1735
                            ) );
1736
                        ?>
1737
                    </p>
1738
                    <p class="wpi-cart-field wpi-col2 wpi-colf">
1739
                        <label for="wpinv_address" class="wpi-label"><?php _e( 'Address', 'invoicing' );?><?php if ( wpinv_get_option( 'address_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1740
                        <?php
1741
                        echo wpinv_html_text( array(
1742
                                'id'            => 'wpinv_address',
1743
                                'name'          => 'wpinv_address',
1744
                                'value'         => $billing_details['address'],
1745
                                'class'         => 'wpi-input form-control',
1746
                                'placeholder'   => __( 'Address', 'invoicing' ),
1747
                                'required'      => (bool)wpinv_get_option( 'address_mandatory' ),
1748
                            ) );
1749
                        ?>
1750
                    </p>
1751
                    <p class="wpi-cart-field wpi-col2 wpi-coll">
1752
                        <label for="wpinv_city" class="wpi-label"><?php _e( 'City', 'invoicing' );?><?php if ( wpinv_get_option( 'city_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1753
                        <?php
1754
                        echo wpinv_html_text( array(
1755
                                'id'            => 'wpinv_city',
1756
                                'name'          => 'wpinv_city',
1757
                                'value'         => $billing_details['city'],
1758
                                'class'         => 'wpi-input form-control',
1759
                                'placeholder'   => __( 'City', 'invoicing' ),
1760
                                'required'      => (bool)wpinv_get_option( 'city_mandatory' ),
1761
                            ) );
1762
                        ?>
1763
                    </p>
1764
                    <p id="wpinv_country_box" class="wpi-cart-field wpi-col2 wpi-colf">
1765
                        <label for="wpinv_country" class="wpi-label"><?php _e( 'Country', 'invoicing' );?><?php if ( wpinv_get_option( 'country_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1766
                        <?php echo wpinv_html_select( array(
1767
                            'options'          => wpinv_get_country_list(),
1768
                            'name'             => 'wpinv_country',
1769
                            'id'               => 'wpinv_country',
1770
                            'selected'         => $selected_country,
1771
                            'show_option_all'  => false,
1772
                            'show_option_none' => false,
1773
                            'class'            => 'wpi-input form-control wpi_select2',
1774
                            'placeholder'      => __( 'Choose a country', 'invoicing' ),
1775
                            'required'         => (bool)wpinv_get_option( 'country_mandatory' ),
1776
                        ) ); ?>
1777
                    </p>
1778
                    <p id="wpinv_state_box" class="wpi-cart-field wpi-col2 wpi-coll">
1779
                        <label for="wpinv_state" class="wpi-label"><?php _e( 'State / Province', 'invoicing' );?><?php if ( wpinv_get_option( 'state_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1780
                        <?php
1781
                        $states = wpinv_get_country_states( $selected_country );
1782
                        if( !empty( $states ) ) {
1783
                            echo wpinv_html_select( array(
1784
                                'options'          => $states,
1785
                                'name'             => 'wpinv_state',
1786
                                'id'               => 'wpinv_state',
1787
                                'selected'         => $billing_details['state'],
1788
                                'show_option_all'  => false,
1789
                                'show_option_none' => false,
1790
                                'class'            => 'wpi-input form-control wpi_select2',
1791
                                'placeholder'      => __( 'Choose a state', 'invoicing' ),
1792
                                'required'         => (bool)wpinv_get_option( 'state_mandatory' ),
1793
                            ) );
1794
                        } else {
1795
                            echo wpinv_html_text( array(
1796
                                'name'          => 'wpinv_state',
1797
                                'value'         => $billing_details['state'],
1798
                                'id'            => 'wpinv_state',
1799
                                'class'         => 'wpi-input form-control',
1800
                                'placeholder'   => __( 'State / Province', 'invoicing' ),
1801
                                'required'      => (bool)wpinv_get_option( 'state_mandatory' ),
1802
                            ) );
1803
                        }
1804
                        ?>
1805
                    </p>
1806
                    <p class="wpi-cart-field wpi-col2 wpi-colf">
1807
                        <label for="wpinv_zip" class="wpi-label"><?php _e( 'ZIP / Postcode', 'invoicing' );?><?php if ( wpinv_get_option( 'zip_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1808
                        <?php
1809
                        echo wpinv_html_text( array(
1810
                                'name'          => 'wpinv_zip',
1811
                                'value'         => $billing_details['zip'],
1812
                                'id'            => 'wpinv_zip',
1813
                                'class'         => 'wpi-input form-control',
1814
                                'placeholder'   => __( 'ZIP / Postcode', 'invoicing' ),
1815
                                'required'      => (bool)wpinv_get_option( 'zip_mandatory' ),
1816
                            ) );
1817
                        ?>
1818
                    </p>
1819
                    <p class="wpi-cart-field wpi-col2 wpi-coll">
1820
                        <label for="wpinv_phone" class="wpi-label"><?php _e( 'Phone', 'invoicing' );?><?php if ( wpinv_get_option( 'phone_mandatory' ) ) { echo '<span class="wpi-required">*</span>'; } ?></label>
1821
                        <?php
1822
                        echo wpinv_html_text( array(
1823
                                'id'            => 'wpinv_phone',
1824
                                'name'          => 'wpinv_phone',
1825
                                'value'         => $billing_details['phone'],
1826
                                'class'         => 'wpi-input form-control',
1827
                                'placeholder'   => __( 'Phone', 'invoicing' ),
1828
                                'required'      => (bool)wpinv_get_option( 'phone_mandatory' ),
1829
                            ) );
1830
                        ?>
1831
                    </p>
1832
                    <?php do_action( 'wpinv_checkout_billing_fields_last', $billing_details ); ?>
1833
                    <div class="clearfix"></div>
1834
                </div>
1835
            </div>
1836
            <?php do_action( 'wpinv_after_billing_fields', $billing_details ); ?>
1837
        </div>
1838
        <?php
1839
    }
1840
}
1841
add_action( 'wpinv_checkout_billing_info', 'wpinv_checkout_billing_info' );
1842
1843
function wpinv_checkout_hidden_fields() {
1844
?>
1845
    <?php if ( is_user_logged_in() ) { ?>
1846
    <input type="hidden" name="wpinv_user_id" value="<?php echo get_current_user_id(); ?>"/>
1847
    <?php } ?>
1848
    <input type="hidden" name="wpi_action" value="payment" />
1849
<?php
1850
}
1851
1852
function wpinv_checkout_button_purchase() {
1853
    ob_start();
1854
?>
1855
    <input type="submit" class="btn btn-success wpinv-submit" id="wpinv-payment-button" data-value="<?php esc_attr_e( 'Proceed to Pay', 'invoicing' ) ?>" name="wpinv_payment" value="<?php esc_attr_e( 'Proceed to Pay', 'invoicing' ) ?>"/>
1856
<?php
1857
    return apply_filters( 'wpinv_checkout_button_purchase', ob_get_clean() );
1858
}
1859
1860
function wpinv_checkout_total() {
1861
    global $cart_total;
1862
?>
1863
<div id="wpinv_checkout_total" class="panel panel-info">
1864
    <div class="panel-body">
1865
    <?php
1866
    do_action( 'wpinv_purchase_form_before_checkout_total' );
1867
    ?>
1868
    <strong><?php _e( 'Invoice Total:', 'invoicing' ) ?></strong> <span class="wpinv-chdeckout-total"><?php echo $cart_total;?></span>
1869
    <?php
1870
    do_action( 'wpinv_purchase_form_after_checkout_total' );
1871
    ?>
1872
    </div>
1873
</div>
1874
<?php
1875
}
1876
add_action( 'wpinv_checkout_form_bottom', 'wpinv_checkout_total', 9998 );
1877
1878
function wpinv_checkout_submit() {
1879
?>
1880
<div id="wpinv_purchase_submit" class="panel panel-success">
1881
    <div class="panel-body text-center">
1882
    <?php
1883
    do_action( 'wpinv_purchase_form_before_submit' );
1884
    wpinv_checkout_hidden_fields();
1885
    echo wpinv_checkout_button_purchase();
1886
    do_action( 'wpinv_purchase_form_after_submit' );
1887
    ?>
1888
    </div>
1889
</div>
1890
<?php
1891
}
1892
add_action( 'wpinv_checkout_form_bottom', 'wpinv_checkout_submit', 9999 );
1893
1894
function wpinv_receipt_billing_address( $invoice_id = 0 ) {
1895
    $invoice = wpinv_get_invoice( $invoice_id );
1896
1897
    if ( empty( $invoice ) ) {
1898
        return NULL;
1899
    }
1900
1901
    $billing_details = $invoice->get_user_info();
1902
    $address_row = wpinv_get_invoice_address_markup( $billing_details );
1903
1904
    ob_start();
1905
    ?>
1906
    <table class="table table-bordered table-sm wpi-billing-details">
1907
        <tbody>
1908
            <tr class="wpi-receipt-name">
1909
                <th class="text-left"><?php _e( 'Name', 'invoicing' ); ?></th>
1910
                <td><?php echo esc_html( trim( $billing_details['first_name'] . ' ' . $billing_details['last_name'] ) ) ;?></td>
1911
            </tr>
1912
            <tr class="wpi-receipt-email">
1913
                <th class="text-left"><?php _e( 'Email', 'invoicing' ); ?></th>
1914
                <td><?php echo $billing_details['email'] ;?></td>
1915
            </tr>
1916
            <tr class="wpi-receipt-address">
1917
                <th class="text-left"><?php _e( 'Address', 'invoicing' ); ?></th>
1918
                <td><?php echo $address_row ;?></td>
1919
            </tr>
1920
            <?php if ( $billing_details['phone'] ) { ?>
1921
            <tr class="wpi-receipt-phone">
1922
                <th class="text-left"><?php _e( 'Phone', 'invoicing' ); ?></th>
1923
                <td><?php echo esc_html( $billing_details['phone'] ) ;?></td>
1924
            </tr>
1925
            <?php } ?>
1926
        </tbody>
1927
    </table>
1928
    <?php
1929
    $output = ob_get_clean();
1930
    
1931
    $output = apply_filters( 'wpinv_receipt_billing_address', $output, $invoice_id );
1932
1933
    echo $output;
1934
}
1935
1936
function wpinv_filter_success_page_content( $content ) {
1937
    if ( isset( $_GET['payment-confirm'] ) && wpinv_is_success_page() ) {
1938
        if ( has_filter( 'wpinv_payment_confirm_' . sanitize_text_field( $_GET['payment-confirm'] ) ) ) {
1939
            $content = apply_filters( 'wpinv_payment_confirm_' . sanitize_text_field( $_GET['payment-confirm'] ), $content );
1940
        }
1941
    }
1942
1943
    return $content;
1944
}
1945
add_filter( 'the_content', 'wpinv_filter_success_page_content', 99999 );
1946
1947
function wpinv_receipt_actions( $invoice ) {
1948
    if ( !empty( $invoice ) ) {
1949
        $actions = array();
1950
1951
        if ( wpinv_user_can_view_invoice( $invoice->ID ) ) {
1952
            $actions['print']   = array(
1953
                'url'  => $invoice->get_view_url( true ),
1954
                'name' => __( 'Print Invoice', 'invoicing' ),
1955
                'class' => 'btn-primary',
1956
            );
1957
        }
1958
1959
        if ( is_user_logged_in() ) {
1960
            $actions['history'] = array(
1961
                'url'  => wpinv_get_history_page_uri(),
1962
                'name' => __( 'Invoice History', 'invoicing' ),
1963
                'class' => 'btn-warning',
1964
            );
1965
        }
1966
1967
        $actions = apply_filters( 'wpinv_invoice_receipt_actions', $actions, $invoice );
1968
1969
        if ( !empty( $actions ) ) {
1970
        ?>
1971
        <div class="wpinv-receipt-actions text-right">
1972
            <?php foreach ( $actions as $key => $action ) { $class = !empty($action['class']) ? sanitize_html_class( $action['class'] ) : ''; ?>
1973
            <a href="<?php echo esc_url( $action['url'] );?>" class="btn btn-sm <?php echo $class . ' ' . sanitize_html_class( $key );?>" <?php echo ( !empty($action['attrs']) ? $action['attrs'] : '' ) ;?>><?php echo esc_html( $action['name'] );?></a>
1974
            <?php } ?>
1975
        </div>
1976
        <?php
1977
        }
1978
    }
1979
}
1980
add_action( 'wpinv_receipt_start', 'wpinv_receipt_actions', -10, 1 );
1981
1982
function wpinv_invoice_link( $invoice_id ) {
1983
    $invoice = wpinv_get_invoice( $invoice_id );
1984
1985
    if ( empty( $invoice ) ) {
1986
        return NULL;
1987
    }
1988
1989
    $invoice_link = '<a href="' . esc_url( $invoice->get_view_url() ) . '">' . $invoice->get_number() . '</a>';
1990
1991
    return apply_filters( 'wpinv_get_invoice_link', $invoice_link, $invoice );
1992
}
1993
1994
function wpinv_invoice_subscription_details( $invoice ) {
1995
    if ( !empty( $invoice ) && $invoice->is_recurring() && ! wpinv_is_subscription_payment( $invoice ) ) {
1996
        $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

1996
        $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...
1997
1998
        if ( empty( $subscription ) ) {
1999
            return;
2000
        }
2001
2002
        $frequency = WPInv_Subscriptions::wpinv_get_pretty_subscription_frequency($subscription->period, $subscription->frequency);
2003
        $billing = wpinv_price(wpinv_format_amount($subscription->recurring_amount), wpinv_get_invoice_currency_code($subscription->parent_payment_id)) . ' / ' . $frequency;
2004
        $initial = wpinv_price(wpinv_format_amount($subscription->initial_amount), wpinv_get_invoice_currency_code($subscription->parent_payment_id));
2005
2006
        $payments = $subscription->get_child_payments();
2007
        ?>
2008
        <div class="wpinv-subscriptions-details">
2009
            <h3 class="wpinv-subscriptions-t"><?php echo apply_filters( 'wpinv_subscription_details_title', __( 'Subscription Details', 'invoicing' ) ); ?></h3>
2010
            <table class="table">
2011
                <thead>
2012
                    <tr>
2013
                        <th><?php _e( 'Billing Cycle', 'invoicing' ) ;?></th>
2014
                        <th><?php _e( 'Start Date', 'invoicing' ) ;?></th>
2015
                        <th><?php _e( 'Expiration Date', 'invoicing' ) ;?></th>
2016
                        <th class="text-center"><?php _e( 'Times Billed', 'invoicing' ) ;?></th>
2017
                        <th class="text-center"><?php _e( 'Status', 'invoicing' ) ;?></th>
2018
                    </tr>
2019
                </thead>
2020
                <tbody>
2021
                    <tr>
2022
                        <td><?php printf(_x('%s then %s', 'Initial subscription amount then billing cycle and amount', 'invoicing'), $initial, $billing); ?></td>
2023
                        <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

2023
                        <td><?php echo date_i18n(/** @scrutinizer ignore-type */ get_option('date_format'), strtotime($subscription->created, current_time('timestamp'))); ?></td>
Loading history...
2024
                        <td><?php echo date_i18n(get_option('date_format'), strtotime($subscription->expiration, current_time('timestamp'))); ?></td>
2025
                        <td class="text-center"><?php echo $subscription->get_times_billed() . ' / ' . (($subscription->bill_times == 0) ? 'Until Cancelled' : $subscription->bill_times); ?></td>
2026
                        <td class="text-center wpi-sub-status"><?php echo $subscription->get_status_label(); ?></td>
2027
                    </tr>
2028
                </tbody>
2029
            </table>
2030
        </div>
2031
        <?php if ( !empty( $payments ) ) { ?>
2032
        <div class="wpinv-renewal-payments">
2033
            <h3 class="wpinv-renewals-t"><?php echo apply_filters( 'wpinv_renewal_payments_title', __( 'Renewal Payments', 'invoicing' ) ); ?></h3>
2034
            <table class="table">
2035
                <thead>
2036
                    <tr>
2037
                        <th>#</th>
2038
                        <th><?php _e( 'Invoice', 'invoicing' ) ;?></th>
2039
                        <th><?php _e( 'Date', 'invoicing' ) ;?></th>
2040
                        <th class="text-right"><?php _e( 'Amount', 'invoicing' ) ;?></th>
2041
                    </tr>
2042
                </thead>
2043
                <tbody>
2044
                    <?php
2045
                        $i = 1;
2046
                        foreach ( $payments as $payment ) {
2047
                            $invoice_id = $payment->ID;
2048
                    ?>
2049
                    <tr>
2050
                        <th scope="row"><?php echo $i;?></th>
2051
                        <td><?php echo wpinv_invoice_link( $invoice_id ) ;?></td>
2052
                        <td><?php echo wpinv_get_invoice_date( $invoice_id ); ?></td>
2053
                        <td class="text-right"><?php echo wpinv_payment_total( $invoice_id, true ); ?></td>
2054
                    </tr>
2055
                    <?php $i++; } ?>
2056
                </tbody>
2057
            </table>
2058
        </div>
2059
        <?php } ?>
2060
        <?php
2061
    }
2062
}
2063
2064
function wpinv_cart_total_label( $label, $invoice ) {
2065
    if ( empty( $invoice ) ) {
2066
        return $label;
2067
    }
2068
2069
    $prefix_label = '';
2070
    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...
2071
        $prefix_label   = '<span class="label label-primary label-recurring">' . __( 'Recurring Payment', 'invoicing' ) . '</span> ' . wpinv_subscription_payment_desc( $invoice );
2072
    } else if ( $invoice->is_renewal() ) {
2073
        $prefix_label   = '<span class="label label-primary label-renewal">' . __( 'Renewal Payment', 'invoicing' ) . '</span> ';        
2074
    }
2075
2076
    if ( $prefix_label != '' ) {
2077
        $label  = '<span class="wpinv-cart-sub-desc">' . $prefix_label . '</span> ' . $label;
2078
    }
2079
2080
    return $label;
2081
}
2082
add_filter( 'wpinv_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
2083
add_filter( 'wpinv_email_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
2084
add_filter( 'wpinv_print_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
2085
2086
add_action( 'wpinv_invoice_print_middle', 'wpinv_invoice_subscription_details', 10, 1 );
2087
2088
function wpinv_invoice_print_description( $invoice ) {
2089
    if ( empty( $invoice ) ) {
2090
        return NULL;
2091
    }
2092
    if ( $description = wpinv_get_invoice_description( $invoice->ID ) ) {
2093
        ?>
2094
        <div class="row wpinv-lower">
2095
            <div class="col-sm-12 wpinv-description">
2096
                <?php echo wpautop( $description ); ?>
2097
            </div>
2098
        </div>
2099
        <?php
2100
    }
2101
}
2102
add_action( 'wpinv_invoice_print_middle', 'wpinv_invoice_print_description', 10.1, 1 );
0 ignored issues
show
Bug introduced by
10.1 of type double is incompatible with the type integer expected by parameter $priority of add_action(). ( Ignorable by Annotation )

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

2102
add_action( 'wpinv_invoice_print_middle', 'wpinv_invoice_print_description', /** @scrutinizer ignore-type */ 10.1, 1 );
Loading history...
2103
2104
function wpinv_invoice_print_payment_info( $invoice ) {
2105
    if ( empty( $invoice ) ) {
2106
        return NULL;
2107
    }
2108
2109
    if ( $payments_info = wpinv_display_payments_info( $invoice->ID, false ) ) {
2110
        ?>
2111
        <div class="row wpinv-payments">
2112
            <div class="col-sm-12">
2113
                <?php echo $payments_info; ?>
2114
            </div>
2115
        </div>
2116
        <?php 
2117
    }
2118
}
2119
// add_action( 'wpinv_invoice_print_after_line_items', 'wpinv_invoice_print_payment_info', 10, 1 );
2120
2121
function wpinv_get_invoice_note_line_item( $note, $echo = true ) {
2122
    if ( empty( $note ) ) {
2123
        return NULL;
2124
    }
2125
2126
    if ( is_int( $note ) ) {
2127
        $note = get_comment( $note );
2128
    }
2129
2130
    if ( !( is_object( $note ) && is_a( $note, 'WP_Comment' ) ) ) {
2131
        return NULL;
2132
    }
2133
2134
    $note_classes   = array( 'note' );
2135
    $note_classes[] = get_comment_meta( $note->comment_ID, '_wpi_customer_note', true ) ? 'customer-note' : '';
2136
    $note_classes[] = $note->comment_author === 'System' ? 'system-note' : '';
2137
    $note_classes   = apply_filters( 'wpinv_invoice_note_class', array_filter( $note_classes ), $note );
2138
    $note_classes   = !empty( $note_classes ) ? implode( ' ', $note_classes ) : '';
2139
2140
    ob_start();
2141
    ?>
2142
    <li rel="<?php echo absint( $note->comment_ID ) ; ?>" class="<?php echo esc_attr( $note_classes ); ?>">
2143
        <div class="note_content">
2144
            <?php echo wpautop( wptexturize( wp_kses_post( $note->comment_content ) ) ); ?>
2145
        </div>
2146
        <p class="meta">
2147
            <abbr class="exact-date" title="<?php echo $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;
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

2147
            <abbr class="exact-date" title="<?php echo $note->comment_date; ?>"><?php printf( __( '%1$s - %2$s at %3$s', 'invoicing' ), $note->comment_author, date_i18n( /** @scrutinizer ignore-type */ get_option( 'date_format' ), strtotime( $note->comment_date ) ), date_i18n( get_option( 'time_format' ), strtotime( $note->comment_date ) ) ); ?></abbr>&nbsp;&nbsp;
Loading history...
2148
            <?php if ( is_admin() && ( $note->comment_author !== 'System' || wpinv_current_user_can_manage_invoicing() ) ) { ?>
2149
                <a href="#" class="delete_note"><?php _e( 'Delete note', 'invoicing' ); ?></a>
2150
            <?php } ?>
2151
        </p>
2152
    </li>
2153
    <?php
2154
    $note_content = ob_get_clean();
2155
    $note_content = apply_filters( 'wpinv_get_invoice_note_line_item', $note_content, $note, $echo );
2156
2157
    if ( $echo ) {
2158
        echo $note_content;
2159
    } else {
2160
        return $note_content;
2161
    }
2162
}
2163
2164
function wpinv_invalid_invoice_content() {
2165
    global $post;
2166
2167
    $invoice = wpinv_get_invoice( $post->ID );
2168
2169
    $error = __( 'This invoice is only viewable by clicking on the invoice link that was sent to you via email.', 'invoicing' );
2170
    if ( !empty( $invoice->ID ) && $invoice->has_status( array_keys( wpinv_get_invoice_statuses() ) ) ) {
2171
        if ( is_user_logged_in() ) {
2172
            if ( wpinv_require_login_to_checkout() ) {
2173
                if ( isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
2174
                    $error = __( 'You are not allowed to view this invoice.', 'invoicing' );
2175
                }
2176
            }
2177
        } else {
2178
            if ( wpinv_require_login_to_checkout() ) {
2179
                if ( isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
2180
                    $error = __( 'You must be logged in to view this invoice.', 'invoicing' );
2181
                }
2182
            }
2183
        }
2184
    } else {
2185
        $error = __( 'This invoice is deleted or does not exist.', 'invoicing' );
2186
    }
2187
    ?>
2188
    <div class="row wpinv-row-invalid">
2189
        <div class="col-md-6 col-md-offset-3 wpinv-message error">
2190
            <h3><?php _e( 'Access Denied', 'invoicing' ); ?></h3>
2191
            <p class="wpinv-msg-text"><?php echo $error; ?></p>
2192
        </div>
2193
    </div>
2194
    <?php
2195
}
2196
add_action( 'wpinv_invalid_invoice_content', 'wpinv_invalid_invoice_content' );
2197
2198
add_action( 'wpinv_checkout_billing_fields_last', 'wpinv_force_company_name_field');
2199
function wpinv_force_company_name_field(){
2200
    $invoice = wpinv_get_invoice_cart();
2201
    $user_id = wpinv_get_user_id( $invoice->ID );
2202
    $company = empty( $user_id ) ? "" : get_user_meta( $user_id, '_wpinv_company', true );
2203
    if ( 1 == wpinv_get_option( 'force_show_company' ) && !wpinv_use_taxes() ) {
2204
        ?>
2205
        <p class="wpi-cart-field wpi-col2 wpi-colf">
2206
            <label for="wpinv_company" class="wpi-label"><?php _e('Company Name', 'invoicing'); ?></label>
2207
            <?php
2208
            echo wpinv_html_text(array(
2209
                'id' => 'wpinv_company',
2210
                'name' => 'wpinv_company',
2211
                'value' => $company,
2212
                'class' => 'wpi-input form-control',
2213
                'placeholder' => __('Company name', 'invoicing'),
2214
                'required'      => true,
2215
            ));
2216
            ?>
2217
        </p>
2218
        <?php
2219
    }
2220
}
2221
2222
/**
2223
 * Function to get privacy policy text.
2224
 *
2225
 * @since 1.0.13
2226
 * @return string
2227
 */
2228
function wpinv_get_policy_text() {
2229
    $privacy_page_id = get_option( 'wp_page_for_privacy_policy', 0 );
2230
2231
    $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]' ));
2232
2233
    if(!$privacy_page_id){
2234
        $privacy_page_id = wpinv_get_option( 'privacy_page', 0 );
2235
    }
2236
2237
    $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

2237
    $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...
2238
2239
    $find_replace = array(
2240
        '[wpinv_privacy_policy]' => $privacy_link,
2241
    );
2242
2243
    $privacy_text = str_replace( array_keys( $find_replace ), array_values( $find_replace ), $text );
2244
2245
    return wp_kses_post(wpautop($privacy_text));
2246
}
2247
2248
2249
/**
2250
 * Allows the user to set their own price for an invoice item
2251
 */
2252
function wpinv_checkout_cart_item_name_your_price( $cart_item, $key ) {
2253
    
2254
    //Ensure we have an item id
2255
    if(! is_array( $cart_item ) || empty( $cart_item['id'] ) ) {
2256
        return;
2257
    }
2258
2259
    //Fetch the item
2260
    $item_id = $cart_item['id'];
2261
    $item    = new WPInv_Item( $item_id );
2262
    
2263
    if(! $item->supports_dynamic_pricing() || !$item->get_is_dynamic_pricing() ) {
2264
        return;
2265
    }
2266
2267
    //Fetch the dynamic pricing "strings"
2268
    $suggested_price_text = esc_html( wpinv_get_option( 'suggested_price_text', __( 'Suggested Price:', 'invoicing' ) ) );
2269
    $minimum_price_text   = esc_html( wpinv_get_option( 'minimum_price_text', __( 'Minimum Price:', 'invoicing' ) ) );
2270
    $name_your_price_text = esc_html( wpinv_get_option( 'name_your_price_text', __( 'Name Your Price', 'invoicing' ) ) );
2271
2272
    //Display a "name_your_price" button
2273
    echo " &mdash; <a href='#' class='wpinv-name-your-price-frontend small'>$name_your_price_text</a></div>";
2274
2275
    //Display a name_your_price form
2276
    echo '<div class="name-your-price-miniform">';
2277
    
2278
    //Maybe display the recommended price
2279
    if( $item->get_price() > 0 && !empty( $suggested_price_text ) ) {
2280
        $suggested_price = $item->get_the_price();
2281
        echo "<div>$suggested_price_text &mdash; $suggested_price</div>";
2282
    }
2283
2284
    //Display the update price form
2285
    $symbol         = wpinv_currency_symbol();
2286
    $position       = wpinv_currency_position();
2287
    $minimum        = esc_attr( $item->get_minimum_price() );
2288
    $price          = esc_attr( $cart_item['item_price'] );
2289
    $update         = esc_attr__( "Update", 'invoicing' );
2290
2291
    //Ensure it supports dynamic prici
2292
    if( $price < $minimum ) {
2293
        $price = $minimum;
2294
    }
2295
2296
    echo '<label>';
2297
    echo $position != 'right' ? $symbol . '&nbsp;' : '';
2298
    echo "<input type='number' min='$minimum' placeholder='$price' value='$price' class='wpi-field-price' />";
2299
    echo $position == 'right' ? '&nbsp;' . $symbol : '' ;
2300
    echo "</label>";
2301
    echo "<input type='hidden' value='$item_id' class='wpi-field-item' />";
2302
    echo "<a class='btn btn-success wpinv-submit wpinv-update-dynamic-price-frontend'>$update</a>";
2303
2304
    //Maybe display the minimum price
2305
    if( $item->get_minimum_price() > 0 && !empty( $minimum_price_text ) ) {
2306
        $minimum_price = wpinv_price( wpinv_format_amount( $item->get_minimum_price() ) );
2307
        echo "<div>$minimum_price_text &mdash; $minimum_price</div>";
2308
    }
2309
2310
    echo "</div>";
2311
2312
}
2313
add_action( 'wpinv_checkout_cart_item_price_after', 'wpinv_checkout_cart_item_name_your_price', 10, 2 );
2314
2315
function wpinv_oxygen_fix_conflict() {
2316
    global $ct_ignore_post_types;
2317
2318
    if ( ! is_array( $ct_ignore_post_types ) ) {
2319
        $ct_ignore_post_types = array();
2320
    }
2321
2322
    $post_types = array( 'wpi_discount', 'wpi_invoice', 'wpi_item' );
2323
2324
    foreach ( $post_types as $post_type ) {
2325
        $ct_ignore_post_types[] = $post_type;
2326
2327
        // Ignore post type
2328
        add_filter( 'pre_option_oxygen_vsb_ignore_post_type_' . $post_type, '__return_true', 999 );
2329
    }
2330
2331
    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

2331
    /** @scrutinizer ignore-call */ 
2332
    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...
2332
    add_filter( 'template_include', 'wpinv_template', 999, 1 );
2333
}
2334
2335
/**
2336
 * Helper function to display a payment form on the frontend.
2337
 */
2338
function getpaid_display_payment_form( $form ) {
2339
    global $invoicing;
2340
2341
    // Ensure that it is published.
2342
	if ( 'publish' != get_post_status( $form ) ) {
2343
		return aui()->alert(
2344
			array(
2345
				'type'    => 'warning',
2346
				'content' => __( 'This payment form is no longer active', 'invoicing' ),
2347
			)
2348
		);
2349
	}
2350
2351
    // Get the form.
2352
    $form = new GetPaid_Payment_Form( $form );
2353
    $html = wpinv_get_template_html( 'payment-forms/form.php', compact( 'form' ) );
2354
    return str_replace( 'sr-only', '', $html );
2355
2356
}
2357
2358
/**
2359
 * Helper function to display a item payment form on the frontend.
2360
 */
2361
function getpaid_display_item_payment_form( $items ) {
2362
    global $invoicing;
2363
2364
    foreach ( array_keys( $items ) as $id ) {
2365
	    if ( 'publish' != get_post_status( $id ) ) {
2366
		    unset( $items[ $id ] );
2367
	    }
2368
    }
2369
2370
    if ( empty( $items ) ) {
2371
		return aui()->alert(
2372
			array(
2373
				'type'    => 'warning',
2374
				'content' => __( 'No published items found', 'invoicing' ),
2375
			)
2376
		);
2377
    }
2378
2379
    $item_key = getpaid_convert_items_to_string( $items );
2380
2381
    // Get the form elements and items.
2382
    $form     = wpinv_get_default_payment_form();
2383
	$elements = $invoicing->form_elements->get_form_elements( $form );
2384
	$items    = $invoicing->form_elements->convert_normal_items( $items );
2385
2386
	ob_start();
2387
	echo "<form class='wpinv_payment_form'>";
2388
	do_action( 'wpinv_payment_form_top' );
2389
    echo "<input type='hidden' name='form_id' value='$form'/>";
2390
    echo "<input type='hidden' name='form_items' value='$item_key'/>";
2391
	wp_nonce_field( 'wpinv_payment_form', 'wpinv_payment_form' );
2392
	wp_nonce_field( 'vat_validation', '_wpi_nonce' );
2393
2394
	foreach ( $elements as $element ) {
2395
		do_action( 'wpinv_frontend_render_payment_form_element', $element, $items, $form );
2396
		do_action( "wpinv_frontend_render_payment_form_{$element['type']}", $element, $items, $form );
2397
	}
2398
2399
	echo "<div class='wpinv_payment_form_errors alert alert-danger d-none'></div>";
2400
	do_action( 'wpinv_payment_form_bottom' );
2401
	echo '</form>';
2402
2403
	$content = ob_get_clean();
2404
	return str_replace( 'sr-only', '', $content );
2405
}
2406
2407
/**
2408
 * Helper function to display an invoice payment form on the frontend.
2409
 */
2410
function getpaid_display_invoice_payment_form( $invoice_id ) {
2411
    global $invoicing;
2412
2413
    $invoice = wpinv_get_invoice( $invoice_id );
2414
2415
    if ( empty( $invoice ) ) {
2416
		return aui()->alert(
2417
			array(
2418
				'type'    => 'warning',
2419
				'content' => __( 'Invoice not found', 'invoicing' ),
2420
			)
2421
		);
2422
    }
2423
2424
    if ( $invoice->is_paid() ) {
2425
		return aui()->alert(
2426
			array(
2427
				'type'    => 'warning',
2428
				'content' => __( 'Invoice has already been paid', 'invoicing' ),
2429
			)
2430
		);
2431
    }
2432
2433
    // Get the form elements and items.
2434
    $form     = wpinv_get_default_payment_form();
2435
	$elements = $invoicing->form_elements->get_form_elements( $form );
2436
	$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...
2437
2438
	ob_start();
2439
	echo "<form class='wpinv_payment_form'>";
2440
	do_action( 'wpinv_payment_form_top' );
2441
    echo "<input type='hidden' name='form_id' value='$form'/>";
2442
    echo "<input type='hidden' name='invoice_id' value='$invoice_id'/>";
2443
	wp_nonce_field( 'wpinv_payment_form', 'wpinv_payment_form' );
2444
	wp_nonce_field( 'vat_validation', '_wpi_nonce' );
2445
2446
	foreach ( $elements as $element ) {
2447
		do_action( 'wpinv_frontend_render_payment_form_element', $element, $items, $form );
2448
		do_action( "wpinv_frontend_render_payment_form_{$element['type']}", $element, $items, $form );
2449
	}
2450
2451
	echo "<div class='wpinv_payment_form_errors alert alert-danger d-none'></div>";
2452
	do_action( 'wpinv_payment_form_bottom' );
2453
	echo '</form>';
2454
2455
	$content = ob_get_clean();
2456
	return str_replace( 'sr-only', '', $content );
2457
}
2458
2459
/**
2460
 * Helper function to convert item string to array.
2461
 */
2462
function getpaid_convert_items_to_array( $items ) {
2463
    $items    = array_filter( array_map( 'trim', explode( ',', $items ) ) );
2464
    $prepared = array();
2465
2466
    foreach ( $items as $item ) {
2467
        $data = array_map( 'trim', explode( '|', $item ) );
2468
2469
        if ( empty( $data[0] ) || ! is_numeric( $data[0] ) ) {
2470
            continue;
2471
        }
2472
2473
        $quantity = 1;
2474
        if ( isset( $data[1] ) && is_numeric( $data[1] ) ) {
2475
            $quantity = $data[1];
2476
        }
2477
2478
        $prepared[ $data[0] ] = $quantity;
2479
2480
    }
2481
2482
    return $prepared;
2483
}
2484
2485
/**
2486
 * Helper function to convert item array to string.
2487
 */
2488
function getpaid_convert_items_to_string( $items ) {
2489
    $prepared = array();
2490
2491
    foreach ( $items as $item => $quantity ) {
2492
        $prepared[] = "$item|$quantity";
2493
    }
2494
    return implode( ',', $prepared );
2495
}
2496
2497
/**
2498
 * Helper function to display a payment item.
2499
 * 
2500
 * Provide a label and one of $form, $items or $invoice.
2501
 */
2502
function getpaid_get_payment_button( $label, $form = null, $items = null, $invoice = null ) {
2503
    $label = sanitize_text_field( $label );
2504
    $nonce = wp_create_nonce('getpaid_ajax_form');
2505
2506
    if ( ! empty( $form ) ) {
2507
        $form  = esc_attr( $form );
2508
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-form='$form'>$label</button>"; 
2509
    }
2510
	
2511
	if ( ! empty( $items ) ) {
2512
        $items  = esc_attr( $items );
2513
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-item='$items'>$label</button>"; 
2514
    }
2515
    
2516
    if ( ! empty( $invoice ) ) {
2517
        $invoice  = esc_attr( $invoice );
2518
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-invoice='$invoice'>$label</button>"; 
2519
    }
2520
2521
}
2522
2523
/**
2524
 * Display invoice description before line items.
2525
 *
2526
 * @param WPInv_Invoice $invoice
2527
 */
2528
function getpaid_the_invoice_description( $invoice ) {
2529
    if ( empty( $invoice->description ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The property description does not exist on WPInv_Invoice. Since you implemented __get, consider adding a @property annotation.
Loading history...
2530
        return;
2531
    }
2532
2533
    $description = wp_kses_post( $invoice->description );
2534
    echo "<div style='color: #616161; font-size: 90%; margin-bottom: 20px;'><em>$description</em></div>";
2535
}
2536
add_action( 'wpinv_invoice_print_before_line_items', 'getpaid_the_invoice_description' );
2537
2538
/**
2539
 * Render element on a form.
2540
 *
2541
 * @param array $element
2542
 * @param GetPaid_Payment_Form $form
2543
 */
2544
function getpaid_payment_form_element( $element, $form ) {
2545
2546
    // Set up the args.
2547
    $element_type    = trim( $element['type'] );
2548
    $element['form'] = $form;
2549
    extract( $element );
2550
2551
    // Try to locate the appropriate template.
2552
    $located = wpinv_locate_template( "payment-forms/elements/$element_type.php" );
2553
    
2554
    // Abort if this is not our element.
2555
    if ( empty( $located ) || ! file_exists( $located ) ) {
2556
        return;
2557
    }
2558
2559
    // Generate the class and id of the element.
2560
    $wrapper_class = 'getpaid-payment-form-element-' . trim( esc_attr( $element_type ) );
2561
    $id            = isset( $id ) ? $id : uniqid( 'gp' );
2562
2563
    // Echo the opening wrapper.
2564
    echo "<div class='getpaid-payment-form-element $wrapper_class'>";
2565
2566
    // Fires before displaying a given element type's content.
2567
    do_action( "getpaid_before_payment_form_{$element_type}_element", $element, $form );
2568
2569
    // Include the template for the element.
2570
    include $located;
2571
2572
    // Fires after displaying a given element type's content.
2573
    do_action( "getpaid_payment_form_{$element_type}_element", $element, $form );
2574
2575
    // Echo the closing wrapper.
2576
    echo '</div>';
2577
}
2578
add_action( 'getpaid_payment_form_element', 'getpaid_payment_form_element', 10, 2 );
2579
2580
/**
2581
 * Shows a list of gateways that support recurring payments.
2582
 */
2583
function wpinv_get_recurring_gateways_text() {
2584
    $gateways = array();
2585
2586
    foreach ( wpinv_get_payment_gateways() as $key => $gateway ) {
2587
        if ( wpinv_gateway_support_subscription( $key ) ) {
2588
            $gateways[] = sanitize_text_field( $gateway['admin_label'] );
2589
        }
2590
    }
2591
2592
    if ( empty( $gateways ) ) {
2593
        return "<span class='form-text text-danger'>" . __( 'No active gateway supports subscription payments.', 'invoicing' ) ."</span>";
2594
    }
2595
2596
    return "<span class='form-text text-muted'>" . wp_sprintf( __( 'Subscription payments only supported by: %s', 'invoicing' ), implode( ', ', $gateways ) ) ."</span>";
2597
2598
}
2599