├── assets
└── js
│ ├── wc-pd-writepanels.min.js
│ └── wc-pd-writepanels.js
├── .gitignore
├── package.json
├── README.md
├── class-wc-pd-core-compatibility.php
├── Gruntfile.js
├── class-wc-pd-helpers.php
├── readme.txt
├── languages
└── woocommerce-product-dependencies.pot
└── woocommerce-product-dependencies.php
/assets/js/wc-pd-writepanels.min.js:
--------------------------------------------------------------------------------
1 | jQuery(function(e){function d(){"product_ids"==c.val()?(n.show(),i.hide()):(i.show(),n.hide())}var c=e("#product_dependencies_dropdown"),n=e("#product_ids_dependencies_choice"),i=e("#category_ids_dependencies_choice");d(),c.change(function(){d()})});
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Editors
2 | project.xml
3 | project.properties
4 | /nbproject/private/
5 | .buildpath
6 | .project
7 | .settings*
8 | sftp-config.json
9 | .idea
10 |
11 | # Grunt
12 | /node_modules/
13 | /vendor/
14 | /deploy/
15 | npm-debug.log
16 | package-lock.json
17 |
18 | # Sass
19 | .sass-cache/
20 |
21 | # OS X metadata
22 | .DS_Store
23 |
24 | # Windows junk
25 | Thumbs.db
26 |
27 | # ApiGen
28 | /wc-apidocs/
29 |
30 | # Unit tests
31 | /tmp
32 | /tests/coverage/
33 |
34 | # Logs
35 | /logs
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "woocommerce-product-dependencies",
3 | "title": "WooCommerce Product Dependencies",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/woocommerce/woocommerce-product-dependencies.git"
7 | },
8 | "license": "GPL-3.0+",
9 | "version": "2.0.1",
10 | "main": "Gruntfile.js",
11 | "devDependencies": {
12 | "grunt": "~1.0.1",
13 | "grunt-checktextdomain": "~1.0.0",
14 | "grunt-contrib-jshint": "~1.1.0",
15 | "grunt-contrib-uglify": "~3.0.0",
16 | "grunt-contrib-watch": "^1.1.0",
17 | "grunt-wp-i18n": "~0.5.4"
18 | },
19 | "engines": {
20 | "node": ">=6.9.4",
21 | "npm": ">=1.1.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/assets/js/wc-pd-writepanels.js:
--------------------------------------------------------------------------------
1 | jQuery( function( $ ) {
2 |
3 | var $product_dependencies_dropdown = $( '#product_dependencies_dropdown' ),
4 | $product_ids_dependencies_choice = $( '#product_ids_dependencies_choice' ),
5 | $category_ids_dependencies_choice = $( '#category_ids_dependencies_choice' );
6 |
7 | function initialize() {
8 | if ( $product_dependencies_dropdown.val() == 'product_ids' ) {
9 | $product_ids_dependencies_choice.show();
10 | $category_ids_dependencies_choice.hide();
11 |
12 | } else {
13 | $category_ids_dependencies_choice.show();
14 | $product_ids_dependencies_choice.hide();
15 | }
16 | }
17 |
18 | initialize();
19 |
20 | $product_dependencies_dropdown.change( function() {
21 | initialize();
22 | } );
23 |
24 | } );
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [WooCommerce Product Dependencies](https://wordpress.org/plugins/woocommerce-product-dependencies/)
2 |
3 | ## Description
4 |
5 | Lightweight WooCommerce plugin that allows you to restrict access to any product, depending on the ownership and/or purchase of other, required products.
6 |
7 |
8 |
9 |
10 |
11 | Features:
12 |
13 | * **Conditional product access** based on the ownership and/or purchase of required products.
14 | * Streamlined admin interface – product dependencies are entered in a dedicated **Dependencies** tab.
15 | * Support for multiple product dependencies.
16 | * Support for "ownership", "purchase" and "ownership/purchase" dependency types.
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | **Important**: Requires WooCommerce 2.2+. WooCommerce 3.0+ or higher recommended.
25 |
26 | **Important**: The code in this plugin is provided "as is". Support via the WordPress.org forum is provided on a **voluntary** basis only.
27 |
--------------------------------------------------------------------------------
/class-wc-pd-core-compatibility.php:
--------------------------------------------------------------------------------
1 | =' );
38 | }
39 |
40 | /**
41 | * Returns true if the installed version of WooCommerce is greater than $version.
42 | *
43 | * @param string $version the version to compare
44 | * @return boolean true if the installed version of WooCommerce is > $version
45 | */
46 | public static function is_wc_version_gt( $version ) {
47 | return self::get_wc_version() && version_compare( self::get_wc_version(), $version, '>' );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /* jshint node:true */
2 | module.exports = function( grunt ) {
3 | 'use strict';
4 |
5 | grunt.initConfig({
6 |
7 | // setting folder templates
8 | dirs: {
9 | css: 'assets/css',
10 | js: 'assets/js'
11 | },
12 |
13 | // JavaScript linting with JSHint.
14 | jshint: {
15 | options: {
16 | 'force': true,
17 | 'boss': true,
18 | 'curly': true,
19 | 'eqeqeq': false,
20 | 'eqnull': true,
21 | 'es3': false,
22 | 'expr': false,
23 | 'immed': true,
24 | 'noarg': true,
25 | 'onevar': true,
26 | 'quotmark': 'single',
27 | 'trailing': true,
28 | 'undef': true,
29 | 'unused': true,
30 | 'sub': false,
31 | 'browser': true,
32 | 'maxerr': 1000,
33 | globals: {
34 | 'jQuery': false,
35 | '$': false,
36 | 'Backbone': false,
37 | '_': false,
38 | 'wc_bundle_params': false,
39 | 'wc_pb_number_round': false
40 | },
41 | },
42 | all: [
43 | 'Gruntfile.js',
44 | '<%= dirs.js %>/*.js',
45 | '!<%= dirs.js %>/*.min.js'
46 | ]
47 | },
48 |
49 | // Minify .js files.
50 | uglify: {
51 | options: {
52 | preserveComments: false
53 | },
54 | jsfiles: {
55 | files: [{
56 | expand: true,
57 | cwd: '<%= dirs.js %>',
58 | src: [
59 | '*.js',
60 | '!*.min.js'
61 | ],
62 | dest: '<%= dirs.js %>',
63 | ext: '.min.js'
64 | }]
65 | }
66 | },
67 |
68 | // Watch changes for assets.
69 | watch: {
70 | js: {
71 | files: [
72 | '<%= dirs.js %>/*js'
73 | ],
74 | tasks: ['uglify']
75 | }
76 | },
77 |
78 | // Generate POT files.
79 | makepot: {
80 | options: {
81 | type: 'wp-plugin',
82 | domainPath: 'languages'
83 | },
84 | go: {
85 | options: {
86 | potFilename: 'woocommerce-product-dependencies.pot',
87 | exclude: [
88 | 'languages/.*',
89 | 'assets/.*',
90 | 'node-modules/.*',
91 | 'woo-includes/.*'
92 | ]
93 | }
94 | }
95 | },
96 |
97 | // Check textdomain errors.
98 | checktextdomain: {
99 | options:{
100 | text_domain: [ 'woocommerce-product-dependencies', 'woocommerce' ],
101 | keywords: [
102 | '__:1,2d',
103 | '_e:1,2d',
104 | '_x:1,2c,3d',
105 | 'esc_html__:1,2d',
106 | 'esc_html_e:1,2d',
107 | 'esc_html_x:1,2c,3d',
108 | 'esc_attr__:1,2d',
109 | 'esc_attr_e:1,2d',
110 | 'esc_attr_x:1,2c,3d',
111 | '_ex:1,2c,3d',
112 | '_n:1,2,4d',
113 | '_nx:1,2,4c,5d',
114 | '_n_noop:1,2,3d',
115 | '_nx_noop:1,2,3c,4d'
116 | ]
117 | },
118 | files: {
119 | src: [
120 | '**/*.php', // Include all files
121 | '!apigen/**', // Exclude apigen/
122 | '!deploy/**', // Exclude deploy/
123 | '!node_modules/**' // Exclude node_modules/
124 | ],
125 | expand: true
126 | }
127 | }
128 | });
129 |
130 | // Load NPM tasks to be used here.
131 | grunt.loadNpmTasks( 'grunt-contrib-jshint' );
132 | grunt.loadNpmTasks( 'grunt-contrib-uglify' );
133 | grunt.loadNpmTasks( 'grunt-contrib-watch' );
134 | grunt.loadNpmTasks( 'grunt-wp-i18n' );
135 | grunt.loadNpmTasks( 'grunt-checktextdomain' );
136 |
137 | // Register tasks.
138 | grunt.registerTask( 'dev', [
139 | 'checktextdomain',
140 | 'uglify'
141 | ]);
142 |
143 | grunt.registerTask( 'default', [
144 | 'dev',
145 | 'makepot'
146 | ]);
147 |
148 | grunt.registerTask( 'domain', [
149 | 'checktextdomain'
150 | ]);
151 | };
152 |
--------------------------------------------------------------------------------
/class-wc-pd-helpers.php:
--------------------------------------------------------------------------------
1 | $product ) {
62 |
63 | $part_to_merge = self::get_part_to_merge_expression( $loop, count( $products ), $relationship );
64 | $product_permalink = $product->is_visible() ? $product->get_permalink() : '';
65 | $product_title = $product->get_name();
66 |
67 | if ( $product_permalink ) {
68 | $part_to_merge = sprintf( $part_to_merge, sprintf( '"%2$s"', esc_url( $product_permalink ), $product_title ) );
69 | } else {
70 | $part_to_merge = sprintf( $part_to_merge, sprintf( '"%s"', $product_title ) );
71 | }
72 |
73 | $parts_to_merge[] = $part_to_merge;
74 |
75 | $loop++;
76 | }
77 | }
78 |
79 | if ( is_rtl() ) {
80 | $parts_to_merge = array_reverse( $parts_to_merge );
81 | }
82 |
83 | return implode( '', $parts_to_merge );
84 | }
85 |
86 | /**
87 | * Merges category titles.
88 | *
89 | * @since 1.2.0
90 | *
91 | * @param array $category_ids
92 | * @param string $relationship
93 | * @return string
94 | */
95 | public static function merge_category_titles( $category_ids, $relationship ) {
96 |
97 | $parts_to_merge = array();
98 |
99 | if ( ! empty( $category_ids ) ) {
100 |
101 | $loop = 0;
102 |
103 | foreach ( $category_ids as $category_id ) {
104 |
105 | $part_to_merge = self::get_part_to_merge_expression( $loop, count( $category_ids ), $relationship );
106 | $category_permalink = get_term_link( $category_id, 'product_cat' );
107 |
108 | if ( $term = get_term_by( 'id', $category_id, 'product_cat' ) ){
109 | $category_title = $term->name;
110 | } else {
111 | continue;
112 | }
113 |
114 | if ( $category_permalink ) {
115 | $part_to_merge = sprintf( $part_to_merge, sprintf( '"%2$s"', esc_url( $category_permalink ), $category_title ) );
116 | } else {
117 | $part_to_merge = sprintf( $part_to_merge, sprintf( '"%s"', $category_title ) );
118 | }
119 |
120 | $parts_to_merge[] = $part_to_merge;
121 |
122 | $loop++;
123 | }
124 | }
125 |
126 | if ( is_rtl() ) {
127 | $parts_to_merge = array_reverse( $parts_to_merge );
128 | }
129 |
130 | return implode( '', $parts_to_merge );
131 | }
132 |
133 | /**
134 | * Return a formatted product title.
135 | *
136 | * @param WC_Product|int $product
137 | * @param string $title
138 | * @return string
139 | */
140 | public static function get_product_title( $product, $title = '' ) {
141 |
142 | if ( ! is_object( $product ) ) {
143 | $product = wc_get_product( $product );
144 | }
145 |
146 | if ( ! $product ) {
147 | return false;
148 | }
149 |
150 | return $product->get_formatted_name();
151 | }
152 |
153 | /**
154 | * Format a product title.
155 | *
156 | * @param string $title
157 | * @param string $identifier
158 | * @param string $meta
159 | * @param string $paren
160 | * @return string
161 | */
162 | public static function format_product_title( $title, $identifier = '', $meta = '', $paren = false ) {
163 |
164 | if ( $identifier && $meta ) {
165 | if ( $paren ) {
166 | $title = sprintf( _x( '%1$s – %2$s (%3$s)', 'product title followed by meta and sku in parenthesis', 'woocommerce-product-dependencies' ), $title, $meta, $identifier );
167 | } else {
168 | $title = sprintf( _x( '%1$s – %2$s – %3$s', 'sku followed by product title and meta', 'woocommerce-product-dependencies' ), $identifier, $title, $meta );
169 | }
170 | } elseif ( $identifier ) {
171 | if ( $paren ) {
172 | $title = sprintf( _x( '%1$s (%2$s)', 'product title followed by sku in parenthesis', 'woocommerce-product-dependencies' ), $title, $identifier );
173 | } else {
174 | $title = sprintf( _x( '%1$s – %2$s', 'sku followed by product title', 'woocommerce-product-dependencies' ), $identifier, $title );
175 | }
176 | } elseif ( $meta ) {
177 | if ( $paren ) {
178 | $title = sprintf( _x( '%1$s (%2$s)', 'product title followed by meta in parenthesis', 'woocommerce-product-dependencies' ), $title, $meta );
179 | } else {
180 | $title = sprintf( _x( '%1$s – %2$s', 'product title followed by meta', 'woocommerce-product-dependencies' ), $title, $meta );
181 | }
182 | }
183 |
184 | return $title;
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === WooCommerce Product Dependencies ===
2 |
3 | Contributors: automattic, woocommerce, SomewhereWarm
4 | Tags: woocommerce, products, dependencies, prerequisite, restrict
5 | Requires at least: 6.2
6 | Tested up to: 6.6
7 | WC requires at least: 8.2
8 | WC tested up to: 9.1
9 | Stable tag: 2.0.1
10 | License: GPLv2 or later
11 | License URI: http://www.gnu.org/licenses/gpl-2.0.html
12 |
13 | Restrict access to any WooCommerce product, depending on the ownership and/or purchase of other required products.
14 |
15 |
16 | == Description ==
17 |
18 | Looking for a way to restrict product access in WooCommerce? Don't want to set up a full-fledged [memberships](https://woocommerce.com/products/woocommerce-memberships/) site?
19 |
20 | This tiny plugin allows you to restrict access to any WooCommerce product, depending on the ownership or purchase of other, required products.
21 |
22 | Features:
23 |
24 | * **Conditional product access** based on the ownership and/or purchase of other required products.
25 | * Support for "ownership", "purchase" and "ownership/purchase" dependency types.
26 |
27 | Developers can checkout and contribute to the source code on the plugin's [GitHub Repository](https://github.com/woocommerce/woocommerce-product-dependencies/).
28 |
29 | **Important**: Requires WooCommerce 2.2+. WooCommerce 3.0+ or higher recommended.
30 |
31 | Like this plugin? You'll love our official WooCommerce Extensions:
32 |
33 | * [WooCommerce Product Bundles](https://woocommerce.com/products/product-bundles/)
34 | * [WooCommerce Composite Products](https://woocommerce.com/products/composite-products/)
35 | * [WooCommerce Conditional Shipping and Payments](https://woocommerce.com/products/conditional-shipping-and-payments/)
36 | * [WooCommerce Product Recommendations](https://woocommerce.com/products/product-recommendations/)
37 | * [All Products for WooCommerce Subscriptions](https://woocommerce.com/products/all-products-for-woocommerce-subscriptions/)
38 |
39 |
40 | == Installation ==
41 |
42 | 1. Download the plugin.
43 | 2. Go to your WordPress Dashboard and then click **Plugins > Add New**.
44 | 3. Click **Upload Plugin** at the top.
45 | 4. Click **Choose File** and select the .zip file you downloaded in **Step 1**.
46 | 5. Click **Install Now** and **Activate** the plugin.
47 |
48 |
49 | == Documentation ==
50 |
51 | Dependencies are evaluated when customers attempt to add a product to their cart. If validation fails, the product cannot be added to the cart and a notice is displayed. In order to evaluate "Ownership"-type dependencies, customers are prompted to log in.
52 |
53 | = Creating Dependencies =
54 |
55 | To add dependencies to a product:
56 |
57 | * Go to the **Product Data > Dependencies** tab.
58 | * Use the **Product Dependencies** field to search for and add some products and/or variations.
59 | * Choose a **Dependency Type**.
60 | * **Update** to save your changes.
61 |
62 | The "Ownership" dependency type is evaluated by checking if the customer has purchased a required product in a previous order. The "Purchase" dependency type requires the customer to have a required product in the cart in order to purchase the dependent one.
63 |
64 | = Ownership vs Purchase =
65 |
66 | The plugin allows you to select between 3 different dependency types:
67 |
68 | * **Ownership**: Access is granted only to customers that already own any of the products added to the Product Dependencies field.
69 | * **Purchase**: The product can be purchased only in combination with any of the items added to the Product Dependencies field. Ownership is not taken into account.
70 | * **Either**: Access is granted with ownership or purchase of any item added to the Product Dependencies field.
71 |
72 |
73 | == Screenshots ==
74 |
75 | 1. Product dependencies can be created from the **Dependencies** tab, found under **Product Data**, and adding products/variations to the **Product Dependencies** field.
76 | 2. If the ownership and/or purchase conditions are not met, products with dependencies cannot be added to the cart and a notification is displayed.
77 |
78 |
79 | == Changelog ==
80 |
81 | = 2.0.0 =
82 | * Tweak - Updated author links.
83 |
84 | = 2.0.0 =
85 | * Important - New: PHP 7.4+ is now required.
86 | * Important - New: WooCommerce 8.2+ is now required.
87 | * Important - New: WordPress 6.2+ is now required.
88 |
89 | = 1.2.8 =
90 | * Feature - Declared compatibility with the new High-Performance Order Tables.
91 |
92 | = 1.2.7 =
93 | * Fix - Prevent products from satisfying their own dependencies.
94 |
95 | = 1.2.6 =
96 | * Tweak - Declared support for WooCommerce 5.0.
97 |
98 | = 1.2.5 =
99 | * Tweak - Declared support for WooCommerce 4.2.
100 |
101 | = 1.2.4 =
102 | * Tweak - Declared support for WC 4.1 and WP 5.4.
103 |
104 | = 1.2.3 =
105 | * Tweak - Updated plugin headers to declare support for WC 3.9 and WP 5.3.
106 |
107 | = 1.2.2 =
108 | * Fix - Remove esc_html when rendering custom notices.
109 |
110 | = 1.2.1 =
111 | * Fix - Products with "Purchase"-type category dependencies cannot be added to the cart although a variation of a product that belongs to the required category has been added to the cart.
112 |
113 | = 1.2.0 =
114 | * Feature - Introduced category-based dependencies.
115 | * Feature - Added custom dependency notices.
116 | * Feature - Added AND/OR dependency relationship. Can be activated for specific products using the 'wc_pd_dependency_relationship' filter.
117 | * Tweak - Tweaked default notices.
118 |
119 | = 1.1.3 =
120 | * Tweak - Updated description.
121 | * Tweak - Added WooCommerce version headers.
122 |
123 | = 1.1.2 =
124 | * Fix - Variable product dependencies not validated correctly in the cart.
125 |
126 | = 1.1.1 =
127 | * Fix - Dependencies not working under WC < 3.0 after last update. Fixed!
128 |
129 | = 1.1.0 =
130 | * Refactored and cleaned up plugin.
131 | * Fix - Added support for WooCommerce 3.0.
132 | * Tweak - Add links to dependent products in notices.
133 |
134 | = 1.0.7 =
135 | * Fix - Stray "or" in dependent products list when only one dependency is present.
136 | * Localization - Added Brazilian Portuguese translation.
137 |
138 | = 1.0.6 =
139 | * Fix - PHP array_values warning.
140 |
141 | = 1.0.5 =
142 | * Fix - WC 2.3 support.
143 |
144 | = 1.0.4 =
145 | * Localization - Added Brazilian translation (robertopc)
146 |
147 | = 1.0.3 =
148 | * Fix - Saving bug
149 |
150 | = 1.0.2 =
151 | * Fix - WC detection fix
152 |
153 | = 1.0.1 =
154 | * Tweak - Styling support for WooCommerce v2 write-panels
155 |
156 | = 1.0 =
157 | * Initial release
158 |
159 |
160 | == Upgrade Notice ==
161 |
162 | = 1.2.7 =
163 | Prevent products from satisfying their own dependencies.
164 |
--------------------------------------------------------------------------------
/languages/woocommerce-product-dependencies.pot:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2024 WooCommerce
2 | # This file is distributed under the GNU General Public License v3.0.
3 | msgid ""
4 | msgstr ""
5 | "Project-Id-Version: WooCommerce Product Dependencies 2.0.1\n"
6 | "Report-Msgid-Bugs-To: "
7 | "https://wordpress.org/support/plugin/woocommerce-product-dependencies\n"
8 | "POT-Creation-Date: 2024-09-19 06:41:32+00:00\n"
9 | "MIME-Version: 1.0\n"
10 | "Content-Type: text/plain; charset=utf-8\n"
11 | "Content-Transfer-Encoding: 8bit\n"
12 | "PO-Revision-Date: 2024-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "X-Generator: grunt-wp-i18n 0.5.4\n"
16 |
17 | #: class-wc-pd-helpers.php:36
18 | msgid "%s"
19 | msgstr ""
20 |
21 | #: class-wc-pd-helpers.php:38
22 | msgid " and %s"
23 | msgstr ""
24 |
25 | #: class-wc-pd-helpers.php:38
26 | msgid " or %s"
27 | msgstr ""
28 |
29 | #: class-wc-pd-helpers.php:40
30 | msgid ", %s"
31 | msgstr ""
32 |
33 | #: woocommerce-product-dependencies.php:81
34 | #: woocommerce-product-dependencies.php:90
35 | msgid "Foul!"
36 | msgstr ""
37 |
38 | #: woocommerce-product-dependencies.php:423
39 | msgid "all required products"
40 | msgstr ""
41 |
42 | #: woocommerce-product-dependencies.php:424
43 | msgid "these products"
44 | msgstr ""
45 |
46 | #: woocommerce-product-dependencies.php:426
47 | msgid "a required product"
48 | msgstr ""
49 |
50 | #: woocommerce-product-dependencies.php:438
51 | msgid "one or more products from the %s categories"
52 | msgstr ""
53 |
54 | #: woocommerce-product-dependencies.php:439
55 | msgid "one or more products from all required categories"
56 | msgstr ""
57 |
58 | #: woocommerce-product-dependencies.php:441
59 | #: woocommerce-product-dependencies.php:445
60 | msgid "a product from the %s category"
61 | msgstr ""
62 |
63 | #: woocommerce-product-dependencies.php:442
64 | msgid "a qualifying product"
65 | msgstr ""
66 |
67 | #: woocommerce-product-dependencies.php:453
68 | msgid ""
69 | "Access to "%1$s" is restricted to customers who have previously "
70 | "purchased %2$s."
71 | msgstr ""
72 |
73 | #: woocommerce-product-dependencies.php:455
74 | msgid ""
75 | "Access to "%1$s" is restricted to customers who have previously "
76 | "purchased %2$s. Please log in to validate ownership "
77 | "and try again."
78 | msgstr ""
79 |
80 | #: woocommerce-product-dependencies.php:474
81 | msgid "a product"
82 | msgid_plural "some products"
83 | msgstr[0] ""
84 | msgstr[1] ""
85 |
86 | #: woocommerce-product-dependencies.php:475
87 | msgid "%1$s from the %2$s category"
88 | msgid_plural "%1$s from the %2$s categories"
89 | msgstr[0] ""
90 | msgstr[1] ""
91 |
92 | #: woocommerce-product-dependencies.php:478
93 | msgid "one or more products from the %s category"
94 | msgid_plural "one or more products from the %s categories"
95 | msgstr[0] ""
96 | msgstr[1] ""
97 |
98 | #: woocommerce-product-dependencies.php:481
99 | msgid ""
100 | ""%1$s" requires purchasing %2$s. Please add %3$s to your cart and "
101 | "try again (you have already purchased %4$s)."
102 | msgstr ""
103 |
104 | #: woocommerce-product-dependencies.php:487
105 | msgid ""
106 | ""%1$s" requires purchasing %2$s. To get access to this product "
107 | "now, please add %3$s to your cart."
108 | msgstr ""
109 |
110 | #: woocommerce-product-dependencies.php:494
111 | msgid ""
112 | ""%1$s" requires purchasing %2$s. If you have previously purchased "
113 | "%3$s, please log in to verify ownership and try again. "
114 | "Alternatively, get access to "%1$s" now by adding %4$s to your "
115 | "cart."
116 | msgstr ""
117 |
118 | #: woocommerce-product-dependencies.php:501
119 | msgid ""
120 | ""%1$s" is only available in combination with %2$s. To purchase "
121 | "this product, please add %3$s to your cart."
122 | msgstr ""
123 |
124 | #: woocommerce-product-dependencies.php:697
125 | #: woocommerce-product-dependencies.php:709
126 | msgid "Dependencies"
127 | msgstr ""
128 |
129 | #: woocommerce-product-dependencies.php:762
130 | #: woocommerce-product-dependencies.php:772
131 | msgid "Product dependencies"
132 | msgstr ""
133 |
134 | #: woocommerce-product-dependencies.php:764
135 | msgid "Select products"
136 | msgstr ""
137 |
138 | #: woocommerce-product-dependencies.php:765
139 | msgid "Select categories"
140 | msgstr ""
141 |
142 | #: woocommerce-product-dependencies.php:779
143 | msgid "Search for products and variations…"
144 | msgstr ""
145 |
146 | #: woocommerce-product-dependencies.php:791
147 | msgid ""
148 | "Restrict product access based on the ownership or purchase of "
149 | "any product or variation added to this list."
150 | msgstr ""
151 |
152 | #: woocommerce-product-dependencies.php:799
153 | msgid "Select product categories…"
154 | msgstr ""
155 |
156 | #: woocommerce-product-dependencies.php:814
157 | msgid "Dependency type"
158 | msgstr ""
159 |
160 | #: woocommerce-product-dependencies.php:817
161 | msgid "Ownership"
162 | msgstr ""
163 |
164 | #: woocommerce-product-dependencies.php:818
165 | msgid "Purchase"
166 | msgstr ""
167 |
168 | #: woocommerce-product-dependencies.php:819
169 | msgid "Either"
170 | msgstr ""
171 |
172 | #: woocommerce-product-dependencies.php:827
173 | msgid "Custom notice"
174 | msgstr ""
175 |
176 | #: woocommerce-product-dependencies.php:828
177 | msgid "Notice to display instead of the default one."
178 | msgstr ""
179 |
180 | #. Plugin Name of the plugin/theme
181 | msgid "WooCommerce Product Dependencies"
182 | msgstr ""
183 |
184 | #. Author URI of the plugin/theme
185 | msgid "https://woocommerce.com/"
186 | msgstr ""
187 |
188 | #. Description of the plugin/theme
189 | msgid ""
190 | "Restrict access to WooCommerce products, depending on the ownership and/or "
191 | "purchase of other, required products."
192 | msgstr ""
193 |
194 | #. Author of the plugin/theme
195 | msgid "WooCommerce"
196 | msgstr ""
197 |
198 | #: class-wc-pd-helpers.php:166
199 | msgctxt "product title followed by meta and sku in parenthesis"
200 | msgid "%1$s – %2$s (%3$s)"
201 | msgstr ""
202 |
203 | #: class-wc-pd-helpers.php:168
204 | msgctxt "sku followed by product title and meta"
205 | msgid "%1$s – %2$s – %3$s"
206 | msgstr ""
207 |
208 | #: class-wc-pd-helpers.php:172
209 | msgctxt "product title followed by sku in parenthesis"
210 | msgid "%1$s (%2$s)"
211 | msgstr ""
212 |
213 | #: class-wc-pd-helpers.php:174
214 | msgctxt "sku followed by product title"
215 | msgid "%1$s – %2$s"
216 | msgstr ""
217 |
218 | #: class-wc-pd-helpers.php:178
219 | msgctxt "product title followed by meta in parenthesis"
220 | msgid "%1$s (%2$s)"
221 | msgstr ""
222 |
223 | #: class-wc-pd-helpers.php:180
224 | msgctxt "product title followed by meta"
225 | msgid "%1$s – %2$s"
226 | msgstr ""
--------------------------------------------------------------------------------
/woocommerce-product-dependencies.php:
--------------------------------------------------------------------------------
1 | plugin_url() . '/assets/js/wc-pd-writepanels' . $suffix . '.js', array(), $this->version );
185 |
186 | $screen = get_current_screen();
187 | $screen_id = $screen ? $screen->id : '';
188 |
189 | if ( in_array( $screen_id, array( 'product' ) ) ) {
190 | wp_enqueue_script( 'wc-pd-writepanels' );
191 | }
192 |
193 | }
194 |
195 | /**
196 | * Validates a product when adding to cart.
197 | *
198 | * @param boolean $add
199 | * @param int $item_id
200 | * @param int $quantity
201 | * @return boolean
202 | */
203 | public function add_to_cart_validation( $add, $item_id, $quantity ) {
204 | return $add && $this->evaluate_dependencies( $item_id );
205 | }
206 |
207 | /**
208 | * Validates cart contents.
209 | */
210 | public function check_cart_items() {
211 |
212 | $cart_items = WC()->cart->cart_contents;
213 |
214 | foreach ( $cart_items as $cart_item ) {
215 | $product = $cart_item[ 'data' ];
216 | $this->evaluate_dependencies( $product );
217 | }
218 | }
219 |
220 | /**
221 | * Check conditions.
222 | *
223 | * @param mixed $item
224 | * @return boolean
225 | */
226 | public function evaluate_dependencies( $item ) {
227 |
228 | if ( is_a( $item, 'WC_Product' ) ) {
229 |
230 | if ( $item->is_type( 'variation' ) ) {
231 | $product_id = $item->get_parent_id();
232 | $product = wc_get_product( $product_id );
233 | } else {
234 | $product_id = $item->get_id();
235 | $product = $item;
236 | }
237 |
238 | } else {
239 | $product_id = absint( $item );
240 | $product = wc_get_product( $product_id );
241 | }
242 |
243 | if ( ! $product ) {
244 | return;
245 | }
246 |
247 | $tied_product_ids = $this->get_tied_product_ids( $product );
248 | $tied_category_ids = $this->get_tied_category_ids( $product );
249 | $dependency_selection_type = $this->get_dependency_selection_type( $product );
250 | $dependency_notice = $this->get_dependency_notice( $product );
251 |
252 | $product_title = $product->get_title();
253 | $tied_products = array();
254 | $dependencies_exist = false;
255 |
256 | // Ensure dependencies exist.
257 | if ( 'product_ids' === $dependency_selection_type ) {
258 |
259 | if ( ! empty( $tied_product_ids ) ) {
260 | foreach ( $tied_product_ids as $id ) {
261 |
262 | $tied_product = wc_get_product( $id );
263 |
264 | if ( $tied_product ) {
265 | $tied_products[ $id ] = $tied_product;
266 | $dependencies_exist = true;
267 | }
268 | }
269 | }
270 |
271 | } else {
272 |
273 | if ( ! empty( $tied_category_ids ) ) {
274 |
275 | $product_categories = (array) get_terms( 'product_cat', array( 'get' => 'all' ) );
276 | $product_category_ids = wp_list_pluck( $product_categories, 'term_id' );
277 | $tied_category_ids = array_intersect( $product_category_ids, $tied_category_ids );
278 | $dependencies_exist = sizeof( $tied_category_ids ) > 0;
279 | }
280 | }
281 |
282 | if ( $dependencies_exist ) {
283 |
284 | $purchase_dependency_result = false;
285 | $ownership_dependency_result = false;
286 |
287 | $purchased_product_ids = array();
288 | $purchased_cat_ids = array();
289 |
290 | $dependency_type = $this->get_dependency_type( $product );
291 | $dependency_relationship = $this->get_dependency_relationship( $product );
292 |
293 | $tied_product_ids = array_keys( $tied_products );
294 | $has_multiple = 'product_ids' === $dependency_selection_type ? sizeof( $tied_products ) > 1 : sizeof( $tied_category_ids ) > 1;
295 | $tied_ids = 'product_ids' === $dependency_selection_type ? $tied_product_ids : $tied_category_ids;
296 | $owned_ids = array();
297 |
298 | // Check cart.
299 | if ( in_array( $dependency_type, array( self::DEPENDENCY_TYPE_PURCHASE, self::DEPENDENCY_TYPE_EITHER ) ) ) {
300 |
301 | $cart_contents = WC()->cart->cart_contents;
302 | $item_id = $product_id;
303 |
304 | foreach ( $cart_contents as $cart_item ) {
305 |
306 | $product_id = $cart_item[ 'product_id' ];
307 | $variation_id = $cart_item[ 'variation_id' ];
308 |
309 | if ( $product_id === $item_id || $variation_id === $item_id ) {
310 | continue;
311 | }
312 |
313 | if ( 'product_ids' === $dependency_selection_type ) {
314 |
315 | if ( in_array( $product_id, $tied_product_ids ) || in_array( $variation_id, $tied_product_ids ) ) {
316 |
317 | if ( 'or' === $dependency_relationship ) {
318 | $purchase_dependency_result = true;
319 | break;
320 | } else {
321 | $purchased_product_ids = array_unique( array_merge( $purchased_product_ids, array_filter( array( $product_id, $variation_id ) ) ) );
322 | }
323 | }
324 |
325 | } else {
326 |
327 | $cart_item_product = $cart_item[ 'data' ]->is_type( 'variation' ) ? wc_get_product( $cart_item[ 'data' ]->get_parent_id() ) : $cart_item[ 'data' ];
328 | $cart_item_cat_ids = $cart_item_product->get_category_ids();
329 |
330 | $matching_cat_ids = array_intersect( $cart_item_cat_ids, $tied_category_ids );
331 |
332 | if ( sizeof( $matching_cat_ids ) ) {
333 |
334 | if ( 'or' === $dependency_relationship ) {
335 | $purchase_dependency_result = true;
336 | break;
337 | } else {
338 | $purchased_cat_ids = array_unique( array_merge( $purchased_cat_ids, array_filter( $matching_cat_ids ) ) );
339 | $purchased_product_ids = array_unique( array_merge( $purchased_product_ids, array_filter( array( $product_id, $variation_id ) ) ) );
340 | }
341 | }
342 | }
343 | }
344 |
345 | $purchased_ids = 'product_ids' === $dependency_selection_type ? $purchased_product_ids : $purchased_cat_ids;
346 |
347 | if ( 'and' === $dependency_relationship ) {
348 | if ( sizeof( $purchased_ids ) >= sizeof( $tied_ids ) ) {
349 | $purchase_dependency_result = true;
350 | }
351 | }
352 | }
353 |
354 | // Check ownership.
355 | if ( in_array( $dependency_type, array( self::DEPENDENCY_TYPE_OWNERSHIP, self::DEPENDENCY_TYPE_EITHER ) ) ) {
356 |
357 | if ( is_user_logged_in() ) {
358 |
359 | $current_user = wp_get_current_user();
360 |
361 | if ( 'category_ids' === $dependency_selection_type ) {
362 | $tied_product_ids = $this->get_product_ids_in_categories( $tied_category_ids );
363 | }
364 |
365 | if ( $dependency_type === self::DEPENDENCY_TYPE_EITHER && $purchase_dependency_result ) {
366 |
367 | $ownership_dependency_result = true;
368 |
369 | } else {
370 |
371 | $owned_product_ids = $this->customer_bought_products( $current_user->user_email, $current_user->ID, $tied_product_ids );
372 |
373 | // Find all categories that these products belong to and then compare against the set of required categories.
374 | if ( 'and' === $dependency_relationship && $has_multiple ) {
375 |
376 | if ( $dependency_type === self::DEPENDENCY_TYPE_EITHER ) {
377 | $owned_product_ids = array_unique( array_merge( $owned_product_ids, $purchased_product_ids ) );
378 | }
379 |
380 | if ( 'product_ids' === $dependency_selection_type ) {
381 | $owned_ids = $owned_product_ids;
382 | } else {
383 | $owned_ids = array_unique( wp_get_object_terms( $owned_product_ids, 'product_cat', array( 'fields' => 'ids' ) ) );
384 | }
385 |
386 | $owned_ids = array_intersect( $owned_ids, $tied_ids );
387 |
388 | $ownership_dependency_result = sizeof( $owned_ids ) >= sizeof( $tied_ids );
389 |
390 | if ( $ownership_dependency_result ) {
391 | $purchase_dependency_result = true;
392 | }
393 |
394 | } else {
395 | $ownership_dependency_result = sizeof( $owned_product_ids );
396 | }
397 | }
398 | }
399 | }
400 |
401 | $result = $ownership_dependency_result || $purchase_dependency_result;
402 |
403 | // Show notice.
404 | if ( false === $result ) {
405 |
406 | if ( ! WC()->session->has_session() ) {
407 | // Generate a random customer ID.
408 | WC()->session->set_customer_session_cookie( true );
409 | }
410 |
411 | if ( $dependency_notice ) {
412 |
413 | wc_add_notice( $dependency_notice, 'error' );
414 |
415 | } else {
416 |
417 | if ( 'product_ids' === $dependency_selection_type ) {
418 |
419 | $required_msg = WC_PD_Helpers::merge_product_titles( $tied_products, $dependency_relationship );
420 |
421 | if ( $has_multiple ) {
422 | if ( 'and' === $dependency_relationship ) {
423 | $action_msg = __( 'all required products', 'woocommerce-product-dependencies' );
424 | $action_msg_2 = __( 'these products', 'woocommerce-product-dependencies' );
425 | } else {
426 | $action_msg = __( 'a required product', 'woocommerce-product-dependencies' );
427 | }
428 | } else {
429 | $action_msg = $required_msg;
430 | }
431 |
432 | } else {
433 |
434 | $merged_category_titles = WC_PD_Helpers::merge_category_titles( $tied_category_ids, $dependency_relationship );
435 |
436 | if ( $has_multiple ) {
437 | if ( 'and' === $dependency_relationship ) {
438 | $required_msg = sprintf( __( 'one or more products from the %s categories', 'woocommerce-product-dependencies' ), $merged_category_titles );
439 | $action_msg = __( 'one or more products from all required categories', 'woocommerce-product-dependencies' );
440 | } else {
441 | $required_msg = sprintf( __( 'a product from the %s category', 'woocommerce-product-dependencies' ), $merged_category_titles );
442 | $action_msg = __( 'a qualifying product', 'woocommerce-product-dependencies' );
443 | }
444 | } else {
445 | $required_msg = sprintf( __( 'a product from the %s category', 'woocommerce-product-dependencies' ), $merged_category_titles );
446 | $action_msg = $required_msg;
447 | }
448 | }
449 |
450 | if ( $dependency_type === self::DEPENDENCY_TYPE_OWNERSHIP ) {
451 |
452 | if ( is_user_logged_in() ) {
453 | $msg = __( 'Access to "%1$s" is restricted to customers who have previously purchased %2$s.', 'woocommerce-product-dependencies' );
454 | } else {
455 | $msg = __( 'Access to "%1$s" is restricted to customers who have previously purchased %2$s. Please log in to validate ownership and try again.', 'woocommerce-product-dependencies' );
456 | }
457 |
458 | wc_add_notice( sprintf( $msg, $product_title, $required_msg, wp_login_url() ), 'error' );
459 |
460 | } elseif ( $dependency_type === self::DEPENDENCY_TYPE_EITHER ) {
461 |
462 | if ( is_user_logged_in() ) {
463 |
464 | if ( 'and' === $dependency_relationship && $has_multiple && sizeof( $owned_ids ) ) {
465 |
466 | if ( 'product_ids' === $dependency_selection_type ) {
467 |
468 | $owned_msg = WC_PD_Helpers::merge_product_titles( array_intersect_key( $tied_products, array_flip( $owned_product_ids ) ), 'and' );
469 | $action_msg = WC_PD_Helpers::merge_product_titles( array_intersect_key( $tied_products, array_flip( array_diff( $tied_ids, $owned_product_ids ) ) ), 'and' );
470 |
471 | } else {
472 |
473 | $owned_category_titles = WC_PD_Helpers::merge_category_titles( $owned_ids, 'and' );
474 | $owned_products_msg = _n( 'a product', 'some products', sizeof( $owned_product_ids ), 'woocommerce-product-dependencies' );
475 | $owned_msg = sprintf( _n( '%1$s from the %2$s category', '%1$s from the %2$s categories', sizeof( $owned_category_titles ), 'woocommerce-product-dependencies' ), $owned_products_msg, $owned_category_titles );
476 |
477 | $action_category_titles = WC_PD_Helpers::merge_category_titles( array_diff( $tied_ids, $owned_ids ), 'and' );
478 | $action_msg = sprintf( _n( 'one or more products from the %s category', 'one or more products from the %s categories', sizeof( $action_category_titles ), 'woocommerce-product-dependencies' ), $action_category_titles );
479 | }
480 |
481 | $msg = __( '"%1$s" requires purchasing %2$s. Please add %3$s to your cart and try again (you have already purchased %4$s).', 'woocommerce-product-dependencies' );
482 |
483 | wc_add_notice( sprintf( $msg, $product_title, $required_msg, $action_msg, $owned_msg ), 'error' );
484 |
485 | } else {
486 |
487 | $msg = __( '"%1$s" requires purchasing %2$s. To get access to this product now, please add %3$s to your cart.', 'woocommerce-product-dependencies' );
488 |
489 | wc_add_notice( sprintf( $msg, $product_title, $required_msg, $action_msg ), 'error' );
490 | }
491 |
492 | } else {
493 |
494 | $msg = __( '"%1$s" requires purchasing %2$s. If you have previously purchased %3$s, please log in to verify ownership and try again. Alternatively, get access to "%1$s" now by adding %4$s to your cart.', 'woocommerce-product-dependencies' );
495 |
496 | wc_add_notice( sprintf( $msg, $product_title, $required_msg, isset( $action_msg_2 ) ? $action_msg_2 : $action_msg, $action_msg, wp_login_url() ), 'error' );
497 | }
498 |
499 | } else {
500 |
501 | $msg = __( '"%1$s" is only available in combination with %2$s. To purchase this product, please add %3$s to your cart.', 'woocommerce-product-dependencies' );
502 |
503 | wc_add_notice( sprintf( $msg, $product_title, $required_msg, $action_msg ), 'error' );
504 | }
505 | }
506 | }
507 |
508 | return $result;
509 | }
510 |
511 | return true;
512 | }
513 |
514 | /**
515 | * Dependency relationship:
516 | * - 'or': Ownership/purchase of any product required.
517 | * - 'and': Ownership/purhase of all products required.
518 | *
519 | * @param WC_Product $product
520 | * @return string
521 | */
522 | public function get_dependency_relationship( $product ) {
523 | return apply_filters( 'wc_pd_dependency_relationship', 'or', $product );
524 | }
525 |
526 | /**
527 | * Returns an array with all dependent product ids.
528 | *
529 | * @since 1.2.0
530 | *
531 | * @param WC_Product $product
532 | * @return array $dependent_ids
533 | */
534 | public function get_tied_product_ids( $product ) {
535 | $dependent_ids = $product->get_meta( '_tied_products', true );
536 | return empty( $dependent_ids ) ? array() : array_unique( $dependent_ids );
537 | }
538 |
539 | /**
540 | * Returns an array with all saved category ids.
541 | *
542 | * @since 1.2.0
543 | *
544 | * @param WC_Product $product
545 | * @return array $category_ids
546 | */
547 | public function get_tied_category_ids( $product ) {
548 | $category_ids = $product->get_meta( '_tied_categories', true );
549 | return empty( $category_ids ) ? array() : array_unique( $category_ids );
550 | }
551 |
552 | /**
553 | * Returns the product dependency selection type.
554 | *
555 | * @since 1.2.0
556 | *
557 | * @param WC_Product $product
558 | * @return string $selection_type
559 | */
560 | public function get_dependency_selection_type( $product ) {
561 | $selection_type = $product->get_meta( '_dependency_selection_type', true );
562 | $selection_type = in_array( $selection_type, array( 'product_ids', 'category_ids' ) ) ? $selection_type : 'product_ids';
563 |
564 | return $selection_type;
565 | }
566 |
567 | /**
568 | * Returns the custom dependency notice.
569 | *
570 | * @since 1.2.0
571 | *
572 | * @param WC_Product $product
573 | * @return string $notice
574 | */
575 | public function get_dependency_notice( $product ) {
576 | $notice = $product->get_meta( '_dependency_notice', true );
577 | return $notice;
578 | }
579 |
580 | /**
581 | * Returns the product dependency type.
582 | *
583 | * @since 1.2.0
584 | *
585 | * @param WC_Product $product
586 | * @return string $type
587 | */
588 | public function get_dependency_type( $product ) {
589 | $type = absint( $product->get_meta( '_dependency_type', true ) );
590 | $type = in_array( $type, array( self::DEPENDENCY_TYPE_OWNERSHIP, self::DEPENDENCY_TYPE_PURCHASE, self::DEPENDENCY_TYPE_EITHER ) ) ? $type : self::DEPENDENCY_TYPE_EITHER;
591 |
592 | return $type;
593 | }
594 |
595 | /**
596 | * Get all product IDs that belong to the specified categories.
597 | *
598 | * @param array $category_ids
599 | * @return array
600 | */
601 | private function get_product_ids_in_categories( $category_ids ) {
602 |
603 | $query_results = new WP_Query( array(
604 | 'post_type' => array( 'product', 'product_variation' ),
605 | 'fields' => 'ids',
606 | 'tax_query' => array(
607 | array(
608 | 'taxonomy' => 'product_cat',
609 | 'field' => 'term_id',
610 | 'terms' => $category_ids,
611 | 'operator' => 'IN',
612 | )
613 | )
614 | ) );
615 |
616 | return $query_results->posts;
617 | }
618 |
619 | /**
620 | * Re-implementation of 'wc_customer_bought_product' with support for array input.
621 | *
622 | * @since 1.2.0
623 | *
624 | * @param string $customer_email
625 | * @param int $user_id
626 | * @param array $product_ids
627 | * @return array
628 | */
629 | private function customer_bought_products( $customer_email, $user_id, $product_ids ) {
630 |
631 | global $wpdb;
632 |
633 | $results = apply_filters( 'wc_pd_pre_customer_bought_products', null, $customer_email, $user_id, $product_ids );
634 |
635 | if ( null !== $results ) {
636 | return $results;
637 | }
638 |
639 | $transient_name = 'wc_cbp_' . md5( $customer_email . $user_id . WC_Cache_Helper::get_transient_version( 'orders' ) );
640 |
641 | if ( false === ( $results = get_transient( $transient_name ) ) ) {
642 |
643 | $customer_data = array( $user_id );
644 |
645 | if ( $user_id ) {
646 |
647 | $user = get_user_by( 'id', $user_id );
648 |
649 | if ( isset( $user->user_email ) ) {
650 | $customer_data[] = $user->user_email;
651 | }
652 | }
653 |
654 | if ( is_email( $customer_email ) ) {
655 | $customer_data[] = $customer_email;
656 | }
657 |
658 | $customer_data = array_map( 'esc_sql', array_filter( array_unique( $customer_data ) ) );
659 | $statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
660 |
661 | if ( sizeof( $customer_data ) == 0 ) {
662 | return false;
663 | }
664 |
665 | $results = $wpdb->get_col( "
666 | SELECT im.meta_value FROM {$wpdb->posts} AS p
667 | INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
668 | INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id
669 | INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id
670 | WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
671 | AND pm.meta_key IN ( '_billing_email', '_customer_user' )
672 | AND im.meta_key IN ( '_product_id', '_variation_id' )
673 | AND im.meta_value != 0
674 | AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' )
675 | " );
676 |
677 | $results = array_map( 'absint', $results );
678 |
679 | set_transient( $transient_name, $results, DAY_IN_SECONDS * 30 );
680 | }
681 |
682 | return array_intersect( $results, $product_ids );
683 | }
684 |
685 | /*
686 | |--------------------------------------------------------------------------
687 | | Admin Filters.
688 | |--------------------------------------------------------------------------
689 | */
690 |
691 | /**
692 | * Add Product Data tab.
693 | *
694 | * @return void
695 | */
696 | public function dependencies_product_data_panel_tab() {
697 | echo '' . __( 'Dependencies', 'woocommerce-product-dependencies' ) . '';
698 | }
699 |
700 | /**
701 | * Add the "Product Dependencies" panel tab.
702 | *
703 | * @param array $tabs
704 | * @return array
705 | */
706 | public function dependencies_product_data_tab( $tabs ) {
707 |
708 | $tabs[ 'dependencies' ] = array(
709 | 'label' => __( 'Dependencies', 'woocommerce-product-dependencies' ),
710 | 'target' => 'tied_products_data',
711 | 'class' => array( 'show_if_simple', 'show_if_variable', 'show_if_bundle', 'show_if_composite', 'linked_product_options', 'show_if_booking', 'show_if_phive_booking' )
712 | );
713 |
714 | return $tabs;
715 | }
716 |
717 | /**
718 | * Add Product Data tab section.
719 | *
720 | * @return void
721 | */
722 | public function dependencies_product_data_panel() {
723 |
724 | global $post, $product_object;
725 |
726 | if ( empty( $product_object ) || ! is_a( $product_object, 'WC_Product' ) ) {
727 | $product_object = wc_get_product( $post->ID );
728 | }
729 |
730 | if ( ! $product_object ) {
731 | return;
732 | }
733 |
734 | $tied_products = $this->get_tied_product_ids( $product_object );
735 | $tied_categories = $this->get_tied_category_ids( $product_object );
736 | $dependency_type = $this->get_dependency_type( $product_object );
737 | $selection_type = $this->get_dependency_selection_type( $product_object );
738 | $dependency_notice = $this->get_dependency_notice( $product_object );
739 |
740 | $product_id_options = array();
741 | $product_categories = (array) get_terms( 'product_cat', array( 'get' => 'all' ) );
742 | $selection_type = in_array( $selection_type, array( 'product_ids', 'category_ids' ) ) ? $selection_type : 'product_ids';
743 |
744 | if ( $tied_products ) {
745 | foreach ( $tied_products as $item_id ) {
746 |
747 | $title = WC_PD_Helpers::get_product_title( $item_id );
748 |
749 | if ( $title ) {
750 | $product_id_options[ $item_id ] = $title;
751 | }
752 | }
753 | }
754 |
755 | ?>
756 |
833 | = 2.7.
838 | *
839 | * @param WC_Product $product
840 | * @return void
841 | */
842 | public function process_product_data( $product ) {
843 |
844 | if ( ! empty( $_POST[ 'tied_categories' ] ) && is_array( $_POST[ 'tied_categories' ] ) ) {
845 |
846 | $tied_categories = array_map( 'intval', $_POST[ 'tied_categories' ] );
847 |
848 | $product->update_meta_data( '_tied_categories', $tied_categories );
849 |
850 | } else {
851 |
852 | $product->delete_meta_data( '_tied_categories' );
853 | }
854 |
855 | if ( ! isset( $_POST[ 'tied_products' ] ) || empty( $_POST[ 'tied_products' ] ) ) {
856 |
857 | $product->delete_meta_data( '_tied_products' );
858 |
859 | } elseif ( isset( $_POST[ 'tied_products' ] ) && ! empty( $_POST[ 'tied_products' ] ) ) {
860 |
861 | $tied_ids = $_POST[ 'tied_products' ];
862 |
863 | if ( is_array( $tied_ids ) ) {
864 | $tied_ids = array_map( 'intval', $tied_ids );
865 | } else {
866 | $tied_ids = array_filter( array_map( 'intval', explode( ',', $tied_ids ) ) );
867 | }
868 |
869 | $product->update_meta_data( '_tied_products', $tied_ids );
870 | }
871 |
872 | if ( ! empty( $_POST[ 'dependency_type' ] ) ) {
873 | $product->update_meta_data( '_dependency_type', stripslashes( $_POST[ 'dependency_type' ] ) );
874 | }
875 |
876 | if ( ! empty( $_POST[ 'product_dependencies_dropdown' ] ) ) {
877 | $product->update_meta_data( '_dependency_selection_type', stripslashes( $_POST[ 'product_dependencies_dropdown' ] ) );
878 | }
879 |
880 | if ( ! empty( $_POST[ 'dependency_notice' ] ) ) {
881 | $product->update_meta_data( '_dependency_notice', wp_kses_post( stripslashes( $_POST[ 'dependency_notice' ] ) ) );
882 | } else {
883 | $product->delete_meta_data( '_dependency_notice' );
884 | }
885 | }
886 |
887 | /**
888 | * Save dependencies meta. WC <= 2.6.
889 | *
890 | * @param int $post_id
891 | * @param WC_Post $post
892 | * @return void
893 | */
894 | public function process_meta( $post_id, $post ) {
895 |
896 | global $post;
897 |
898 | if ( ! empty( $_POST[ 'tied_categories' ] ) && is_array( $_POST[ 'tied_categories' ] ) ) {
899 |
900 | $tied_categories = array_map( 'intval', $_POST[ 'tied_categories' ] );
901 |
902 | update_post_meta( $post_id, '_tied_categories', $tied_categories );
903 |
904 | } else {
905 |
906 | delete_post_meta( $post_id, '_tied_categories' );
907 | }
908 |
909 | if ( ! isset( $_POST[ 'tied_products' ] ) || empty( $_POST[ 'tied_products' ] ) ) {
910 |
911 | delete_post_meta( $post_id, '_tied_products' );
912 |
913 | } elseif ( isset( $_POST[ 'tied_products' ] ) && ! empty( $_POST[ 'tied_products' ] ) ) {
914 |
915 | $tied_ids = $_POST[ 'tied_products' ];
916 |
917 | if ( is_array( $tied_ids ) ) {
918 | $tied_ids = array_map( 'intval', $tied_ids );
919 | } else {
920 | $tied_ids = array_filter( array_map( 'intval', explode( ',', $tied_ids ) ) );
921 | }
922 |
923 | update_post_meta( $post_id, '_tied_products', $tied_ids );
924 | }
925 |
926 | if ( ! empty( $_POST[ 'dependency_type' ] ) ) {
927 | update_post_meta( $post_id, '_dependency_type', stripslashes( $_POST[ 'dependency_type' ] ) );
928 | }
929 |
930 | if ( ! empty( $_POST[ 'product_dependencies_dropdown' ] ) ) {
931 | update_post_meta( $post_id, '_dependency_selection_type', stripslashes( $_POST[ 'product_dependencies_dropdown' ] ) );
932 | }
933 |
934 | if ( ! empty( $_POST[ 'dependency_notice' ] ) ) {
935 | update_post_meta( $post_id, '_dependency_notice', wp_kses_post( stripslashes( $_POST[ 'dependency_notice' ] ) ) );
936 | } else {
937 |
938 | delete_post_meta( $post_id, '_dependency_notice' );
939 | }
940 | }
941 |
942 | /*
943 | |--------------------------------------------------------------------------
944 | | Deprecated methods.
945 | |--------------------------------------------------------------------------
946 | */
947 |
948 | /**
949 | * Check conditions.
950 | *
951 | * @deprecated 1.1.0
952 | *
953 | * @param int $item_id
954 | * @return boolean
955 | */
956 | public function woo_tied_evaluate_access( $id ) {
957 | _deprecated_function( __METHOD__ . '()', '1.1.0', __CLASS__ . '::evaluate_access()' );
958 | return WC_Product_Dependencies()->evaluate_dependencies( $id );
959 | }
960 | }
961 |
962 | /**
963 | * Returns the main instance of WC_Product_Dependencies to prevent the need to use globals.
964 | *
965 | * @since 1.1.0
966 | * @return WC_Product_Dependencies
967 | */
968 | function WC_Product_Dependencies() {
969 | return WC_Product_Dependencies::instance();
970 | }
971 |
972 | // Backwards compatibility with v1.0.
973 | $GLOBALS[ 'woocommerce_restricted_access' ] = WC_Product_Dependencies();
974 |
--------------------------------------------------------------------------------