Issues (865)

Security Analysis    4 potential vulnerabilities

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection (1)
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection (2)
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting (1)
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/class-wpinv-subscriptions.php (6 issues)

1
<?php
2
/**
3
 * Main Subscriptions class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
/**
9
 * Main Subscriptions class.
10
 *
11
 */
12
class WPInv_Subscriptions {
13
14
    /**
15
	 * Class constructor.
16
	 */
17
    public function __construct() {
18
19
        // Fire gateway specific hooks when a subscription changes.
20
        add_action( 'getpaid_subscription_status_changed', array( $this, 'process_subscription_status_change' ), 10, 3 );
21
22
        // De-activate a subscription whenever the invoice changes payment statuses.
23
        add_action( 'getpaid_invoice_status_changed', array( $this, 'maybe_deactivate_invoice_subscription' ), 20, 1 );
24
25
        // Handles subscription cancelations.
26
        add_action( 'getpaid_authenticated_action_subscription_cancel', array( $this, 'user_cancel_single_subscription' ) );
27
28
        // Create a subscription whenever an invoice is created, (and update it when it is updated).
29
        add_action( 'wpinv_invoice_metabox_saved', array( $this, 'maybe_update_invoice_subscription' ), 5 );
30
        add_action( 'getpaid_checkout_invoice_updated', array( $this, 'maybe_update_invoice_subscription' ), 5 );
31
32
        // Handles admin subscription update actions.
33
        add_action( 'getpaid_authenticated_admin_action_update_single_subscription', array( $this, 'admin_update_single_subscription' ) );
34
        add_action( 'getpaid_authenticated_admin_action_subscription_manual_renew', array( $this, 'admin_renew_single_subscription' ) );
35
        add_action( 'getpaid_authenticated_admin_action_subscription_manual_delete', array( $this, 'admin_delete_single_subscription' ) );
36
37
        // Filter invoice item row actions.
38
        add_action( 'getpaid-invoice-page-line-item-actions', array( $this, 'filter_invoice_line_item_actions' ), 10, 3 );
39
    }
40
41
    /**
42
     * Returns an invoice's subscription.
43
     *
44
     * @param WPInv_Invoice $invoice
45
     * @return WPInv_Subscription|bool
46
     */
47
    public function get_invoice_subscription( $invoice ) {
48
        $subscription_id = $invoice->get_subscription_id();
49
50
        // Fallback to the parent invoice if the child invoice has no subscription id.
51
        if ( empty( $subscription_id ) && $invoice->is_renewal() ) {
52
            $subscription_id = $invoice->get_parent_payment()->get_subscription_id();
53
        }
54
55
        // Fetch the subscription.
56
        $subscription = new WPInv_Subscription( $subscription_id );
57
58
        // Return subscription or use a fallback for backwards compatibility.
59
        return $subscription->exists() ? $subscription : wpinv_get_invoice_subscription( $invoice );
60
    }
61
62
    /**
63
     * Returns the appropriate subscription status based on the invoice status.
64
     *
65
     * @param string $invoice_status
66
     * @return string
67
     */
68
    protected function get_subscription_status_from_invoice_status( $invoice_status ) {
69
        $status_mapping = array(
70
            'draft'            => 'pending',
71
            'wpi-failed'       => 'failing',
72
            'wpi-processing'   => 'pending',
73
            'wpi-onhold'       => 'pending',
74
            'publish'          => 'active',
75
            'wpi-renewal'      => 'pending',
76
            'wpi-cancelled'    => 'cancelled',
77
            'wpi-pending'      => 'pending',
78
            'wpi-refunded'     => 'cancelled',
79
        );
80
81
        return isset( $status_mapping[ $invoice_status ] ) ? $status_mapping[ $invoice_status ] : 'pending';
82
    }
83
84
    /**
85
     * Deactivates the invoice subscription(s) whenever an invoice status changes.
86
     *
87
     * @param WPInv_Invoice $invoice
88
     */
89
    public function maybe_deactivate_invoice_subscription( $invoice ) {
90
91
        $subscriptions = getpaid_get_invoice_subscriptions( $invoice );
92
93
        if ( empty( $subscriptions ) ) {
94
            return;
95
        }
96
97
        if ( ! is_array( $subscriptions ) ) {
0 ignored issues
show
The condition is_array($subscriptions) is always false.
Loading history...
98
            $subscriptions = array( $subscriptions );
99
        }
100
101
        $new_status = $this->get_subscription_status_from_invoice_status( $invoice->get_status() );
102
103
        foreach ( $subscriptions as $subscription ) {
104
            $subscription->set_status( $new_status );
105
            $subscription->save();
106
        }
107
108
    }
109
110
    /**
111
	 * Processes subscription status changes.
112
     *
113
     * @param WPInv_Subscription $subscription
114
     * @param string $from
115
     * @param string $to
116
	 */
117
    public function process_subscription_status_change( $subscription, $from, $to ) {
118
119
        $gateway = $subscription->get_gateway();
120
121
        if ( ! empty( $gateway ) ) {
122
            $gateway = sanitize_key( $gateway );
123
            $from    = sanitize_key( $from );
124
            $to      = sanitize_key( $to );
125
            do_action( "getpaid_{$gateway}_subscription_$to", $subscription, $from );
126
        }
127
128
    }
129
130
    /**
131
     * Get pretty subscription frequency
132
     *
133
     * @param $period
134
     * @param int $frequency_count The frequency of the period.
135
     * @deprecated
136
     * @return mixed|string|void
137
     */
138
    public static function wpinv_get_pretty_subscription_frequency( $period, $frequency_count = 1 ) {
139
        return getpaid_get_subscription_period_label( $period, $frequency_count );
140
    }
141
142
    /**
143
     * Handles cancellation requests for a subscription
144
     *
145
     * @access      public
146
     * @since       1.0.0
147
     * @return      void
148
     */
149
    public function user_cancel_single_subscription( $data ) {
150
151
        // Ensure there is a subscription to cancel.
152
        if ( empty( $data['subscription'] ) ) {
153
            return;
154
        }
155
156
        $subscription = new WPInv_Subscription( (int) $data['subscription'] );
157
158
        // Ensure that it exists and that it belongs to the current user.
159
        if ( ! $subscription->exists() || $subscription->get_customer_id() != get_current_user_id() ) {
160
            $notice = 'perm_cancel_subscription';
161
162
        // Can it be cancelled.
163
        } elseif ( ! $subscription->can_cancel() ) {
164
            $notice = 'cannot_cancel_subscription';
165
166
        // Cancel it.
167
        } else {
168
169
            $subscription->cancel();
170
            $notice = 'cancelled_subscription';
171
        }
172
173
        $redirect = array(
174
            'getpaid-action' => false,
175
            'getpaid-nonce'  => false,
176
            'wpinv-notice'   => $notice,
177
        );
178
179
        wp_safe_redirect( add_query_arg( $redirect ) );
180
        exit;
0 ignored issues
show
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...
181
182
    }
183
184
    /**
185
     * Creates a subscription(s) for an invoice.
186
     *
187
     * @access      public
188
     * @param       WPInv_Invoice $invoice
189
     * @since       1.0.0
190
     */
191
    public function maybe_create_invoice_subscription( $invoice ) {
192
        global $getpaid_subscriptions_skip_invoice_update;
193
194
        // Abort if it is not recurring.
195
        if ( ! $invoice->is_type( 'invoice' ) || $invoice->is_free() || ! $invoice->is_recurring() || $invoice->is_renewal() ) {
196
            return;
197
        }
198
199
        // Either group the subscriptions or only process a single suscription.
200
        if ( getpaid_should_group_subscriptions( $invoice ) ) {
201
202
            $subscription_groups = array();
203
            $is_first            = true;
204
205
            foreach ( getpaid_calculate_subscription_totals( $invoice ) as $group_key => $totals ) {
206
                $subscription_groups[ $group_key ] = $this->create_invoice_subscription_group( $totals, $invoice, 0, $is_first );
207
208
                if ( $is_first ) {
209
                    $getpaid_subscriptions_skip_invoice_update = true;
210
                    $invoice->set_subscription_id( $subscription_groups[ $group_key ]['subscription_id'] );
211
                    $invoice->save();
212
                    $getpaid_subscriptions_skip_invoice_update = false;
213
                }
214
215
                $is_first                          = false;
216
            }
217
218
            // Cache subscription groups.
219
            update_post_meta( $invoice->get_id(), 'getpaid_subscription_groups', $subscription_groups );
220
            return true;
221
222
        }
223
224
        $subscription = new WPInv_Subscription();
225
        return $this->update_invoice_subscription( $subscription, $invoice );
226
227
    }
228
229
    /**
230
     * Saves a new invoice subscription group.
231
     *
232
     * @access      public
233
     * @param       array $totals
234
     * @param       WPInv_Invoice $invoice
235
     * @param       int $subscription_id Current subscription id of the group.
236
     * @param       bool $is_first Whether or not this is the first subscription group for the invoice. In which case we'll add totals of non-recurring items.
237
     *
238
     * @since       2.3.0
239
     */
240
    public function create_invoice_subscription_group( $totals, $invoice, $subscription_id = 0, $is_first = false ) {
241
242
        $subscription  = new WPInv_Subscription( (int) $subscription_id );
243
        $initial_amt   = $totals['initial_total'];
244
        $recurring_amt = $totals['recurring_total'];
245
        $fees          = array();
246
247
        // Maybe add recurring fees.
248
        if ( $is_first ) {
249
250
            foreach ( $invoice->get_fees() as $i => $fee ) {
251
                if ( ! empty( $fee['recurring_fee'] ) ) {
252
                    $initial_amt   += wpinv_sanitize_amount( $fee['initial_fee'] );
253
                    $recurring_amt += wpinv_sanitize_amount( $fee['recurring_fee'] );
254
                    $fees[ $i ]       = $fee;
255
                }
256
            }
257
        }
258
259
        $subscription->set_customer_id( $invoice->get_user_id() );
260
        $subscription->set_parent_invoice_id( $invoice->get_id() );
261
        $subscription->set_initial_amount( $initial_amt );
262
        $subscription->set_recurring_amount( $recurring_amt );
263
        $subscription->set_date_created( current_time( 'mysql' ) );
264
        $subscription->set_status( $invoice->is_paid() ? 'active' : 'pending' );
265
        $subscription->set_product_id( $totals['item_id'] );
266
        $subscription->set_period( $totals['period'] );
267
        $subscription->set_frequency( $totals['interval'] );
268
        $subscription->set_bill_times( $totals['recurring_limit'] );
269
        $subscription->set_next_renewal_date( $totals['renews_on'] );
270
271
        // Trial periods.
272
        if ( ! empty( $totals['trialling'] ) ) {
273
            $subscription->set_trial_period( $totals['trialling'] );
274
            $subscription->set_status( 'trialling' );
275
276
        // If initial amount is free, treat it as a free trial even if the subscription item does not have a free trial.
277
        } elseif ( empty( $initial_amt ) ) {
278
            $subscription->set_trial_period( $totals['interval'] . ' ' . $totals['period'] );
279
            $subscription->set_status( 'trialling' );
280
        }
281
282
        $subscription->save();
283
284
        $totals['subscription_id'] = $subscription->get_id();
285
        $totals['fees']            = $fees;
286
287
        return $totals;
288
    }
289
290
    /**
291
     * (Maybe) Updates a subscription for an invoice.
292
     *
293
     * @access      public
294
     * @param       WPInv_Invoice $invoice
295
     * @since       1.0.19
296
     */
297
    public function maybe_update_invoice_subscription( $invoice ) {
298
        global $getpaid_subscriptions_skip_invoice_update;
299
300
        // Avoid infinite loops.
301
        if ( ! empty( $getpaid_subscriptions_skip_invoice_update ) ) {
302
            return;
303
        }
304
305
        // Do not process renewals.
306
        if ( $invoice->is_renewal() ) {
307
            return;
308
        }
309
310
        // Delete existing subscriptions if available and the invoice is not recurring.
311
        if ( ! $invoice->is_recurring() ) {
312
            $this->delete_invoice_subscriptions( $invoice );
313
            return;
314
        }
315
316
        // Fetch existing subscriptions.
317
        $subscriptions = getpaid_get_invoice_subscriptions( $invoice );
318
319
        // Create new ones if no existing subscriptions.
320
        if ( empty( $subscriptions ) ) {
321
            return $this->maybe_create_invoice_subscription( $invoice );
322
        }
323
324
        // Abort if an invoice is paid and already has a subscription.
325
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
326
            return;
327
        }
328
329
        $is_grouped   = is_array( $subscriptions );
330
        $should_group = getpaid_should_group_subscriptions( $invoice );
331
332
        // Ensure that the subscriptions are only grouped if there are more than 1 recurring items.
333
        if ( $is_grouped != $should_group ) {
334
            $this->delete_invoice_subscriptions( $invoice );
335
            delete_post_meta( $invoice->get_id(), 'getpaid_subscription_groups' );
336
            return $this->maybe_create_invoice_subscription( $invoice );
337
        }
338
339
        // If there is only one recurring item...
340
        if ( ! $is_grouped ) {
341
            return $this->update_invoice_subscription( $subscriptions, $invoice );
342
        }
343
344
        // Process subscription groups.
345
        $current_groups      = getpaid_get_invoice_subscription_groups( $invoice->get_id() );
346
        $subscription_groups = array();
347
        $is_first            = true;
348
349
        // Create new subscription groups.
350
        foreach ( getpaid_calculate_subscription_totals( $invoice ) as $group_key => $totals ) {
351
            $subscription_id                   = isset( $current_groups[ $group_key ] ) ? $current_groups[ $group_key ]['subscription_id'] : 0;
352
            $subscription_groups[ $group_key ] = $this->create_invoice_subscription_group( $totals, $invoice, $subscription_id, $is_first );
353
354
            if ( $is_first && $invoice->get_subscription_id() !== $subscription_groups[ $group_key ]['subscription_id'] ) {
355
                $getpaid_subscriptions_skip_invoice_update = true;
356
                $invoice->set_subscription_id( $subscription_groups[ $group_key ]['subscription_id'] );
357
                $invoice->save();
358
                $getpaid_subscriptions_skip_invoice_update = false;
359
            }
360
361
            $is_first                          = false;
362
        }
363
364
        // Delete non-existent subscription groups.
365
        foreach ( $current_groups as $group_key => $data ) {
366
            if ( ! isset( $subscription_groups[ $group_key ] ) ) {
367
                $subscription = new WPInv_Subscription( (int) $data['subscription_id'] );
368
369
                if ( $subscription->exists() ) {
370
                    $subscription->delete( true );
371
                }
372
}
373
        }
374
375
        // Cache subscription groups.
376
        update_post_meta( $invoice->get_id(), 'getpaid_subscription_groups', $subscription_groups );
377
        return true;
378
379
    }
380
381
    /**
382
     * Deletes invoice subscription(s).
383
     *
384
     * @param WPInv_Invoice $invoice
385
     */
386
    public function delete_invoice_subscriptions( $invoice ) {
387
388
        $subscriptions = getpaid_get_invoice_subscriptions( $invoice );
389
390
        if ( empty( $subscriptions ) ) {
391
            return;
392
        }
393
394
        if ( ! is_array( $subscriptions ) ) {
0 ignored issues
show
The condition is_array($subscriptions) is always false.
Loading history...
395
            $subscriptions = array( $subscriptions );
396
        }
397
398
        foreach ( $subscriptions as $subscription ) {
399
            $subscription->delete( true );
400
        }
401
402
    }
403
404
    /**
405
     * Updates a subscription for an invoice.
406
     *
407
     * @access      public
408
     * @param       WPInv_Subscription $subscription
409
     * @param       WPInv_Invoice $invoice
410
     * @since       1.0.19
411
     */
412
    public function update_invoice_subscription( $subscription, $invoice ) {
413
414
        // Delete the subscription if an invoice is free or nolonger recurring.
415
        if ( ! $invoice->is_type( 'invoice' ) || $invoice->is_free() || ! $invoice->is_recurring() ) {
416
            return $subscription->delete();
417
        }
418
419
        $subscription->set_customer_id( $invoice->get_user_id() );
420
        $subscription->set_parent_invoice_id( $invoice->get_id() );
421
        $subscription->set_initial_amount( $invoice->get_initial_total() );
422
        $subscription->set_recurring_amount( $invoice->get_recurring_total() );
423
        $subscription->set_date_created( current_time( 'mysql' ) );
424
        $subscription->set_status( $invoice->is_paid() ? 'active' : 'pending' );
425
426
        // Get the recurring item and abort if it does not exist.
427
        $subscription_item = $invoice->get_recurring( true );
428
        if ( ! $subscription_item->get_id() ) {
429
            $invoice->set_subscription_id( 0 );
430
            $invoice->save();
431
            return $subscription->delete();
432
        }
433
434
        $subscription->set_product_id( $subscription_item->get_id() );
435
        $subscription->set_period( $subscription_item->get_recurring_period( true ) );
436
        $subscription->set_frequency( $subscription_item->get_recurring_interval() );
437
        $subscription->set_bill_times( $subscription_item->get_recurring_limit() );
438
439
        // Calculate the next renewal date.
440
        $period       = $subscription_item->get_recurring_period( true );
441
        $interval     = $subscription_item->get_recurring_interval();
442
443
        // If the subscription item has a trial period...
444
        if ( $subscription_item->has_free_trial() ) {
445
            $period   = $subscription_item->get_trial_period( true );
446
            $interval = $subscription_item->get_trial_interval();
447
            $subscription->set_trial_period( $interval . ' ' . $period );
448
            $subscription->set_status( 'trialling' );
449
        }
450
451
        // If initial amount is free, treat it as a free trial even if the subscription item does not have a free trial.
452
        if ( $invoice->has_free_trial() ) {
453
            $subscription->set_trial_period( $interval . ' ' . $period );
454
            $subscription->set_status( 'trialling' );
455
        }
456
457
        // Calculate the next renewal date.
458
        $expiration = date( 'Y-m-d H:i:s', strtotime( "+$interval $period", strtotime( $subscription->get_date_created() ) ) );
459
460
        $subscription->set_next_renewal_date( $expiration );
461
        $subscription->save();
462
        $invoice->set_subscription_id( $subscription->get_id() );
463
        return $subscription->get_id();
464
465
    }
466
467
    /**
468
     * Fired when an admin updates a subscription via the single subscription single page.
469
     *
470
     * @param       array $data
471
     * @since       1.0.19
472
     */
473
    public function admin_update_single_subscription( $args ) {
474
475
        // Ensure the subscription exists and that a status has been given.
476
        if ( empty( $args['subscription_id'] ) ) {
477
            return;
478
        }
479
480
        // Retrieve the subscriptions.
481
        $subscription = new WPInv_Subscription( $args['subscription_id'] );
482
483
        if ( $subscription->get_id() ) {
484
485
            $subscription->set_props(
486
                array(
487
                    'status'       => isset( $args['subscription_status'] ) ? $args['subscription_status'] : null,
488
                    'profile_id'   => isset( $args['wpinv_subscription_profile_id'] ) ? $args['wpinv_subscription_profile_id'] : null,
489
                    'date_created' => ! empty( $args['wpinv_subscription_date_created'] ) ? $args['wpinv_subscription_date_created'] : null,
490
                    'expiration'   => ! empty( $args['wpinv_subscription_expiration'] ) ? $args['wpinv_subscription_expiration'] : null,
491
                    'bill_times'   => ! empty( $args['wpinv_subscription_max_bill_times'] ) ? $args['wpinv_subscription_max_bill_times'] : null,
492
                )
493
            );
494
495
            $changes = $subscription->get_changes();
496
497
            $subscription->save();
498
            getpaid_admin()->show_info( __( 'Subscription updated', 'invoicing' ) );
499
500
            do_action( 'getpaid_admin_updated_subscription', $subscription, $args, $changes );
501
        }
502
503
    }
504
505
    /**
506
     * Fired when an admin manually renews a subscription.
507
     *
508
     * @param       array $data
509
     * @since       1.0.19
510
     */
511
    public function admin_renew_single_subscription( $args ) {
512
513
        // Ensure the subscription exists and that a status has been given.
514
        if ( empty( $args['id'] ) ) {
515
            return;
516
        }
517
518
        // Retrieve the subscriptions.
519
        $subscription = new WPInv_Subscription( $args['id'] );
520
521
        if ( $subscription->get_id() ) {
522
523
            do_action( 'getpaid_admin_renew_subscription', $subscription );
524
525
            $args = array( 'transaction_id', $subscription->get_parent_invoice()->generate_key( 'renewal_' ) );
526
527
            if ( ! $subscription->add_payment( $args ) ) {
528
                getpaid_admin()->show_error( __( 'We are unable to renew this subscription as the parent invoice does not exist.', 'invoicing' ) );
529
            } else {
530
                $subscription->renew();
531
                getpaid_admin()->show_info( __( 'This subscription has been renewed and extended.', 'invoicing' ) );
532
            }
533
534
            wp_safe_redirect(
535
                add_query_arg(
536
                    array(
537
                        'getpaid-admin-action' => false,
538
                        'getpaid-nonce'        => false,
539
                    )
540
                )
541
            );
542
            exit;
0 ignored issues
show
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...
543
544
        }
545
546
    }
547
548
    /**
549
     * Fired when an admin manually deletes a subscription.
550
     *
551
     * @param       array $data
552
     * @since       1.0.19
553
     */
554
    public function admin_delete_single_subscription( $args ) {
555
556
        // Ensure the subscription exists and that a status has been given.
557
        if ( empty( $args['id'] ) ) {
558
            return;
559
        }
560
561
        // Retrieve the subscriptions.
562
        $subscription = new WPInv_Subscription( $args['id'] );
563
564
        if ( $subscription->delete() ) {
565
            getpaid_admin()->show_info( __( 'This subscription has been deleted.', 'invoicing' ) );
566
        } else {
567
            getpaid_admin()->show_error( __( 'We are unable to delete this subscription. Please try again.', 'invoicing' ) );
568
        }
569
570
        $redirected = wp_safe_redirect(
571
            add_query_arg(
572
                array(
573
                    'getpaid-admin-action' => false,
574
                    'getpaid-nonce'        => false,
575
                    'id'                   => false,
576
                )
577
            )
578
        );
579
580
        if ( $redirected ) {
581
            exit;
0 ignored issues
show
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...
582
        }
583
584
    }
585
586
    /**
587
     * Filters the invoice line items actions.
588
     *
589
     * @param array actions
0 ignored issues
show
The type actions was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
590
     * @param WPInv_Item $item
591
     * @param WPInv_Invoice $invoice
592
     */
593
    public function filter_invoice_line_item_actions( $actions, $item, $invoice ) {
594
595
        // Abort if this invoice uses subscription groups.
596
        $subscriptions = getpaid_get_invoice_subscriptions( $invoice );
597
        if ( ! $invoice->is_recurring() || ! is_object( $subscriptions ) ) {
598
            return $actions;
599
        }
600
601
        // Fetch item subscription.
602
        $args  = array(
603
            'invoice_in'  => $invoice->is_parent() ? $invoice->get_id() : $invoice->get_parent_id(),
604
            'product_in'  => $item->get_id(),
605
            'number'      => 1,
606
            'count_total' => false,
607
            'fields'      => 'id',
608
        );
609
610
        $subscription = new GetPaid_Subscriptions_Query( $args );
611
        $subscription = $subscription->get_results();
612
613
        // In case we found a match...
614
        if ( ! empty( $subscription ) ) {
615
            $url                     = esc_url( add_query_arg( 'subscription', (int) $subscription[0], get_permalink( (int) wpinv_get_option( 'invoice_subscription_page' ) ) ) );
616
            $actions['subscription'] = "<a href='$url' class='text-decoration-none'>" . __( 'Manage Subscription', 'invoicing' ) . '</a>';
617
        }
618
619
        return $actions;
620
621
    }
622
623
}
624