├── admin
├── field-group.php
└── views
│ └── field-group-field-conditional-logic-advanced.php
├── assets
├── css
│ └── acf-input.css
└── js
│ ├── acf-field-group.js
│ └── acf-input.js
├── composer.json
├── index.php
├── lib
└── AcfConditionalLogicAdvanced.php
├── readme.txt
├── screenshot-1.png
└── screenshot-2.png
/admin/field-group.php:
--------------------------------------------------------------------------------
1 | 0,
54 | 'group_id' => 0,
55 | 'rule_id' => 0,
56 | 'value' => null,
57 | 'param' => null,
58 | 'disabled' => false
59 | ));
60 |
61 |
62 | // vars
63 | $choices = array();
64 |
65 |
66 | switch( $options['param'] ) {
67 |
68 | case "post_template" :
69 |
70 | // vars
71 | $choices = array(
72 | 'default' => apply_filters( 'default_page_template_title', __('Default Template', 'acf') )
73 | );
74 |
75 | // get templates (WP 4.7)
76 | if( acf_version_compare('wp', '>=', '4.7') ) {
77 | $templates = acf_get_post_templates();
78 | $choices = array_merge($choices, $templates);
79 | }
80 |
81 | // break
82 | break;
83 |
84 |
85 | case "post_format" :
86 |
87 | $choices = get_post_format_strings();
88 |
89 | break;
90 |
91 |
92 | case "post_category" :
93 | $taxonomies = array_map(function($taxonomyName) {
94 | return get_taxonomy($taxonomyName);
95 | }, acf_get_taxonomies());
96 |
97 | $applicableTaxonomies = array_filter($taxonomies, function($taxonomy) {
98 | if ($taxonomy->name == 'post_format') return;
99 | return true;
100 | });
101 |
102 | $choices = acf_get_taxonomy_terms(array_map(function($taxonomy) {
103 | return $taxonomy->name;
104 | }, $applicableTaxonomies));
105 |
106 | break;
107 | }
108 |
109 |
110 | // allow custom location rules
111 | $choices = apply_filters( 'acf/conditional_logic_advanced/rule_values/' . $options['param'], $choices );
112 |
113 |
114 | // create field
115 | acf_render_field(array(
116 | 'type' => 'select',
117 | 'prefix' => "acf_fields[{$options['field_id']}][conditional_logic_advanced][{$options['group_id']}][{$options['rule_id']}]",
118 | 'name' => 'value',
119 | 'value' => $options['value'],
120 | 'choices' => $choices,
121 | 'disabled' => $options['disabled'],
122 | ));
123 |
124 | }
125 |
126 |
127 | /*
128 | * ajax_render_location_value
129 | *
130 | * This function can be accessed via an AJAX action and will return the result from the render_location_value function
131 | *
132 | * @type function (ajax)
133 | * @date 30/09/13
134 | * @since 5.0.0
135 | *
136 | * @param n/a
137 | * @return n/a
138 | */
139 |
140 | function ajax_render_conditional_logic_advanced_value() {
141 |
142 | // validate
143 | if( !acf_verify_ajax() ) {
144 |
145 | die();
146 |
147 | }
148 |
149 |
150 | // call function
151 | $this->render_conditional_logic_advanced_value( $_POST );
152 |
153 |
154 | // die
155 | die();
156 |
157 | }
158 | }
159 |
160 | endif;
--------------------------------------------------------------------------------
/admin/views/field-group-field-conditional-logic-advanced.php:
--------------------------------------------------------------------------------
1 | 'post_template',
19 | 'operator' => '==',
20 | 'value' => 'default',
21 | )
22 |
23 | )
24 |
25 | );
26 |
27 | }
28 |
29 | // vars
30 | $rule_types = apply_filters('acf/conditional_logic_advanced/rule_types', array(
31 | __("Post",'acf') => array(
32 | 'post_template' => __("Post Template",'acf'),
33 | 'post_format' => __("Post Format",'acf'),
34 | 'post_category' => __("Post Taxonomy",'acf'),
35 | ),
36 | ));
37 |
38 |
39 | // WP < 4.7
40 | if( acf_version_compare('wp', '<', '4.7') ) {
41 |
42 | unset( $rule_types[ __("Post",'acf') ]['post_template'] );
43 |
44 | }
45 |
46 | $rule_operators = apply_filters( 'acf/conditional_logic_advanced/rule_operators', array(
47 | '==' => __("is equal to",'acf'),
48 | '!=' => __("is not equal to",'acf'),
49 | ));
50 |
51 | ?>
52 |
53 |
54 |
55 | |
56 |
57 | 'true_false',
61 | 'name' => 'conditional_logic_advanced',
62 | 'prefix' => $field['prefix'],
63 | 'value' => $disabled ? 0 : 1,
64 | 'ui' => 1,
65 | 'class' => 'conditional-logic-advanced-toggle',
66 | ));
67 |
68 | ?>
69 | style="display:none;">
70 |
71 | $group ):
72 |
73 | // validate
74 | if( empty($group) ) {
75 |
76 | continue;
77 |
78 | }
79 |
80 |
81 | // $group_id must be completely different to $rule_id to avoid JS issues
82 | $group_id = "group_{$group_id}";
83 | $h4 = ($group_id == "group_0") ? __("Show this field group if",'acf') : __("or",'acf');
84 |
85 | ?>
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | $rule ):
94 |
95 | // valid rule
96 | $rule = wp_parse_args( $rule, array(
97 | 'field' => '',
98 | 'operator' => '==',
99 | 'value' => '',
100 | ));
101 |
102 |
103 | // $group_id must be completely different to $rule_id to avoid JS issues
104 | $rule_id = "rule_{$rule_id}";
105 | $prefix = "{$field['prefix']}[conditional_logic_advanced][{$group_id}][{$rule_id}]";
106 |
107 | ?>
108 |
109 | 'select',
114 | 'prefix' => $prefix,
115 | 'name' => 'param',
116 | 'value' => $rule['param'],
117 | 'choices' => $rule_types,
118 | 'class' => 'conditional-logic-advanced-rule-param',
119 | 'disabled' => $disabled,
120 | ));
121 |
122 | ?> |
123 | 'select',
128 | 'prefix' => $prefix,
129 | 'name' => 'operator',
130 | 'value' => $rule['operator'],
131 | 'choices' => $rule_operators,
132 | 'class' => 'conditional-logic-advanced-rule-operator',
133 | 'disabled' => $disabled,
134 | ));
135 |
136 | ?> |
137 | acfAdminFieldGroupdConditionalLogicAdvanced->render_conditional_logic_advanced_value(array(
140 | 'field_id' => $field['ID'],
141 | 'group_id' => $group_id,
142 | 'rule_id' => $rule_id,
143 | 'value' => $rule['value'],
144 | 'param' => $rule['param'],
145 | 'class' => 'conditional-logic-advanced-rule-value',
146 | 'disabled' => $disabled,
147 | ));
148 | ?> |
149 |
150 |
151 | |
152 |
153 |
154 | |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | |
169 |
170 |
--------------------------------------------------------------------------------
/assets/css/acf-input.css:
--------------------------------------------------------------------------------
1 | /*--------------------------------------------------------------------------
2 | *
3 | * Conditional Logic Advanced
4 | *
5 | *-------------------------------------------------------------------------*/
6 | /* Hide */
7 | .hidden-by-conditional-logic-advanced {
8 | display: none !important;
9 | }
10 | /* Hide (appear empty) */
11 | .hidden-by-conditional-logic-advanced.appear-empty {
12 | display: table-cell !important;
13 | }
14 | .hidden-by-conditional-logic-advanced.appear-empty .acf-input {
15 | display: none !important;
16 | }
17 |
--------------------------------------------------------------------------------
/assets/js/acf-field-group.js:
--------------------------------------------------------------------------------
1 | (function($){
2 |
3 | /*
4 | * locations
5 | *
6 | * This model will handle location rule events
7 | *
8 | * @type function
9 | * @date 19/08/2015
10 | * @since 5.2.3
11 | *
12 | * @param $post_id (int)
13 | * @return $post_id (int)
14 | */
15 |
16 | acf.field_group.conditional_logic_advanced = acf.model.extend({
17 |
18 | _checked: false,
19 |
20 | events: {
21 | 'change .conditional-logic-advanced-toggle': 'change_toggle',
22 | 'click .add-conditional-logic-advanced-rule': 'add_rule',
23 | 'click .add-conditional-logic-advanced-group': 'add_group',
24 | 'click .remove-conditional-logic-advanced-rule': 'remove_rule',
25 | 'change .conditional-logic-advanced-rule-param': 'change_rule'
26 | },
27 |
28 | /*
29 | * change_toggle
30 | *
31 | * This function is triggered by changing the 'Conditional Logic' radio button
32 | *
33 | * @type function
34 | * @date 8/04/2014
35 | * @since 5.0.0
36 | *
37 | * @param $input
38 | * @return n/a
39 | */
40 |
41 | change_toggle: function( e ){
42 |
43 | // vars
44 | var $input = e.$el,
45 | checked = e.$el.prop('checked'),
46 | $td = $input.closest('.acf-input');
47 |
48 | if( checked ) {
49 |
50 | $td.find('.rule-groups').show();
51 | $td.find('.rule-groups').find('[name]').prop('disabled', false);
52 |
53 | } else {
54 |
55 | $td.find('.rule-groups').hide();
56 | $td.find('.rule-groups').find('[name]').prop('disabled', true);
57 |
58 | }
59 |
60 | this._checked = checked;
61 | },
62 |
63 | /*
64 | * add_rule
65 | *
66 | * This function will add a new rule below the specified $tr
67 | *
68 | * @type function
69 | * @date 8/04/2014
70 | * @since 5.0.0
71 | *
72 | * @param $tr
73 | * @return n/a
74 | */
75 |
76 | add_rule: function( e ){
77 |
78 | // vars
79 | var $tr = e.$el.closest('tr');
80 |
81 |
82 | // duplicate
83 | $tr2 = acf.duplicate( $tr );
84 |
85 | },
86 |
87 |
88 | /*
89 | * remove_rule
90 | *
91 | * This function will remove the $tr and potentially the group
92 | *
93 | * @type function
94 | * @date 8/04/2014
95 | * @since 5.0.0
96 | *
97 | * @param $tr
98 | * @return n/a
99 | */
100 |
101 | remove_rule: function( e ){
102 |
103 | // vars
104 | var $tr = e.$el.closest('tr');
105 |
106 |
107 | // save field
108 | $tr.find('select:first').trigger('change');
109 |
110 |
111 | if( $tr.siblings('tr').length == 0 ) {
112 |
113 | // remove group
114 | $tr.closest('.rule-group').remove();
115 |
116 | }
117 |
118 |
119 | // remove tr
120 | $tr.remove();
121 |
122 |
123 | },
124 |
125 |
126 | /*
127 | * add_group
128 | *
129 | * This function will add a new rule group to the given $groups container
130 | *
131 | * @type function
132 | * @date 8/04/2014
133 | * @since 5.0.0
134 | *
135 | * @param $tr
136 | * @return n/a
137 | */
138 |
139 | add_group: function( e ){
140 |
141 | // vars
142 | var $groups = e.$el.closest('.rule-groups'),
143 | $group = $groups.find('.rule-group:last');
144 |
145 |
146 | // duplicate
147 | $group2 = acf.duplicate( $group );
148 |
149 |
150 | // update h4
151 | $group2.find('h4').text( acf._e('or') );
152 |
153 |
154 | // remove all tr's except the first one
155 | $group2.find('tr:not(:first)').remove();
156 |
157 | },
158 |
159 |
160 | /*
161 | * change_rule
162 | *
163 | * This function is triggered when changing a location rule trigger
164 | *
165 | * @type function
166 | * @date 8/04/2014
167 | * @since 5.0.0
168 | *
169 | * @param $select
170 | * @return n/a
171 | */
172 |
173 | change_rule: function( e ){
174 |
175 | // vars
176 | var $select = e.$el,
177 | $tr = $select.closest('tr'),
178 | rule_id = $tr.attr('data-id'),
179 | $group = $tr.closest('.rule-group'),
180 | group_id = $group.attr('data-id');
181 |
182 |
183 | // add loading gif
184 | var $div = $('');
185 |
186 | $tr.find('td.value').html( $div );
187 |
188 |
189 | // load location html
190 | $.ajax({
191 | url: acf.get('ajaxurl'),
192 | data: acf.prepare_for_ajax({
193 | 'field_id': $select.parents('.acf-field-object').eq(0).data('id'),
194 | 'action': 'acf/field_group/render_conditional_logic_advanced_value',
195 | 'rule_id': rule_id,
196 | 'group_id': group_id,
197 | 'param': $select.val(),
198 | 'value': ''
199 | }),
200 | type: 'post',
201 | dataType: 'html',
202 | success: function(html){
203 | $select = $(html).prop('enabled', this._checked);
204 | $div.replaceWith($select);
205 | }.bind(this)
206 | });
207 |
208 | }
209 | });
210 |
211 | })(jQuery);
--------------------------------------------------------------------------------
/assets/js/acf-input.js:
--------------------------------------------------------------------------------
1 |
2 | (function($){
3 |
4 | acf.conditional_logic_advanced = acf.model.extend({
5 |
6 | actions: {
7 | 'prepare 20': 'render',
8 | 'append 20': 'render'
9 | },
10 |
11 | events: {
12 | 'change #page_template': '_change_template',
13 | 'change #post-formats-select input': '_change_format',
14 | 'change #post .categorychecklist input': '_change_term',
15 | 'change #post .categorychecklist select': '_change_term',
16 | 'change .acf-field input': 'change',
17 | 'change .acf-field textarea': 'change',
18 | 'change .acf-field select': 'change'
19 | },
20 | o: {
21 | //'page_template': 0,
22 | //'post_format': 0,
23 | //'post_taxonomy': 0
24 | },
25 |
26 | items: {},
27 | triggers: {},
28 |
29 |
30 | /*
31 | * add
32 | *
33 | * This function will add a set of conditional logic rules
34 | *
35 | * @type function
36 | * @date 22/05/2015
37 | * @since 5.2.3
38 | *
39 | * @param target (string) target field key
40 | * @param groups (array) rule groups
41 | * @return $post_id (int)
42 | */
43 |
44 | add: function( target, groups ){
45 |
46 | // debug
47 | //console.log( 'conditional_logic.add(%o, %o)', target, groups );
48 |
49 |
50 | // populate triggers
51 | for( var i in groups ) {
52 |
53 | // vars
54 | var group = groups[i];
55 |
56 | for( var k in group ) {
57 |
58 | // vars
59 | var rule = group[k],
60 | trigger = (rule.param) ? rule.param : rule.field,
61 | triggers = this.triggers[ trigger ] || {};
62 |
63 |
64 | // append trigger (sub field will simply override)
65 | triggers[ target ] = target;
66 |
67 |
68 | // update
69 | this.triggers[ trigger ] = triggers;
70 |
71 | }
72 |
73 | }
74 |
75 |
76 | // append items
77 | this.items[ target ] = groups;
78 | },
79 |
80 | update: function( k, v ){
81 |
82 | this.o[ k ] = v;
83 |
84 | //console.log('update', k, v);
85 |
86 | return this;
87 |
88 | },
89 |
90 |
91 | _update_template: function(){
92 |
93 | // vars
94 | var page_template = $('#page_template').val();
95 |
96 |
97 | // update & fetch
98 | return this.update('page_template', page_template);
99 |
100 | },
101 |
102 | _change_template: function() {
103 | this._update_template().refresh();
104 | },
105 |
106 | _update_format: function(){
107 |
108 | // vars
109 | var post_format = $('#post-formats-select input:checked').val();
110 |
111 |
112 | // default
113 | if( post_format == '0' ) {
114 |
115 | post_format = 'standard';
116 |
117 | }
118 |
119 |
120 | // update & fetch
121 | return this.update('post_format', post_format);
122 |
123 | },
124 |
125 | _change_format: function() {
126 | this._update_format().refresh();
127 | },
128 |
129 | _update_term: function(){
130 |
131 | // reference
132 | var self = this;
133 |
134 |
135 | // bail early if within media popup
136 | if( $('#post .categorychecklist input, #post .categorychecklist select').closest('.media-frame').exists() ) {
137 |
138 | return;
139 |
140 | }
141 |
142 | // vars
143 | var post_taxonomy = this.o['post_taxonomy'] || [];
144 |
145 |
146 | // loop over term lists
147 | $('#post .categorychecklist').each(function(){
148 | var values = [];
149 |
150 | // vars
151 | var $el = $(this),
152 | $checkbox = $el.find('input[type="checkbox"]').not(':disabled'),
153 | $radio = $el.find('input[type="radio"]').not(':disabled'),
154 | $select = $el.find('select').not(':disabled'),
155 | $hidden = $el.find('input[type="hidden"]').not(':disabled'),
156 | taxonomy = /^taxonomy-(.*)$/.exec($el.parents('.categorydiv[id^=taxonomy-]').attr('id'))[1]
157 | termIds = [];
158 |
159 |
160 | // bail early if in attachment
161 | if( $el.closest('.media-frame').exists() ) {
162 |
163 | return;
164 |
165 | }
166 |
167 |
168 | // checkbox
169 | if( $checkbox.exists() ) {
170 |
171 | $checkbox.filter(':checked').each(function(){
172 |
173 | termIds.push( parseInt($(this).val()) );
174 |
175 | });
176 |
177 | } else if( $radio.exists() ) {
178 |
179 | $radio.filter(':checked').each(function(){
180 |
181 | termIds.push( parseInt($(this).val()) );
182 |
183 | });
184 |
185 | } else if( $select.exists() ) {
186 |
187 | $select.find('option:selected').each(function(){
188 |
189 | termIds.push( parseInt($(this).val()) );
190 |
191 | });
192 |
193 | } else if( $hidden.exists() ) {
194 |
195 | $hidden.each(function(){
196 |
197 | // ignor blank values
198 | if( ! $(this).val() ) {
199 |
200 | return;
201 |
202 | }
203 |
204 | termIds.push( parseInt($(this).val()) );
205 |
206 | });
207 |
208 | }
209 |
210 | // remove all entries for this taxonomy before adding
211 | post_taxonomy = post_taxonomy.filter(function(value) {
212 | return value.taxonomy != taxonomy;
213 | });
214 |
215 | termIds
216 | // filter duplicates
217 | .filter(function(value, index, values) {
218 | return values.indexOf(value) === index;
219 | })
220 | // add taxonomy entries
221 | .forEach(function(termId) {
222 | post_taxonomy.push({
223 | id: termId,
224 | taxonomy: taxonomy
225 | });
226 | });
227 | });
228 |
229 |
230 | // update screen
231 | return this.update( 'post_taxonomy', post_taxonomy );
232 |
233 | },
234 |
235 | _change_term: function() {
236 | this._update_term().refresh();
237 | },
238 |
239 | _change_tag: function() {
240 | this._update_tag().refresh();
241 | },
242 |
243 | _update_tag: function(e) {
244 | var tagDelimiter = ( window.tagsSuggestL10n && window.tagsSuggestL10n.tagDelimiter ) || ',';
245 | var post_taxonomy = this.o['post_taxonomy'] || [];
246 |
247 | $('[id^="tagsdiv-"] .jaxtag textarea')
248 | .toArray()
249 | .forEach(function(el) {
250 | var taxonomy = $(el).parents('.tagsdiv').attr('id'),
251 | value = $(el).val();
252 | elTags = $(el).find('button').toArray();
253 |
254 | // remove all entries for this taxonomy before adding
255 | post_taxonomy = post_taxonomy.filter(function(value) {
256 | return value.taxonomy != taxonomy;
257 | });
258 |
259 | value
260 | .split(tagDelimiter)
261 | .forEach(function(tagName) {
262 | tagName = $.trim(tagName);
263 |
264 | if (!tagName) return;
265 |
266 | post_taxonomy.push({
267 | name: tagName,
268 | taxonomy: taxonomy
269 | });
270 | });
271 | })
272 |
273 | // update screen
274 | return this.update( 'post_taxonomy', post_taxonomy );
275 | },
276 |
277 |
278 | /*
279 | * render
280 | *
281 | * This function will render all fields
282 | *
283 | * @type function
284 | * @date 22/05/2015
285 | * @since 5.2.3
286 | *
287 | * @param $post_id (int)
288 | * @return $post_id (int)
289 | */
290 |
291 | render: function( $el ) {
292 | // debug
293 | //console.log('conditional_logic.render(%o)', $el);
294 |
295 | // override wordpress core tag parsing, so that we can detect when tags change
296 | $(document).ready(function($) {
297 | if (!window.tagBox) return;
298 |
299 | var tagBox = window.tagBox,
300 | parseTagsOriginal = tagBox.parseTags,
301 | flushTagsOriginal = tagBox.flushTags;
302 |
303 | tagBox.parseTags = function() {
304 | var result = parseTagsOriginal.apply(tagBox, arguments);
305 | this._change_tag();
306 | return result;
307 | }.bind(this);
308 |
309 | tagBox.flushTags = function() {
310 | var result = flushTagsOriginal.apply(tagBox, arguments);
311 | this._change_tag();
312 | return result;
313 | }.bind(this);
314 |
315 | }.bind(this));
316 |
317 | this._update_format();
318 | this._update_template();
319 | this._update_term();
320 | this._update_tag();
321 |
322 | this.refresh();
323 | },
324 |
325 | /*
326 | * change
327 | *
328 | * This function is called when an input is changed and will render any fields which are considered targets of this trigger
329 | *
330 | * @type function
331 | * @date 22/05/2015
332 | * @since 5.2.3
333 | *
334 | * @param $post_id (int)
335 | * @return $post_id (int)
336 | */
337 |
338 | change: function( e ){
339 |
340 | // debug
341 | //console.log( 'conditional_logic.change(%o)', $input );
342 |
343 |
344 | // vars
345 | var $input = e.$el,
346 | $field = acf.get_field_wrap( $input ),
347 | key = $field.data('key');
348 |
349 |
350 | // bail early if this field does not trigger any actions
351 | if( typeof this.triggers[key] === 'undefined' ) {
352 |
353 | return false;
354 |
355 | }
356 |
357 |
358 | // vars
359 | $parent = $field.parent();
360 |
361 |
362 | // update visibility
363 | for( var i in this.triggers[ key ] ) {
364 |
365 | // get the target key
366 | var target_key = this.triggers[ key ][ i ];
367 |
368 |
369 | // get targets
370 | var $targets = acf.get_fields(target_key, $parent, true);
371 |
372 |
373 | // render
374 | this.render_fields( $targets );
375 |
376 | }
377 |
378 |
379 | // action for 3rd party customization
380 | //acf.do_action('refresh', $parent);
381 |
382 | },
383 |
384 | refresh: function() {
385 | // get targets
386 | var $targets = acf.get_fields( '', '', true );
387 |
388 |
389 | // render fields
390 | this.render_fields( $targets );
391 |
392 |
393 | // action for 3rd party customization
394 | //acf.do_action('refresh', $el);
395 |
396 | },
397 |
398 |
399 | /*
400 | * render_fields
401 | *
402 | * This function will render a selection of fields
403 | *
404 | * @type function
405 | * @date 22/05/2015
406 | * @since 5.2.3
407 | *
408 | * @param $post_id (int)
409 | * @return $post_id (int)
410 | */
411 |
412 | render_fields: function( $targets ) {
413 |
414 | // reference
415 | var self = this;
416 |
417 |
418 | // loop over targets and render them
419 | $targets.each(function(){
420 |
421 | self.render_field( $(this) );
422 |
423 | });
424 |
425 | },
426 |
427 |
428 | /*
429 | * render_field
430 | *
431 | * This function will render a field
432 | *
433 | * @type function
434 | * @date 22/05/2015
435 | * @since 5.2.3
436 | *
437 | * @param $post_id (int)
438 | * @return $post_id (int)
439 | */
440 |
441 | render_field : function( $target ){
442 |
443 | // vars
444 | var key = $target.data('key');
445 |
446 |
447 | // bail early if this field does not contain any conditional logic
448 | if( typeof this.items[ key ] === 'undefined' ) {
449 |
450 | return false;
451 |
452 | }
453 |
454 |
455 | // vars
456 | var visibility = false;
457 |
458 |
459 | // debug
460 | //console.log( 'conditional_logic.render_field(%o)', $field );
461 |
462 |
463 | // get conditional logic
464 | var groups = this.items[ key ];
465 |
466 |
467 | // calculate visibility
468 | for( var i = 0; i < groups.length; i++ ) {
469 |
470 | // vars
471 | var group = groups[i],
472 | match_group = true;
473 |
474 | for( var k = 0; k < group.length; k++ ) {
475 |
476 | // vars
477 | var rule = group[k];
478 |
479 | // break if rule did not validate
480 | if( !this.calculate(rule, $target) ) {
481 |
482 | match_group = false;
483 | break;
484 |
485 | }
486 |
487 | }
488 |
489 |
490 | // set visibility if rule group did validate
491 | if( match_group ) {
492 |
493 | visibility = true;
494 | break;
495 |
496 | }
497 |
498 | }
499 |
500 |
501 | // hide / show field
502 | if( visibility ) {
503 |
504 | this.show_field( $target );
505 |
506 | } else {
507 |
508 | this.hide_field( $target );
509 |
510 | }
511 |
512 | },
513 |
514 |
515 | /*
516 | * show_field
517 | *
518 | * This function will show a field
519 | *
520 | * @type function
521 | * @date 22/05/2015
522 | * @since 5.2.3
523 | *
524 | * @param $post_id (int)
525 | * @return $post_id (int)
526 | */
527 |
528 | show_field: function( $field ){
529 |
530 | // debug
531 | //console.log('show_field(%o)', $field);
532 |
533 |
534 | // vars
535 | var key = $field.data('key');
536 |
537 |
538 | // remove class
539 | $field.removeClass( 'hidden-by-conditional-logic-advanced' );
540 |
541 |
542 | // enable
543 | acf.enable_form( $field, 'condition_'+key );
544 |
545 |
546 | // action for 3rd party customization
547 | acf.do_action('show_field', $field, 'conditional_logic_advanced' );
548 |
549 | },
550 |
551 |
552 | /*
553 | * hide_field
554 | *
555 | * This function will hide a field
556 | *
557 | * @type function
558 | * @date 22/05/2015
559 | * @since 5.2.3
560 | *
561 | * @param $post_id (int)
562 | * @return $post_id (int)
563 | */
564 |
565 | hide_field : function( $field ){
566 |
567 | // debug
568 | //console.log('hide_field(%o)', $field);
569 |
570 |
571 | // vars
572 | var key = $field.data('key');
573 |
574 |
575 | // add class
576 | $field.addClass( 'hidden-by-conditional-logic-advanced' );
577 |
578 |
579 | // disable
580 | acf.disable_form( $field, 'condition_'+key );
581 |
582 |
583 | // action for 3rd party customization
584 | acf.do_action('hide_field', $field, 'conditional_logic_advanced' );
585 |
586 | },
587 |
588 |
589 | /*
590 | * get_trigger
591 | *
592 | * This function will return the relevant $trigger for a $target
593 | *
594 | * @type function
595 | * @date 22/05/2015
596 | * @since 5.2.3
597 | *
598 | * @param $post_id (int)
599 | * @return $post_id (int)
600 | */
601 |
602 | get_trigger: function( $target, key ){
603 |
604 | // vars
605 | var selector = acf.get_selector( key );
606 |
607 |
608 | // find sibling $trigger
609 | var $trigger = $target.siblings( selector );
610 |
611 |
612 | // parent trigger
613 | if( !$trigger.exists() ) {
614 |
615 | // vars
616 | var parent = acf.get_selector();
617 |
618 |
619 | // loop through parent fields and review their siblings too
620 | $target.parents( parent ).each(function(){
621 |
622 | // find sibling $trigger
623 | $trigger = $(this).siblings( selector );
624 |
625 |
626 | // bail early if $trigger is found
627 | if( $trigger.exists() ) {
628 |
629 | return false;
630 |
631 | }
632 |
633 | });
634 |
635 | }
636 |
637 |
638 | // bail early if no $trigger is found
639 | if( !$trigger.exists() ) {
640 |
641 | return false;
642 |
643 | }
644 |
645 |
646 | // return
647 | return $trigger;
648 |
649 | },
650 |
651 |
652 | /*
653 | * calculate
654 | *
655 | * This function will calculate if a rule matches based on the $trigger
656 | *
657 | * @type function
658 | * @date 22/05/2015
659 | * @since 5.2.3
660 | *
661 | * @param $post_id (int)
662 | * @return $post_id (int)
663 | */
664 |
665 | calculate : function( rule, $target ){
666 |
667 | // debug
668 | //console.log( 'calculate(%o, %o, %o)', rule, $trigger, $target);
669 |
670 | // vars
671 | var match = false;
672 |
673 | switch(rule['param']) {
674 | case 'post_template':
675 | match = this.o['page_template'] == rule['value'];
676 | break;
677 |
678 | case 'post_category':
679 | match = this.o['post_taxonomy'].some(function(value) {
680 | if (rule['value'].taxonomy != value.taxonomy) return;
681 | if (value.id && rule['value'].id == value.id) return true;
682 | if (value.name && rule['value'].name == value.name) return true;
683 | });
684 | break;
685 |
686 | case 'post_format':
687 | match = this.o['post_format'] == rule['value'];
688 | break;
689 |
690 | default:
691 | if (rule['field']) {
692 | var $trigger = this.get_trigger( $target, rule.field ),
693 | type = $trigger.data('type');
694 |
695 | // input with :checked
696 | if( type == 'true_false' || type == 'checkbox' || type == 'radio' ) {
697 |
698 | match = this.calculate_checkbox( rule, $trigger );
699 |
700 |
701 | } else if( type == 'select' ) {
702 |
703 | match = this.calculate_select( rule, $trigger );
704 |
705 | }
706 | } else {
707 | console.error('Unknown rule param: ' + rule['param']);
708 | }
709 | break;
710 | }
711 |
712 | // reverse if 'not equal to'
713 | if( rule.operator === "!=" ) {
714 |
715 | match = !match;
716 |
717 | }
718 |
719 |
720 | // return
721 | return match;
722 |
723 | },
724 |
725 | calculate_checkbox: function( rule, $trigger ){
726 |
727 | // look for selected input
728 | var match = $trigger.find('input[value="' + rule.value + '"]:checked').exists();
729 |
730 |
731 | // override for "allow null"
732 | if( rule.value === '' && !$trigger.find('input:checked').exists() ) {
733 |
734 | match = true;
735 |
736 | }
737 |
738 |
739 | // return
740 | return match;
741 |
742 | },
743 |
744 |
745 | calculate_select: function( rule, $trigger ){
746 |
747 | // vars
748 | var $select = $trigger.find('select'),
749 | val = $select.val();
750 |
751 |
752 | // check for no value
753 | if( !val && !$.isNumeric(val) ) {
754 |
755 | val = '';
756 |
757 | }
758 |
759 |
760 | // convert to array
761 | if( !$.isArray(val) ) {
762 |
763 | val = [ val ];
764 |
765 | }
766 |
767 |
768 | // calc
769 | match = ($.inArray(rule.value, val) > -1);
770 |
771 |
772 | // return
773 | return match;
774 |
775 | }
776 | });
777 |
778 | })(jQuery);
779 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "andrejpavlovic/acf-conditional-logic-advanced",
3 | "description": "Adds an Advanced Conditional Logic field setting to ACF that can show/hide individual fields based on post template, format, and/or category.",
4 | "version": "1.1.3",
5 | "type": "wordpress-plugin",
6 | "license": "GPL-2.0"
7 | }
8 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | plugin_basename( __FILE__ ),
20 | 'path' => plugin_dir_path( __FILE__ ),
21 | 'url' => plugin_dir_url( __FILE__ ),
22 | ]);
23 | $acfCondLogAdv->initialize();
24 |
--------------------------------------------------------------------------------
/lib/AcfConditionalLogicAdvanced.php:
--------------------------------------------------------------------------------
1 | settings = $settings;
8 |
9 | // admin
10 | if( is_admin() ) {
11 | require $this->settings['path'] . 'admin/field-group.php';
12 | $this->acfAdminFieldGroupdConditionalLogicAdvanced = new acf_admin_field_group_conditional_logic_advanced();
13 | }
14 |
15 | add_action('init', array($this, 'register_assets'), 5);
16 |
17 | add_action('acf/input/admin_enqueue_scripts', [$this, 'input_admin_enqueue_scripts']);
18 | add_action('acf/field_group/admin_enqueue_scripts', [$this, 'field_group_admin_enqueue_scripts']);
19 |
20 | add_filter('acf/update_field', function($field) {
21 | // clean up conditional logic keys
22 | if( !empty($field['conditional_logic_advanced']) ) {
23 |
24 | // extract groups
25 | $groups = acf_extract_var( $field, 'conditional_logic_advanced' );
26 |
27 |
28 | // clean array
29 | $groups = array_filter($groups);
30 | $groups = array_values($groups);
31 |
32 |
33 | // clean rules
34 | foreach( array_keys($groups) as $i ) {
35 |
36 | $groups[ $i ] = array_filter($groups[ $i ]);
37 | $groups[ $i ] = array_values($groups[ $i ]);
38 |
39 | }
40 |
41 |
42 | // reset conditional logic
43 | $field['conditional_logic_advanced'] = $groups;
44 |
45 | }
46 |
47 | return $field;
48 | });
49 |
50 | add_action('acf/render_field', [$this, 'acf_render_field']);
51 | }
52 |
53 | function initialize() {
54 | add_action('acf/render_field_settings', [$this, 'render_field_settings']);
55 | }
56 |
57 | function render_field_settings($field) {
58 | if ($field['type'] == 'clone') return;
59 |
60 | $args = [
61 | 'field' => $field,
62 | ];
63 | require $this->settings['path'] . 'admin/views/field-group-field-conditional-logic-advanced.php';
64 | }
65 |
66 | function acf_render_field($field) {
67 | if (empty($field['conditional_logic_advanced'])) return;
68 |
69 | $groups = $field['conditional_logic_advanced'];
70 |
71 | // convert taxonomy term from slug to id
72 | foreach($groups as $groupId => $group) {
73 | foreach ($group as $ruleId => $rule) {
74 | if (!empty($rule['field'])) continue;
75 |
76 | if ($rule['param'] != 'post_category') continue;
77 | $param = explode(':', $rule['value']);
78 |
79 | $taxonomyTerm = get_term_by('slug', $param[1], $param[0]);
80 |
81 | $groups[$groupId][$ruleId]['value'] = array(
82 | 'id' => $taxonomyTerm->term_id,
83 | 'slug' => $taxonomyTerm->slug,
84 | 'taxonomy' => $taxonomyTerm->taxonomy,
85 | 'name' => $taxonomyTerm->name,
86 | );
87 | }
88 | }
89 | ?>
90 |
93 | settings['url'] . 'assets/js/acf-input.js', array('acf-input') );
99 | wp_register_script('acf-field-group-conditional-logic-advanced', $this->settings['url'] . 'assets/js/acf-field-group.js', array('acf-input-conditional-logic-advanced') );
100 |
101 | // styles
102 | wp_register_style('acf-input-conditional-logic-advanced', $this->settings['url'] . 'assets/css/acf-input.css', array('acf-input') );
103 | }
104 |
105 | function input_admin_enqueue_scripts() {
106 | wp_enqueue_script('acf-input-conditional-logic-advanced');
107 | wp_enqueue_style('acf-input-conditional-logic-advanced');
108 | }
109 |
110 | function field_group_admin_enqueue_scripts() {
111 | wp_enqueue_script('acf-field-group-conditional-logic-advanced');
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === ACF Conditional Logic Advanced ===
2 | Contributors: andrej.pavlovic
3 | Tags: acf, advanced custom fields, acf-field, conditional logic
4 | Requires at least: 3.6.0
5 | Tested up to: 4.9.9
6 | License: GPLv2
7 | License URI: http://www.gnu.org/licenses/gpl-2.0.html
8 |
9 | Adds an Advanced Conditional Logic field setting to ACF that can show/hide individual fields based on post template, format, and/or category.
10 |
11 | = Links =
12 | * [Website](https://github.com/andrejpavlovic/acf-conditional-logic-advanced)
13 | * [Support](https://github.com/andrejpavlovic/acf-conditional-logic-advanced/issues)
14 | * [Advanced Custom Fields](https://www.advancedcustomfields.com/)
15 |
16 | == Screenshots ==
17 |
18 | 1. Post Category options
19 | 2. Advanced Conditional Logic field setting options: Template, Format, Category
20 |
21 | == Changelog ==
22 |
23 | = 1.1.3 =
24 | * Small fix to prevent acf-input category check from throwing errors when editing menus
25 |
26 | = 1.1.2 =
27 | * Small fix for Yes/No when editing Field in Field Group
28 | * Tested with ACF 5.7.7
29 |
30 | = 1.1.1 =
31 |
32 | * Don't display Conditional Logic Advanced row when field type is "Clone".
33 |
34 | = 1.1.0 =
35 | * Added support for custom taxonomies.
36 | * Added support for non-hierarchical taxonomies. (e.g. Tags)
37 | * Reorganized the Post Template dropdown options.
38 |
39 | = 1.0.3 =
40 | * composer.json - fixed version
41 |
42 | = 1.0.2 =
43 | * composer.json - fixed name
44 |
45 | = 1.0.1 =
46 | * Added composer.json
47 |
48 | = 1.0.0 =
49 | * Initial release.
50 |
--------------------------------------------------------------------------------
/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrejpavlovic/acf-conditional-logic-advanced/63ca1022265e0d257575ab3a8f31f91fe14a654f/screenshot-1.png
--------------------------------------------------------------------------------
/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrejpavlovic/acf-conditional-logic-advanced/63ca1022265e0d257575ab3a8f31f91fe14a654f/screenshot-2.png
--------------------------------------------------------------------------------