Completed
Push — master ( 60f62d...312fad )
by Brian
19s queued 15s
created

wpinv_after_invoice_content()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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

3 paths for user data to reach this point

  1. Path: Read from $_GET, and $_GET['vat_class'] is assigned to $vat_class in includes/admin/class-getpaid-post-types-admin.php on line 552
  1. Read from $_GET, and $_GET['vat_class'] is assigned to $vat_class
    in includes/admin/class-getpaid-post-types-admin.php on line 552
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 556
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 418
  2. Path: Read from $_GET, and $_GET['vat_rule'] is assigned to $vat_rule in includes/admin/class-getpaid-post-types-admin.php on line 522
  1. Read from $_GET, and $_GET['vat_rule'] is assigned to $vat_rule
    in includes/admin/class-getpaid-post-types-admin.php on line 522
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 527
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 418
  3. Path: Read from $_GET, and $_GET['type'] is assigned to $type in includes/admin/class-getpaid-post-types-admin.php on line 577
  1. Read from $_GET, and $_GET['type'] is assigned to $type
    in includes/admin/class-getpaid-post-types-admin.php on line 577
  2. wpinv_html_select() is called
    in includes/admin/class-getpaid-post-types-admin.php on line 581
  3. Enters via parameter $args
    in includes/wpinv-template-functions.php on line 418

Used in variable context

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

General Strategies to prevent injection

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

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

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

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

1335
        $custom_css     = wp_kses( $custom_css, /** @scrutinizer ignore-type */ array( '\'', '\"' ) );
Loading history...
1336
        $custom_css     = str_replace( '&gt;', '>', $custom_css );
1337
        echo '<style type="text/css">';
1338
        echo $custom_css;
1339
        echo '</style>';
1340
    }
1341
1342
}
1343
add_action( 'wpinv_invoice_print_head', 'wpinv_display_style' );
1344
add_action( 'wpinv_invalid_invoice_head', 'wpinv_display_style' );
1345
1346
function wpinv_checkout_billing_details() {
1347
    $invoice_id = (int)wpinv_get_invoice_cart_id();
1348
    if (empty($invoice_id)) {
1349
        wpinv_error_log( 'Invoice id not found', 'ERROR', __FILE__, __LINE__ );
1350
        return null;
1351
    }
1352
1353
    $invoice = wpinv_get_invoice_cart( $invoice_id );
1354
    if (empty($invoice)) {
1355
        wpinv_error_log( 'Invoice not found', 'ERROR', __FILE__, __LINE__ );
1356
        return null;
1357
    }
1358
    $user_id        = $invoice->get_user_id();
1359
    $user_info      = $invoice->get_user_info();
1360
    $address_info   = wpinv_get_user_address( $user_id );
1361
1362
    if ( empty( $user_info['first_name'] ) && !empty( $user_info['first_name'] ) ) {
1363
        $user_info['first_name'] = $user_info['first_name'];
1364
        $user_info['last_name'] = $user_info['last_name'];
1365
    }
1366
1367
    if ( ( ( empty( $user_info['country'] ) && !empty( $address_info['country'] ) ) || ( empty( $user_info['state'] ) && !empty( $address_info['state'] ) && $user_info['country'] == $address_info['country'] ) ) ) {
1368
        $user_info['country']   = $address_info['country'];
1369
        $user_info['state']     = $address_info['state'];
1370
        $user_info['city']      = $address_info['city'];
1371
        $user_info['zip']       = $address_info['zip'];
1372
    }
1373
1374
    $address_fields = array(
1375
        'user_id',
1376
        'company',
1377
        'vat_number',
1378
        'email',
1379
        'phone',
1380
        'address'
1381
    );
1382
1383
    foreach ( $address_fields as $field ) {
1384
        if ( empty( $user_info[$field] ) ) {
1385
            $user_info[$field] = $address_info[$field];
1386
        }
1387
    }
1388
1389
    return apply_filters( 'wpinv_checkout_billing_details', $user_info, $invoice );
1390
}
1391
1392
1393
/**
1394
 * Displays the checkout page.
1395
 */
1396
function wpinv_checkout_form() {
1397
    global $wpi_checkout_id;
1398
1399
    // Retrieve the current invoice.
1400
    $invoice_id = wpinv_get_invoice_cart_id();
1401
1402
    if ( empty( $invoice_id ) ) {
1403
1404
        return aui()->alert(
1405
            array(
1406
                'type'    => 'warning',
1407
                'content' => __( 'Invalid invoice', 'invoicing' ),
1408
            )
1409
        );
1410
1411
    }
1412
1413
    // Can the user view this invoice?
1414
    if ( ! wpinv_user_can_view_invoice( $invoice_id ) ) {
1415
1416
        return aui()->alert(
1417
            array(
1418
                'type'    => 'warning',
1419
                'content' => __( 'You are not allowed to view this invoice', 'invoicing' ),
1420
            )
1421
        );
1422
1423
    }
1424
1425
    // Set the global invoice id.
1426
    $wpi_checkout_id = $invoice_id;
1427
1428
    // We'll display this invoice via the default form.
1429
    $form = new GetPaid_Payment_Form( wpinv_get_default_payment_form() );
1430
1431
    if ( 0 == $form->get_id() ) {
1432
1433
        return aui()->alert(
1434
            array(
1435
                'type'    => 'warning',
1436
                'content' => __( 'Error loading the payment form', 'invoicing' ),
1437
            )
1438
        );
1439
1440
    }
1441
1442
    // Set the invoice.
1443
    $form->invoice = new WPInv_Invoice( $invoice_id );
1444
    $form->set_items( $form->invoice->get_items() );
1445
1446
    // Generate the html.
1447
    return $form->get_html();
1448
1449
}
1450
1451
function wpinv_checkout_cart( $cart_details = array(), $echo = true ) {
1452
    global $ajax_cart_details;
1453
    $ajax_cart_details = $cart_details;
1454
1455
    ob_start();
1456
    do_action( 'wpinv_before_checkout_cart' );
1457
    echo '<div id="wpinv_checkout_cart_form" method="post">';
1458
        echo '<div id="wpinv_checkout_cart_wrap">';
1459
            wpinv_get_template_part( 'wpinv-checkout-cart' );
1460
        echo '</div>';
1461
    echo '</div>';
1462
    do_action( 'wpinv_after_checkout_cart' );
1463
    $content = ob_get_clean();
1464
1465
    if ( $echo ) {
1466
        echo $content;
1467
    } else {
1468
        return $content;
1469
    }
1470
}
1471
add_action( 'wpinv_checkout_cart', 'wpinv_checkout_cart', 10 );
1472
1473
function wpinv_empty_cart_message() {
1474
	return apply_filters( 'wpinv_empty_cart_message', '<span class="wpinv_empty_cart">' . __( 'Your cart is empty.', 'invoicing' ) . '</span>' );
1475
}
1476
1477
/**
1478
 * Echoes the Empty Cart Message
1479
 *
1480
 * @since 1.0
1481
 * @return void
1482
 */
1483
function wpinv_empty_checkout_cart() {
1484
    echo aui()->alert(
1485
        array(
1486
            'type'    => 'warning',
1487
            'content' => wpinv_empty_cart_message(),
1488
        )
1489
    );
1490
}
1491
add_action( 'wpinv_cart_empty', 'wpinv_empty_checkout_cart' );
1492
1493
function wpinv_update_cart_button() {
1494
    if ( !wpinv_item_quantities_enabled() )
1495
        return;
1496
?>
1497
    <input type="submit" name="wpinv_update_cart_submit" class="wpinv-submit wpinv-no-js button" value="<?php _e( 'Update Cart', 'invoicing' ); ?>"/>
1498
    <input type="hidden" name="wpi_action" value="update_cart"/>
1499
<?php
1500
}
1501
1502
function wpinv_checkout_cart_columns() {
1503
    $default = 3;
1504
    if ( wpinv_item_quantities_enabled() ) {
1505
        $default++;
1506
    }
1507
    
1508
    if ( wpinv_use_taxes() ) {
1509
        $default++;
1510
    }
1511
1512
    return apply_filters( 'wpinv_checkout_cart_columns', $default );
1513
}
1514
1515
function wpinv_display_cart_messages() {
1516
    global $wpi_session;
1517
1518
    $messages = $wpi_session->get( 'wpinv_cart_messages' );
1519
1520
    if ( $messages ) {
1521
        foreach ( $messages as $message_id => $message ) {
1522
            // Try and detect what type of message this is
1523
            if ( strpos( strtolower( $message ), 'error' ) ) {
1524
                $type = 'error';
1525
            } elseif ( strpos( strtolower( $message ), 'success' ) ) {
1526
                $type = 'success';
1527
            } else {
1528
                $type = 'info';
1529
            }
1530
1531
            $classes = apply_filters( 'wpinv_' . $type . '_class', array( 'wpinv_errors', 'wpinv-alert', 'wpinv-alert-' . $type ) );
1532
1533
            echo '<div class="' . implode( ' ', $classes ) . '">';
1534
                // Loop message codes and display messages
1535
                    echo '<p class="wpinv_error" id="wpinv_msg_' . $message_id . '">' . $message . '</p>';
1536
            echo '</div>';
1537
        }
1538
1539
        // Remove all of the cart saving messages
1540
        $wpi_session->set( 'wpinv_cart_messages', null );
1541
    }
1542
}
1543
add_action( 'wpinv_before_checkout_cart', 'wpinv_display_cart_messages' );
1544
1545
function wpinv_discount_field() {
1546
    if ( isset( $_GET['wpi-gateway'] ) && wpinv_is_ajax_disabled() ) {
1547
        return; // Only show before a payment method has been selected if ajax is disabled
1548
    }
1549
1550
    if ( !wpinv_is_checkout() ) {
1551
        return;
1552
    }
1553
1554
    if ( wpinv_has_active_discounts() && wpinv_get_cart_total() ) {
1555
    ?>
1556
    <div id="wpinv-discount-field" class="panel panel-default">
1557
        <div class="panel-body">
1558
            <p>
1559
                <label class="wpinv-label" for="wpinv_discount_code"><strong><?php _e( 'Discount', 'invoicing' ); ?></strong></label>
1560
                <span class="wpinv-description"><?php _e( 'Enter a discount code if you have one.', 'invoicing' ); ?></span>
1561
            </p>
1562
            <div class="form-group row">
1563
                <div class="col-sm-4">
1564
                    <input class="wpinv-input form-control" type="text" id="wpinv_discount_code" name="wpinv_discount_code" placeholder="<?php _e( 'Enter discount code', 'invoicing' ); ?>"/>
1565
                </div>
1566
                <div class="col-sm-3">
1567
                    <button id="wpi-apply-discount" type="button" class="btn btn-success btn-sm"><?php _e( 'Apply Discount', 'invoicing' ); ?></button>
1568
                </div>
1569
                <div style="clear:both"></div>
1570
                <div class="col-sm-12 wpinv-discount-msg">
1571
                    <div class="alert alert-success"><i class="fa fa-check-circle"></i><span class="wpi-msg"></span></div>
1572
                    <div class="alert alert-error"><i class="fa fa-warning"></i><span class="wpi-msg"></span></div>
1573
                </div>
1574
            </div>
1575
        </div>
1576
    </div>
1577
<?php
1578
    }
1579
}
1580
add_action( 'wpinv_after_checkout_cart', 'wpinv_discount_field', -10 );
1581
1582
function wpinv_agree_to_terms_js() {
1583
    if ( wpinv_get_option( 'show_agree_to_terms', false ) ) {
1584
?>
1585
<script type="text/javascript">
1586
    jQuery(document).ready(function($){
1587
        $( document.body ).on('click', '.wpinv_terms_links', function(e) {
1588
            //e.preventDefault();
1589
            $('#wpinv_terms').slideToggle();
1590
            $('.wpinv_terms_links').toggle();
1591
            return false;
1592
        });
1593
    });
1594
</script>
1595
<?php
1596
    }
1597
}
1598
add_action( 'wpinv_checkout_form_top', 'wpinv_agree_to_terms_js' );
1599
1600
function wpinv_checkout_billing_info() {
1601
    if ( wpinv_is_checkout() ) {
1602
        $billing_details    = wpinv_checkout_billing_details();
1603
        $selected_country   = !empty( $billing_details['country'] ) ? $billing_details['country'] : wpinv_default_billing_country();
1604
        ?>
1605
        <div id="wpinv-fields" class="clearfix">
1606
            <div id="wpi-billing" class="wpi-billing clearfix panel panel-default">
1607
                <div class="panel-heading"><h3 class="panel-title"><?php _e( 'Billing Details', 'invoicing' );?></h3></div>
1608
                <div id="wpinv-fields-box" class="panel-body">
1609
                    <?php do_action( 'wpinv_checkout_billing_fields_first', $billing_details ); ?>
1610
                    <p class="wpi-cart-field wpi-col2 wpi-colf">
1611
                        <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>
1612
                        <?php
1613
                        echo wpinv_html_text( array(
1614
                                'id'            => 'wpinv_first_name',
1615
                                'name'          => 'wpinv_first_name',
1616
                                'value'         => $billing_details['first_name'],
1617
                                'class'         => 'wpi-input form-control',
1618
                                'placeholder'   => __( 'First name', 'invoicing' ),
1619
                                'required'      => (bool)wpinv_get_option( 'fname_mandatory' ),
1620
                            ) );
1621
                        ?>
1622
                    </p>
1623
                    <p class="wpi-cart-field wpi-col2 wpi-coll">
1624
                        <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>
1625
                        <?php
1626
                        echo wpinv_html_text( array(
1627
                                'id'            => 'wpinv_last_name',
1628
                                'name'          => 'wpinv_last_name',
1629
                                'value'         => $billing_details['last_name'],
1630
                                'class'         => 'wpi-input form-control',
1631
                                'placeholder'   => __( 'Last name', 'invoicing' ),
1632
                                'required'      => (bool)wpinv_get_option( 'lname_mandatory' ),
1633
                            ) );
1634
                        ?>
1635
                    </p>
1636
                    <p class="wpi-cart-field wpi-col2 wpi-colf">
1637
                        <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>
1638
                        <?php
1639
                        echo wpinv_html_text( array(
1640
                                'id'            => 'wpinv_address',
1641
                                'name'          => 'wpinv_address',
1642
                                'value'         => $billing_details['address'],
1643
                                'class'         => 'wpi-input form-control',
1644
                                'placeholder'   => __( 'Address', 'invoicing' ),
1645
                                'required'      => (bool)wpinv_get_option( 'address_mandatory' ),
1646
                            ) );
1647
                        ?>
1648
                    </p>
1649
                    <p class="wpi-cart-field wpi-col2 wpi-coll">
1650
                        <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>
1651
                        <?php
1652
                        echo wpinv_html_text( array(
1653
                                'id'            => 'wpinv_city',
1654
                                'name'          => 'wpinv_city',
1655
                                'value'         => $billing_details['city'],
1656
                                'class'         => 'wpi-input form-control',
1657
                                'placeholder'   => __( 'City', 'invoicing' ),
1658
                                'required'      => (bool)wpinv_get_option( 'city_mandatory' ),
1659
                            ) );
1660
                        ?>
1661
                    </p>
1662
                    <p id="wpinv_country_box" class="wpi-cart-field wpi-col2 wpi-colf">
1663
                        <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>
1664
                        <?php echo wpinv_html_select( array(
1665
                            'options'          => wpinv_get_country_list(),
1666
                            'name'             => 'wpinv_country',
1667
                            'id'               => 'wpinv_country',
1668
                            'selected'         => $selected_country,
1669
                            'show_option_all'  => false,
1670
                            'show_option_none' => false,
1671
                            'class'            => 'wpi-input form-control wpi_select2',
1672
                            'placeholder'      => __( 'Choose a country', 'invoicing' ),
1673
                            'required'         => (bool)wpinv_get_option( 'country_mandatory' ),
1674
                        ) ); ?>
1675
                    </p>
1676
                    <p id="wpinv_state_box" class="wpi-cart-field wpi-col2 wpi-coll">
1677
                        <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>
1678
                        <?php
1679
                        $states = wpinv_get_country_states( $selected_country );
1680
                        if( !empty( $states ) ) {
1681
                            echo wpinv_html_select( array(
1682
                                'options'          => $states,
1683
                                'name'             => 'wpinv_state',
1684
                                'id'               => 'wpinv_state',
1685
                                'selected'         => $billing_details['state'],
1686
                                'show_option_all'  => false,
1687
                                'show_option_none' => false,
1688
                                'class'            => 'wpi-input form-control wpi_select2',
1689
                                'placeholder'      => __( 'Choose a state', 'invoicing' ),
1690
                                'required'         => (bool)wpinv_get_option( 'state_mandatory' ),
1691
                            ) );
1692
                        } else {
1693
                            echo wpinv_html_text( array(
1694
                                'name'          => 'wpinv_state',
1695
                                'value'         => $billing_details['state'],
1696
                                'id'            => 'wpinv_state',
1697
                                'class'         => 'wpi-input form-control',
1698
                                'placeholder'   => __( 'State / Province', 'invoicing' ),
1699
                                'required'      => (bool)wpinv_get_option( 'state_mandatory' ),
1700
                            ) );
1701
                        }
1702
                        ?>
1703
                    </p>
1704
                    <p class="wpi-cart-field wpi-col2 wpi-colf">
1705
                        <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>
1706
                        <?php
1707
                        echo wpinv_html_text( array(
1708
                                'name'          => 'wpinv_zip',
1709
                                'value'         => $billing_details['zip'],
1710
                                'id'            => 'wpinv_zip',
1711
                                'class'         => 'wpi-input form-control',
1712
                                'placeholder'   => __( 'ZIP / Postcode', 'invoicing' ),
1713
                                'required'      => (bool)wpinv_get_option( 'zip_mandatory' ),
1714
                            ) );
1715
                        ?>
1716
                    </p>
1717
                    <p class="wpi-cart-field wpi-col2 wpi-coll">
1718
                        <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>
1719
                        <?php
1720
                        echo wpinv_html_text( array(
1721
                                'id'            => 'wpinv_phone',
1722
                                'name'          => 'wpinv_phone',
1723
                                'value'         => $billing_details['phone'],
1724
                                'class'         => 'wpi-input form-control',
1725
                                'placeholder'   => __( 'Phone', 'invoicing' ),
1726
                                'required'      => (bool)wpinv_get_option( 'phone_mandatory' ),
1727
                            ) );
1728
                        ?>
1729
                    </p>
1730
                    <?php do_action( 'wpinv_checkout_billing_fields_last', $billing_details ); ?>
1731
                    <div class="clearfix"></div>
1732
                </div>
1733
            </div>
1734
            <?php do_action( 'wpinv_after_billing_fields', $billing_details ); ?>
1735
        </div>
1736
        <?php
1737
    }
1738
}
1739
add_action( 'wpinv_checkout_billing_info', 'wpinv_checkout_billing_info' );
1740
1741
function wpinv_checkout_hidden_fields() {
1742
?>
1743
    <?php if ( is_user_logged_in() ) { ?>
1744
    <input type="hidden" name="wpinv_user_id" value="<?php echo get_current_user_id(); ?>"/>
1745
    <?php } ?>
1746
    <input type="hidden" name="wpi_action" value="payment" />
1747
<?php
1748
}
1749
1750
function wpinv_checkout_button_purchase() {
1751
    ob_start();
1752
?>
1753
    <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' ) ?>"/>
1754
<?php
1755
    return apply_filters( 'wpinv_checkout_button_purchase', ob_get_clean() );
1756
}
1757
1758
function wpinv_checkout_total() {
1759
    global $cart_total;
1760
?>
1761
<div id="wpinv_checkout_total" class="panel panel-info">
1762
    <div class="panel-body">
1763
    <?php
1764
    do_action( 'wpinv_purchase_form_before_checkout_total' );
1765
    ?>
1766
    <strong><?php _e( 'Invoice Total:', 'invoicing' ) ?></strong> <span class="wpinv-chdeckout-total"><?php echo $cart_total;?></span>
1767
    <?php
1768
    do_action( 'wpinv_purchase_form_after_checkout_total' );
1769
    ?>
1770
    </div>
1771
</div>
1772
<?php
1773
}
1774
add_action( 'wpinv_checkout_form_bottom', 'wpinv_checkout_total', 9998 );
1775
1776
function wpinv_checkout_submit() {
1777
?>
1778
<div id="wpinv_purchase_submit" class="panel panel-success">
1779
    <div class="panel-body text-center">
1780
    <?php
1781
    do_action( 'wpinv_purchase_form_before_submit' );
1782
    wpinv_checkout_hidden_fields();
1783
    echo wpinv_checkout_button_purchase();
1784
    do_action( 'wpinv_purchase_form_after_submit' );
1785
    ?>
1786
    </div>
1787
</div>
1788
<?php
1789
}
1790
add_action( 'wpinv_checkout_form_bottom', 'wpinv_checkout_submit', 9999 );
1791
1792
function wpinv_receipt_billing_address( $invoice_id = 0 ) {
1793
    $invoice = wpinv_get_invoice( $invoice_id );
1794
1795
    if ( empty( $invoice ) ) {
1796
        return NULL;
1797
    }
1798
1799
    $billing_details = $invoice->get_user_info();
1800
    $address_row = wpinv_get_invoice_address_markup( $billing_details );
1801
1802
    ob_start();
1803
    ?>
1804
    <table class="table table-bordered table-sm wpi-billing-details">
1805
        <tbody>
1806
            <tr class="wpi-receipt-name">
1807
                <th class="text-left"><?php _e( 'Name', 'invoicing' ); ?></th>
1808
                <td><?php echo esc_html( trim( $billing_details['first_name'] . ' ' . $billing_details['last_name'] ) ) ;?></td>
1809
            </tr>
1810
            <tr class="wpi-receipt-email">
1811
                <th class="text-left"><?php _e( 'Email', 'invoicing' ); ?></th>
1812
                <td><?php echo $billing_details['email'] ;?></td>
1813
            </tr>
1814
            <tr class="wpi-receipt-address">
1815
                <th class="text-left"><?php _e( 'Address', 'invoicing' ); ?></th>
1816
                <td><?php echo $address_row ;?></td>
1817
            </tr>
1818
            <?php if ( $billing_details['phone'] ) { ?>
1819
            <tr class="wpi-receipt-phone">
1820
                <th class="text-left"><?php _e( 'Phone', 'invoicing' ); ?></th>
1821
                <td><?php echo esc_html( $billing_details['phone'] ) ;?></td>
1822
            </tr>
1823
            <?php } ?>
1824
        </tbody>
1825
    </table>
1826
    <?php
1827
    $output = ob_get_clean();
1828
    
1829
    $output = apply_filters( 'wpinv_receipt_billing_address', $output, $invoice_id );
1830
1831
    echo $output;
1832
}
1833
1834
function wpinv_filter_success_page_content( $content ) {
1835
    if ( isset( $_GET['payment-confirm'] ) && wpinv_is_success_page() ) {
1836
        if ( has_filter( 'wpinv_payment_confirm_' . sanitize_text_field( $_GET['payment-confirm'] ) ) ) {
1837
            $content = apply_filters( 'wpinv_payment_confirm_' . sanitize_text_field( $_GET['payment-confirm'] ), $content );
1838
        }
1839
    }
1840
1841
    return $content;
1842
}
1843
add_filter( 'the_content', 'wpinv_filter_success_page_content', 99999 );
1844
1845
function wpinv_receipt_actions( $invoice ) {
1846
    if ( !empty( $invoice ) ) {
1847
        $actions = array();
1848
1849
        if ( wpinv_user_can_view_invoice( $invoice->ID ) ) {
1850
            $actions['print']   = array(
1851
                'url'  => $invoice->get_view_url( true ),
1852
                'name' => __( 'Print Invoice', 'invoicing' ),
1853
                'class' => 'btn-primary',
1854
            );
1855
        }
1856
1857
        if ( is_user_logged_in() ) {
1858
            $actions['history'] = array(
1859
                'url'  => wpinv_get_history_page_uri(),
1860
                'name' => __( 'Invoice History', 'invoicing' ),
1861
                'class' => 'btn-warning',
1862
            );
1863
        }
1864
1865
        $actions = apply_filters( 'wpinv_invoice_receipt_actions', $actions, $invoice );
1866
1867
        if ( !empty( $actions ) ) {
1868
        ?>
1869
        <div class="wpinv-receipt-actions text-right">
1870
            <?php foreach ( $actions as $key => $action ) { $class = !empty($action['class']) ? sanitize_html_class( $action['class'] ) : ''; ?>
1871
            <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>
1872
            <?php } ?>
1873
        </div>
1874
        <?php
1875
        }
1876
    }
1877
}
1878
add_action( 'wpinv_receipt_start', 'wpinv_receipt_actions', -10, 1 );
1879
1880
function wpinv_invoice_link( $invoice_id ) {
1881
    $invoice = wpinv_get_invoice( $invoice_id );
1882
1883
    if ( empty( $invoice ) ) {
1884
        return NULL;
1885
    }
1886
1887
    $invoice_link = '<a href="' . esc_url( $invoice->get_view_url() ) . '">' . $invoice->get_number() . '</a>';
1888
1889
    return apply_filters( 'wpinv_get_invoice_link', $invoice_link, $invoice );
1890
}
1891
1892
function wpinv_invoice_subscription_details( $invoice ) {
1893
    if ( !empty( $invoice ) && $invoice->is_recurring() && ! wpinv_is_subscription_payment( $invoice ) ) {
1894
        $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

1894
        $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...
1895
1896
        if ( empty( $subscription ) ) {
1897
            return;
1898
        }
1899
1900
        $frequency = WPInv_Subscriptions::wpinv_get_pretty_subscription_frequency($subscription->period, $subscription->frequency);
1901
        $billing = wpinv_price(wpinv_format_amount($subscription->recurring_amount), wpinv_get_invoice_currency_code($subscription->parent_payment_id)) . ' / ' . $frequency;
1902
        $initial = wpinv_price(wpinv_format_amount($subscription->initial_amount), wpinv_get_invoice_currency_code($subscription->parent_payment_id));
1903
1904
        $payments = $subscription->get_child_payments();
1905
        ?>
1906
        <div class="wpinv-subscriptions-details">
1907
            <h3 class="wpinv-subscriptions-t"><?php echo apply_filters( 'wpinv_subscription_details_title', __( 'Subscription Details', 'invoicing' ) ); ?></h3>
1908
            <table class="table">
1909
                <thead>
1910
                    <tr>
1911
                        <th><?php _e( 'Billing Cycle', 'invoicing' ) ;?></th>
1912
                        <th><?php _e( 'Start Date', 'invoicing' ) ;?></th>
1913
                        <th><?php _e( 'Expiration Date', 'invoicing' ) ;?></th>
1914
                        <th class="text-center"><?php _e( 'Times Billed', 'invoicing' ) ;?></th>
1915
                        <th class="text-center"><?php _e( 'Status', 'invoicing' ) ;?></th>
1916
                    </tr>
1917
                </thead>
1918
                <tbody>
1919
                    <tr>
1920
                        <td><?php printf(_x('%s then %s', 'Initial subscription amount then billing cycle and amount', 'invoicing'), $initial, $billing); ?></td>
1921
                        <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

1921
                        <td><?php echo date_i18n(/** @scrutinizer ignore-type */ get_option('date_format'), strtotime($subscription->created, current_time('timestamp'))); ?></td>
Loading history...
1922
                        <td><?php echo date_i18n(get_option('date_format'), strtotime($subscription->expiration, current_time('timestamp'))); ?></td>
1923
                        <td class="text-center"><?php echo $subscription->get_times_billed() . ' / ' . (($subscription->bill_times == 0) ? 'Until Cancelled' : $subscription->bill_times); ?></td>
1924
                        <td class="text-center wpi-sub-status"><?php echo $subscription->get_status_label(); ?></td>
1925
                    </tr>
1926
                </tbody>
1927
            </table>
1928
        </div>
1929
        <?php if ( !empty( $payments ) ) { ?>
1930
        <div class="wpinv-renewal-payments">
1931
            <h3 class="wpinv-renewals-t"><?php echo apply_filters( 'wpinv_renewal_payments_title', __( 'Renewal Payments', 'invoicing' ) ); ?></h3>
1932
            <table class="table">
1933
                <thead>
1934
                    <tr>
1935
                        <th>#</th>
1936
                        <th><?php _e( 'Invoice', 'invoicing' ) ;?></th>
1937
                        <th><?php _e( 'Date', 'invoicing' ) ;?></th>
1938
                        <th class="text-right"><?php _e( 'Amount', 'invoicing' ) ;?></th>
1939
                    </tr>
1940
                </thead>
1941
                <tbody>
1942
                    <?php
1943
                        $i = 1;
1944
                        foreach ( $payments as $payment ) {
1945
                            $invoice_id = $payment->ID;
1946
                    ?>
1947
                    <tr>
1948
                        <th scope="row"><?php echo $i;?></th>
1949
                        <td><?php echo wpinv_invoice_link( $invoice_id ) ;?></td>
1950
                        <td><?php echo wpinv_get_invoice_date( $invoice_id ); ?></td>
1951
                        <td class="text-right"><?php echo wpinv_payment_total( $invoice_id, true ); ?></td>
1952
                    </tr>
1953
                    <?php $i++; } ?>
1954
                </tbody>
1955
            </table>
1956
        </div>
1957
        <?php } ?>
1958
        <?php
1959
    }
1960
}
1961
1962
function wpinv_cart_total_label( $label, $invoice ) {
1963
    if ( empty( $invoice ) ) {
1964
        return $label;
1965
    }
1966
1967
    $prefix_label = '';
1968
    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...
1969
        $prefix_label   = '<span class="label label-primary label-recurring">' . __( 'Recurring Payment', 'invoicing' ) . '</span> ' . wpinv_subscription_payment_desc( $invoice );
1970
    } else if ( $invoice->is_renewal() ) {
1971
        $prefix_label   = '<span class="label label-primary label-renewal">' . __( 'Renewal Payment', 'invoicing' ) . '</span> ';        
1972
    }
1973
1974
    if ( $prefix_label != '' ) {
1975
        $label  = '<span class="wpinv-cart-sub-desc">' . $prefix_label . '</span> ' . $label;
1976
    }
1977
1978
    return $label;
1979
}
1980
add_filter( 'wpinv_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
1981
add_filter( 'wpinv_email_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
1982
add_filter( 'wpinv_print_cart_total_label', 'wpinv_cart_total_label', 10, 2 );
1983
1984
add_action( 'wpinv_invoice_print_middle', 'wpinv_invoice_subscription_details', 10, 1 );
1985
1986
function wpinv_invoice_print_description( $invoice ) {
1987
    if ( empty( $invoice ) ) {
1988
        return NULL;
1989
    }
1990
    if ( $description = wpinv_get_invoice_description( $invoice->ID ) ) {
1991
        ?>
1992
        <div class="row wpinv-lower">
1993
            <div class="col-sm-12 wpinv-description">
1994
                <?php echo wpautop( $description ); ?>
1995
            </div>
1996
        </div>
1997
        <?php
1998
    }
1999
}
2000
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

2000
add_action( 'wpinv_invoice_print_middle', 'wpinv_invoice_print_description', /** @scrutinizer ignore-type */ 10.1, 1 );
Loading history...
2001
2002
function wpinv_invoice_print_payment_info( $invoice ) {
2003
    if ( empty( $invoice ) ) {
2004
        return NULL;
2005
    }
2006
2007
    if ( $payments_info = wpinv_display_payments_info( $invoice->ID, false ) ) {
2008
        ?>
2009
        <div class="row wpinv-payments">
2010
            <div class="col-sm-12">
2011
                <?php echo $payments_info; ?>
2012
            </div>
2013
        </div>
2014
        <?php 
2015
    }
2016
}
2017
// add_action( 'wpinv_invoice_print_after_line_items', 'wpinv_invoice_print_payment_info', 10, 1 );
2018
2019
function wpinv_get_invoice_note_line_item( $note, $echo = true ) {
2020
    if ( empty( $note ) ) {
2021
        return NULL;
2022
    }
2023
2024
    if ( is_int( $note ) ) {
2025
        $note = get_comment( $note );
2026
    }
2027
2028
    if ( !( is_object( $note ) && is_a( $note, 'WP_Comment' ) ) ) {
2029
        return NULL;
2030
    }
2031
2032
    $note_classes   = array( 'note' );
2033
    $note_classes[] = get_comment_meta( $note->comment_ID, '_wpi_customer_note', true ) ? 'customer-note' : '';
2034
    $note_classes[] = $note->comment_author === 'System' ? 'system-note' : '';
2035
    $note_classes   = apply_filters( 'wpinv_invoice_note_class', array_filter( $note_classes ), $note );
2036
    $note_classes   = !empty( $note_classes ) ? implode( ' ', $note_classes ) : '';
2037
2038
    ob_start();
2039
    ?>
2040
    <li rel="<?php echo absint( $note->comment_ID ) ; ?>" class="<?php echo esc_attr( $note_classes ); ?>">
2041
        <div class="note_content">
2042
            <?php echo wpautop( wptexturize( wp_kses_post( $note->comment_content ) ) ); ?>
2043
        </div>
2044
        <p class="meta">
2045
            <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

2045
            <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...
2046
            <?php if ( is_admin() && ( $note->comment_author !== 'System' || wpinv_current_user_can_manage_invoicing() ) ) { ?>
2047
                <a href="#" class="delete_note"><?php _e( 'Delete note', 'invoicing' ); ?></a>
2048
            <?php } ?>
2049
        </p>
2050
    </li>
2051
    <?php
2052
    $note_content = ob_get_clean();
2053
    $note_content = apply_filters( 'wpinv_get_invoice_note_line_item', $note_content, $note, $echo );
2054
2055
    if ( $echo ) {
2056
        echo $note_content;
2057
    } else {
2058
        return $note_content;
2059
    }
2060
}
2061
2062
function wpinv_invalid_invoice_content() {
2063
    global $post;
2064
2065
    $invoice = wpinv_get_invoice( $post->ID );
2066
2067
    $error = __( 'This invoice is only viewable by clicking on the invoice link that was sent to you via email.', 'invoicing' );
2068
    if ( !empty( $invoice->ID ) && $invoice->has_status( array_keys( wpinv_get_invoice_statuses() ) ) ) {
2069
        if ( is_user_logged_in() ) {
2070
            if ( wpinv_require_login_to_checkout() ) {
2071
                if ( isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
2072
                    $error = __( 'You are not allowed to view this invoice.', 'invoicing' );
2073
                }
2074
            }
2075
        } else {
2076
            if ( wpinv_require_login_to_checkout() ) {
2077
                if ( isset( $_GET['invoice_key'] ) && $_GET['invoice_key'] === $invoice->get_key() ) {
2078
                    $error = __( 'You must be logged in to view this invoice.', 'invoicing' );
2079
                }
2080
            }
2081
        }
2082
    } else {
2083
        $error = __( 'This invoice is deleted or does not exist.', 'invoicing' );
2084
    }
2085
    ?>
2086
    <div class="row wpinv-row-invalid">
2087
        <div class="col-md-6 col-md-offset-3 wpinv-message error">
2088
            <h3><?php _e( 'Access Denied', 'invoicing' ); ?></h3>
2089
            <p class="wpinv-msg-text"><?php echo $error; ?></p>
2090
        </div>
2091
    </div>
2092
    <?php
2093
}
2094
add_action( 'wpinv_invalid_invoice_content', 'wpinv_invalid_invoice_content' );
2095
2096
add_action( 'wpinv_checkout_billing_fields_last', 'wpinv_force_company_name_field');
2097
function wpinv_force_company_name_field(){
2098
    $invoice = wpinv_get_invoice_cart();
2099
    $user_id = wpinv_get_user_id( $invoice->ID );
2100
    $company = empty( $user_id ) ? "" : get_user_meta( $user_id, '_wpinv_company', true );
2101
    if ( 1 == wpinv_get_option( 'force_show_company' ) && !wpinv_use_taxes() ) {
2102
        ?>
2103
        <p class="wpi-cart-field wpi-col2 wpi-colf">
2104
            <label for="wpinv_company" class="wpi-label"><?php _e('Company Name', 'invoicing'); ?></label>
2105
            <?php
2106
            echo wpinv_html_text(array(
2107
                'id' => 'wpinv_company',
2108
                'name' => 'wpinv_company',
2109
                'value' => $company,
2110
                'class' => 'wpi-input form-control',
2111
                'placeholder' => __('Company name', 'invoicing'),
2112
                'required'      => true,
2113
            ));
2114
            ?>
2115
        </p>
2116
        <?php
2117
    }
2118
}
2119
2120
/**
2121
 * Function to get privacy policy text.
2122
 *
2123
 * @since 1.0.13
2124
 * @return string
2125
 */
2126
function wpinv_get_policy_text() {
2127
    $privacy_page_id = get_option( 'wp_page_for_privacy_policy', 0 );
2128
2129
    $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]' ));
2130
2131
    if(!$privacy_page_id){
2132
        $privacy_page_id = wpinv_get_option( 'privacy_page', 0 );
2133
    }
2134
2135
    $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

2135
    $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...
2136
2137
    $find_replace = array(
2138
        '[wpinv_privacy_policy]' => $privacy_link,
2139
    );
2140
2141
    $privacy_text = str_replace( array_keys( $find_replace ), array_values( $find_replace ), $text );
2142
2143
    return wp_kses_post(wpautop($privacy_text));
2144
}
2145
2146
2147
/**
2148
 * Allows the user to set their own price for an invoice item
2149
 */
2150
function wpinv_checkout_cart_item_name_your_price( $cart_item, $key ) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

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

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

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

Loading history...
2151
    
2152
    //Ensure we have an item id
2153
    if(! is_array( $cart_item ) || empty( $cart_item['id'] ) ) {
2154
        return;
2155
    }
2156
2157
    //Fetch the item
2158
    $item_id = $cart_item['id'];
2159
    $item    = new WPInv_Item( $item_id );
2160
    
2161
    if(! $item->supports_dynamic_pricing() || !$item->get_is_dynamic_pricing() ) {
2162
        return;
2163
    }
2164
2165
    //Fetch the dynamic pricing "strings"
2166
    $suggested_price_text = esc_html( wpinv_get_option( 'suggested_price_text', __( 'Suggested Price:', 'invoicing' ) ) );
2167
    $minimum_price_text   = esc_html( wpinv_get_option( 'minimum_price_text', __( 'Minimum Price:', 'invoicing' ) ) );
2168
    $name_your_price_text = esc_html( wpinv_get_option( 'name_your_price_text', __( 'Name Your Price', 'invoicing' ) ) );
2169
2170
    //Display a "name_your_price" button
2171
    echo " &mdash; <a href='#' class='wpinv-name-your-price-frontend small'>$name_your_price_text</a></div>";
2172
2173
    //Display a name_your_price form
2174
    echo '<div class="name-your-price-miniform">';
2175
    
2176
    //Maybe display the recommended price
2177
    if( $item->get_price() > 0 && !empty( $suggested_price_text ) ) {
2178
        $suggested_price = $item->get_the_price();
2179
        echo "<div>$suggested_price_text &mdash; $suggested_price</div>";
2180
    }
2181
2182
    //Display the update price form
2183
    $symbol         = wpinv_currency_symbol();
2184
    $position       = wpinv_currency_position();
2185
    $minimum        = esc_attr( $item->get_minimum_price() );
2186
    $price          = esc_attr( $cart_item['item_price'] );
2187
    $update         = esc_attr__( "Update", 'invoicing' );
2188
2189
    //Ensure it supports dynamic prici
2190
    if( $price < $minimum ) {
2191
        $price = $minimum;
2192
    }
2193
2194
    echo '<label>';
2195
    echo $position != 'right' ? $symbol . '&nbsp;' : '';
2196
    echo "<input type='number' min='$minimum' placeholder='$price' value='$price' class='wpi-field-price' />";
2197
    echo $position == 'right' ? '&nbsp;' . $symbol : '' ;
2198
    echo "</label>";
2199
    echo "<input type='hidden' value='$item_id' class='wpi-field-item' />";
2200
    echo "<a class='btn btn-success wpinv-submit wpinv-update-dynamic-price-frontend'>$update</a>";
2201
2202
    //Maybe display the minimum price
2203
    if( $item->get_minimum_price() > 0 && !empty( $minimum_price_text ) ) {
2204
        $minimum_price = wpinv_price( wpinv_format_amount( $item->get_minimum_price() ) );
2205
        echo "<div>$minimum_price_text &mdash; $minimum_price</div>";
2206
    }
2207
2208
    echo "</div>";
2209
2210
}
2211
add_action( 'wpinv_checkout_cart_item_price_after', 'wpinv_checkout_cart_item_name_your_price', 10, 2 );
2212
2213
function wpinv_oxygen_fix_conflict() {
2214
    global $ct_ignore_post_types;
2215
2216
    if ( ! is_array( $ct_ignore_post_types ) ) {
2217
        $ct_ignore_post_types = array();
2218
    }
2219
2220
    $post_types = array( 'wpi_discount', 'wpi_invoice', 'wpi_item' );
2221
2222
    foreach ( $post_types as $post_type ) {
2223
        $ct_ignore_post_types[] = $post_type;
2224
2225
        // Ignore post type
2226
        add_filter( 'pre_option_oxygen_vsb_ignore_post_type_' . $post_type, '__return_true', 999 );
2227
    }
2228
2229
    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

2229
    /** @scrutinizer ignore-call */ 
2230
    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...
2230
    add_filter( 'template_include', 'wpinv_template', 999, 1 );
2231
}
2232
2233
/**
2234
 * Helper function to display a payment form on the frontend.
2235
 * 
2236
 * @param GetPaid_Payment_Form $form
2237
 */
2238
function getpaid_display_payment_form( $form ) {
2239
2240
    if ( is_numeric( $form ) ) {
0 ignored issues
show
introduced by
The condition is_numeric($form) is always false.
Loading history...
2241
        $form = new GetPaid_Payment_Form( $form );
2242
    }
2243
2244
    $form->display();
2245
2246
}
2247
2248
/**
2249
 * Helper function to display a item payment form on the frontend.
2250
 */
2251
function getpaid_display_item_payment_form( $items ) {
2252
    global $invoicing;
2253
2254
    foreach ( array_keys( $items ) as $id ) {
2255
	    if ( 'publish' != get_post_status( $id ) ) {
2256
		    unset( $items[ $id ] );
2257
	    }
2258
    }
2259
2260
    if ( empty( $items ) ) {
2261
		return aui()->alert(
2262
			array(
2263
				'type'    => 'warning',
2264
				'content' => __( 'No published items found', 'invoicing' ),
2265
			)
2266
		);
2267
    }
2268
2269
    $item_key = getpaid_convert_items_to_string( $items );
2270
2271
    // Get the form elements and items.
2272
    $form     = wpinv_get_default_payment_form();
2273
	$elements = $invoicing->form_elements->get_form_elements( $form );
2274
	$items    = $invoicing->form_elements->convert_normal_items( $items );
2275
2276
	ob_start();
2277
	echo "<form class='wpinv_payment_form'>";
2278
	do_action( 'wpinv_payment_form_top' );
2279
    echo "<input type='hidden' name='form_id' value='$form'/>";
2280
    echo "<input type='hidden' name='form_items' value='$item_key'/>";
2281
	wp_nonce_field( 'wpinv_payment_form', 'wpinv_payment_form' );
2282
	wp_nonce_field( 'vat_validation', '_wpi_nonce' );
2283
2284
	foreach ( $elements as $element ) {
2285
		do_action( 'wpinv_frontend_render_payment_form_element', $element, $items, $form );
2286
		do_action( "wpinv_frontend_render_payment_form_{$element['type']}", $element, $items, $form );
2287
	}
2288
2289
	echo "<div class='wpinv_payment_form_errors alert alert-danger d-none'></div>";
2290
	do_action( 'wpinv_payment_form_bottom' );
2291
	echo '</form>';
2292
2293
	$content = ob_get_clean();
2294
	return str_replace( 'sr-only', '', $content );
2295
}
2296
2297
/**
2298
 * Helper function to display an invoice payment form on the frontend.
2299
 */
2300
function getpaid_display_invoice_payment_form( $invoice_id ) {
2301
    global $invoicing;
2302
2303
    $invoice = wpinv_get_invoice( $invoice_id );
2304
2305
    if ( empty( $invoice ) ) {
2306
		return aui()->alert(
2307
			array(
2308
				'type'    => 'warning',
2309
				'content' => __( 'Invoice not found', 'invoicing' ),
2310
			)
2311
		);
2312
    }
2313
2314
    if ( $invoice->is_paid() ) {
2315
		return aui()->alert(
2316
			array(
2317
				'type'    => 'warning',
2318
				'content' => __( 'Invoice has already been paid', 'invoicing' ),
2319
			)
2320
		);
2321
    }
2322
2323
    // Get the form elements and items.
2324
    $form     = wpinv_get_default_payment_form();
2325
	$elements = $invoicing->form_elements->get_form_elements( $form );
2326
	$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...
2327
2328
	ob_start();
2329
	echo "<form class='wpinv_payment_form'>";
2330
	do_action( 'wpinv_payment_form_top' );
2331
    echo "<input type='hidden' name='form_id' value='$form'/>";
2332
    echo "<input type='hidden' name='invoice_id' value='$invoice_id'/>";
2333
	wp_nonce_field( 'wpinv_payment_form', 'wpinv_payment_form' );
2334
	wp_nonce_field( 'vat_validation', '_wpi_nonce' );
2335
2336
	foreach ( $elements as $element ) {
2337
		do_action( 'wpinv_frontend_render_payment_form_element', $element, $items, $form );
2338
		do_action( "wpinv_frontend_render_payment_form_{$element['type']}", $element, $items, $form );
2339
	}
2340
2341
	echo "<div class='wpinv_payment_form_errors alert alert-danger d-none'></div>";
2342
	do_action( 'wpinv_payment_form_bottom' );
2343
	echo '</form>';
2344
2345
	$content = ob_get_clean();
2346
	return str_replace( 'sr-only', '', $content );
2347
}
2348
2349
/**
2350
 * Helper function to convert item string to array.
2351
 */
2352
function getpaid_convert_items_to_array( $items ) {
2353
    $items    = array_filter( array_map( 'trim', explode( ',', $items ) ) );
2354
    $prepared = array();
2355
2356
    foreach ( $items as $item ) {
2357
        $data = array_map( 'trim', explode( '|', $item ) );
2358
2359
        if ( empty( $data[0] ) || ! is_numeric( $data[0] ) ) {
2360
            continue;
2361
        }
2362
2363
        $quantity = 1;
2364
        if ( isset( $data[1] ) && is_numeric( $data[1] ) ) {
2365
            $quantity = $data[1];
2366
        }
2367
2368
        $prepared[ $data[0] ] = $quantity;
2369
2370
    }
2371
2372
    return $prepared;
2373
}
2374
2375
/**
2376
 * Helper function to convert item array to string.
2377
 */
2378
function getpaid_convert_items_to_string( $items ) {
2379
    $prepared = array();
2380
2381
    foreach ( $items as $item => $quantity ) {
2382
        $prepared[] = "$item|$quantity";
2383
    }
2384
    return implode( ',', $prepared );
2385
}
2386
2387
/**
2388
 * Helper function to display a payment item.
2389
 * 
2390
 * Provide a label and one of $form, $items or $invoice.
2391
 */
2392
function getpaid_get_payment_button( $label, $form = null, $items = null, $invoice = null ) {
2393
    $label = sanitize_text_field( $label );
2394
    $nonce = wp_create_nonce('getpaid_ajax_form');
2395
2396
    if ( ! empty( $form ) ) {
2397
        $form  = esc_attr( $form );
2398
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-form='$form'>$label</button>"; 
2399
    }
2400
	
2401
	if ( ! empty( $items ) ) {
2402
        $items  = esc_attr( $items );
2403
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-item='$items'>$label</button>"; 
2404
    }
2405
    
2406
    if ( ! empty( $invoice ) ) {
2407
        $invoice  = esc_attr( $invoice );
2408
        return "<button class='btn btn-primary getpaid-payment-button' type='button' data-nonce='$nonce' data-invoice='$invoice'>$label</button>"; 
2409
    }
2410
2411
}
2412
2413
/**
2414
 * Display invoice description before line items.
2415
 *
2416
 * @param WPInv_Invoice $invoice
2417
 */
2418
function getpaid_the_invoice_description( $invoice ) {
2419
    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...
2420
        return;
2421
    }
2422
2423
    $description = wp_kses_post( $invoice->description );
2424
    echo "<div style='color: #616161; font-size: 90%; margin-bottom: 20px;'><em>$description</em></div>";
2425
}
2426
add_action( 'wpinv_invoice_print_before_line_items', 'getpaid_the_invoice_description' );
2427
2428
/**
2429
 * Render element on a form.
2430
 *
2431
 * @param array $element
2432
 * @param GetPaid_Payment_Form $form
2433
 */
2434
function getpaid_payment_form_element( $element, $form ) {
2435
2436
    // Set up the args.
2437
    $element_type    = trim( $element['type'] );
2438
    $element['form'] = $form;
2439
    extract( $element );
2440
2441
    // Try to locate the appropriate template.
2442
    $located = wpinv_locate_template( "payment-forms/elements/$element_type.php" );
2443
    
2444
    // Abort if this is not our element.
2445
    if ( empty( $located ) || ! file_exists( $located ) ) {
2446
        return;
2447
    }
2448
2449
    // Generate the class and id of the element.
2450
    $wrapper_class = 'getpaid-payment-form-element-' . trim( esc_attr( $element_type ) );
2451
    $id            = isset( $id ) ? $id : uniqid( 'gp' );
2452
2453
    // Echo the opening wrapper.
2454
    echo "<div class='getpaid-payment-form-element $wrapper_class'>";
2455
2456
    // Fires before displaying a given element type's content.
2457
    do_action( "getpaid_before_payment_form_{$element_type}_element", $element, $form );
2458
2459
    // Include the template for the element.
2460
    include $located;
2461
2462
    // Fires after displaying a given element type's content.
2463
    do_action( "getpaid_payment_form_{$element_type}_element", $element, $form );
2464
2465
    // Echo the closing wrapper.
2466
    echo '</div>';
2467
}
2468
add_action( 'getpaid_payment_form_element', 'getpaid_payment_form_element', 10, 2 );
2469
2470
/**
2471
 * Shows a list of gateways that support recurring payments.
2472
 */
2473
function wpinv_get_recurring_gateways_text() {
2474
    $gateways = array();
2475
2476
    foreach ( wpinv_get_payment_gateways() as $key => $gateway ) {
2477
        if ( wpinv_gateway_support_subscription( $key ) ) {
2478
            $gateways[] = sanitize_text_field( $gateway['admin_label'] );
2479
        }
2480
    }
2481
2482
    if ( empty( $gateways ) ) {
2483
        return "<span class='form-text text-danger'>" . __( 'No active gateways support subscription payments.', 'invoicing' ) ."</span>";
2484
    }
2485
2486
    return "<span class='form-text text-muted'>" . wp_sprintf( __( 'Subscription payments only supported by: %s', 'invoicing' ), implode( ', ', $gateways ) ) ."</span>";
2487
2488
}
2489