Toolset Types – Custom Post Types, Custom Fields and Taxonomies - Version 1.9.1

Version Description

  • Released date: 2016-03-08
  • Fixed javascript infinite loop in post field group edit page.
  • Fixed conflict between post relationship table and WordPress heartbeat ajax call.
  • Fixed field slug limit of 20 characters.
  • Fixed issue with filtering by multiple checkboxes fields that failed to return results.
  • Fixed custom post type icon on "At a Glance" section.
  • Fixed hidden visibility option of post types that did not work for built-in types.
  • Fixed issue when adding an existing field that was always attached to bottom of the list.
  • Fixed issue with parent custom post type that could not be stored in "Select child fields from Child to be displayed in Post Relationship table"
  • Fixed options of unsaved checkbox / select / radio fields weren't sortable.
  • Fixed an issue when adding a existing field to another group.
  • Fixed an issue with cursor that was moved automatically to the end of slug input.
Download this release

Release Info

Developer christianglingener
Plugin Icon 128x128 Toolset Types – Custom Post Types, Custom Fields and Taxonomies
Version 1.9.1
Comparing to
See all releases

Code changes from version 1.9 to 1.9.1

Files changed (66) hide show
  1. admin.php +77 -33
  2. embedded/classes/field/accessor/termmeta.php +5 -1
  3. embedded/classes/field/datamapper/abstract.php +3 -0
  4. embedded/classes/field/datamapper/checkboxes.php +4 -18
  5. embedded/classes/field/definition.php +97 -10
  6. embedded/classes/field/instance_term.php +1 -0
  7. embedded/classes/field/option_checkboxes.php +112 -0
  8. embedded/classes/field/option_radio.php +62 -0
  9. embedded/classes/field/option_select.php +27 -0
  10. embedded/classes/field/renderer/abstract.php +2 -0
  11. embedded/classes/field/renderer/factory.php +86 -0
  12. embedded/classes/field/renderer/preview/address.php +45 -0
  13. embedded/classes/field/renderer/preview/base.php +146 -0
  14. embedded/classes/field/renderer/preview/checkbox.php +34 -0
  15. embedded/classes/field/renderer/preview/checkboxes.php +48 -0
  16. embedded/classes/field/renderer/preview/colorpicker.php +48 -0
  17. embedded/classes/field/renderer/preview/date.php +40 -0
  18. embedded/classes/field/renderer/preview/file.php +25 -0
  19. embedded/classes/field/renderer/preview/image.php +90 -0
  20. embedded/classes/field/renderer/preview/radio.php +45 -0
  21. embedded/classes/field/renderer/preview/skype.php +24 -0
  22. embedded/classes/field/renderer/preview/textfield.php +31 -0
  23. embedded/classes/field/renderer/preview/url.php +73 -0
  24. embedded/classes/field/type_definition_factory.php +24 -3
  25. embedded/classes/field/utils.php +1 -2
  26. embedded/classes/gui/term_field_editing.php +91 -0
  27. embedded/classes/utils.php +115 -5
  28. embedded/composer/installed.json +4 -4
  29. embedded/frontend.php +4 -4
  30. embedded/functions.php +32 -4
  31. embedded/includes/conditional-display.php +8 -8
  32. embedded/includes/custom-types.php +95 -16
  33. embedded/includes/wpml.php +6 -3
  34. embedded/plugin.php +1 -1
  35. embedded/readme.txt +4 -2
  36. embedded/resources/css/basic.css +5 -1
  37. embedded/resources/css/fix-wordpress-core.css +985 -0
  38. embedded/resources/js/basic.js +5 -2
  39. embedded/resources/js/fields-form.js +22 -12
  40. embedded/resources/js/post-relationship.js +43 -25
  41. help.php +1 -1
  42. includes/classes/class.types.admin.edit.fields.php +0 -5
  43. includes/classes/class.types.admin.edit.post.type.php +41 -14
  44. includes/classes/class.types.admin.edit.taxonomy.php +1 -1
  45. includes/classes/class.types.dashboard.php +0 -21
  46. includes/classes/class.wpcf.marketing.messages.php +20 -87
  47. includes/classes/class.wpcf.marketing.php +1 -96
  48. includes/classes/class.wpcf.marketing.tutorial.php +0 -243
  49. includes/classes/page/listing/abstract.php +1 -1
  50. includes/conditional-display.php +4 -0
  51. marketing/etc/types-site-kinds.php +0 -36
  52. marketing/getting-started/assets/css/getting-started.css +0 -156
  53. marketing/getting-started/assets/images/arrow.png +0 -0
  54. marketing/getting-started/assets/scripts/getting-started.js +0 -46
  55. marketing/getting-started/index.php +0 -32
  56. plus/installer/changelog.txt +5 -0
  57. plus/installer/includes/class-installer-theme.php +13 -2
  58. plus/installer/includes/installer.class.php +82 -62
  59. plus/installer/installer.php +1 -1
  60. plus/installer/loader.php +2 -2
  61. plus/installer/res/css/admin.css +9 -1
  62. plus/installer/res/js/admin.js +24 -8
  63. plus/installer/templates/repository-listing.php +19 -7
  64. readme.txt +19 -3
  65. resources/js/fields-form.js +35 -26
  66. wpcf.php +24 -8
admin.php CHANGED
@@ -21,7 +21,6 @@ add_action( 'init', 'wpcf_init_admin_pages' );
21
 
22
  add_action( 'admin_menu', 'wpcf_admin_menu_hook' );
23
  add_action( 'wpcf_admin_page_init', 'wpcf_enqueue_scripts' );
24
- add_action( 'admin_enqueue_scripts', 'wpcf_admin_enqueue_scripts' );
25
 
26
  // OMG, why so early? At this point we don't even have embedded Types (with functions.php).
27
  if ( defined( 'DOING_AJAX' ) ) {
@@ -1334,38 +1333,6 @@ function wpcf_get_temporary_directory()
1334
  return $dir;
1335
  }
1336
 
1337
- /**
1338
- *
1339
- */
1340
-
1341
- function wpcf_admin_enqueue_scripts($hook)
1342
- {
1343
- wp_register_script(
1344
- 'marketing-getting-started',
1345
- plugin_dir_url( __FILE__ ).'/marketing/getting-started/assets/scripts/getting-started.js',
1346
- array('jquery'),
1347
- WPCF_VERSION,
1348
- true
1349
- );
1350
- if ( preg_match( '@/marketing/getting-started/[^/]+.php$@', $hook ) ) {
1351
- $marketing = new WPCF_Types_Marketing_Messages();
1352
- wp_localize_script(
1353
- 'marketing-getting-started',
1354
- 'marketing_getting_started',
1355
- array( 'id' => $marketing->get_option_name() )
1356
- );
1357
- wp_enqueue_script('marketing-getting-started');
1358
- wp_enqueue_style(
1359
- 'marketing-getting-started',
1360
- plugin_dir_url( __FILE__ ).'/marketing/getting-started/assets/css/getting-started.css',
1361
- array(),
1362
- WPCF_VERSION,
1363
- 'all'
1364
- );
1365
- }
1366
- }
1367
-
1368
-
1369
  /**
1370
  * add types configuration to debug
1371
  */
@@ -1513,3 +1480,80 @@ function wpcf_admin_menu_user_fields_control() {
1513
  echo '</form>';
1514
  wpcf_add_admin_footer();
1515
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  add_action( 'admin_menu', 'wpcf_admin_menu_hook' );
23
  add_action( 'wpcf_admin_page_init', 'wpcf_enqueue_scripts' );
 
24
 
25
  // OMG, why so early? At this point we don't even have embedded Types (with functions.php).
26
  if ( defined( 'DOING_AJAX' ) ) {
1333
  return $dir;
1334
  }
1335
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1336
  /**
1337
  * add types configuration to debug
1338
  */
1480
  echo '</form>';
1481
  wpcf_add_admin_footer();
1482
  }
1483
+
1484
+
1485
+ /* Delete this with release of 2.0 as it's than fixed in toolset-common */
1486
+ function types_670() { ?>
1487
+ <script type="text/javascript">
1488
+ function typesCheckTrigger(trigger, formID)
1489
+ {
1490
+ var $ = jQuery;
1491
+ $trigger = $('[data-wpt-name="' + trigger + '"]', formID)
1492
+
1493
+ if ($('body').hasClass('wp-admin')) {
1494
+ trigger = trigger.replace(/wpcf\-/, 'wpcf[') + ']';
1495
+ $trigger = $('[data-wpt-name="' + trigger + '"]', formID);
1496
+ }
1497
+
1498
+ if ($trigger.length < 1) {
1499
+ $trigger = $('[data-wpt-name="' + trigger + '[skypename]"]', formID);
1500
+ }
1501
+
1502
+ if ($trigger.length < 1) {
1503
+ $trigger = $('[data-wpt-name="' + trigger + '[datepicker]"]', formID);
1504
+ }
1505
+
1506
+ if ($trigger.length < 1) {
1507
+ $trigger = $('[data-wpt-name="' + trigger + '[]"]', formID);
1508
+ }
1509
+
1510
+ if ($trigger.length > 0 && 'option' == $trigger.data('wpt-type')) {
1511
+ $trigger = $trigger.parent();
1512
+ }
1513
+
1514
+ if ($trigger.length < 1) {
1515
+ if( trigger.indexOf( 'cred-' ) == -1 )
1516
+ $trigger = typesCheckTrigger('cred-' + trigger, formID);
1517
+
1518
+
1519
+ return false;
1520
+ }
1521
+ return $trigger;
1522
+ }
1523
+
1524
+ if( typeof wptCondTriggers !== 'undefined' ) {
1525
+ _.each(wptCondTriggers, function (triggers, formID) {
1526
+ _.each(triggers, function (fields, trigger) {
1527
+ if( ! typesCheckTrigger(trigger, formID, trigger) ) {
1528
+ delete wptCondTriggers[formID][trigger];
1529
+ if( typeof wptCondFields !== 'undefined' ) {
1530
+ _.each( wptCondFields, function( fields, pageID ) {
1531
+ _.each( fields, function( field, fieldKey ) {
1532
+ _.each( field[ 'conditions' ], function( condition, conditionKey ) {
1533
+ if( condition[ 'id' ] == trigger ) {
1534
+ delete wptCondFields[ pageID ][ fieldKey ][ 'conditions' ][ conditionKey ];
1535
+ }
1536
+ } )
1537
+ } );
1538
+ } );
1539
+ }
1540
+ }
1541
+ });
1542
+ });
1543
+ }
1544
+
1545
+ if( typeof wptCondCustomTriggers !== 'undefined' ) {
1546
+ _.each( wptCondCustomTriggers, function( triggers, formID ) {
1547
+ _.each( triggers, function( fields, trigger ) {
1548
+ if( !typesCheckTrigger( trigger, formID, trigger ) ) {
1549
+ delete wptCondCustomTriggers[ formID ][ trigger ];
1550
+ }
1551
+ } );
1552
+ } );
1553
+ }
1554
+
1555
+ </script>
1556
+ <?php
1557
+ }
1558
+
1559
+ add_action( 'admin_print_footer_scripts', 'types_670', 100 );
embedded/classes/field/accessor/termmeta.php CHANGED
@@ -12,7 +12,10 @@ class WPCF_Field_Accessor_Termmeta extends WPCF_Field_Accessor_Abstract {
12
 
13
 
14
  public function get_raw_value() {
15
- return get_term_meta( $this->object_id, $this->meta_key, $this->is_single );
 
 
 
16
  }
17
 
18
  public function update_raw_value( $value, $prev_value = '' ) {
@@ -30,6 +33,7 @@ class WPCF_Field_Accessor_Termmeta extends WPCF_Field_Accessor_Abstract {
30
  return add_term_meta( $this->object_id, $this->meta_key, $value, $this->is_single );
31
  }
32
 
 
33
  /**
34
  * Delete field value from the database.
35
  *
12
 
13
 
14
  public function get_raw_value() {
15
+ // Since meta data (for posts and users, anyway) was historically loaded by get_*_meta() with $single = false,
16
+ // it always returned an array even for single fields. Keeping that for compatibility with toolset-forms and
17
+ // simplicity.
18
+ return get_term_meta( $this->object_id, $this->meta_key, false );
19
  }
20
 
21
  public function update_raw_value( $value, $prev_value = '' ) {
33
  return add_term_meta( $this->object_id, $this->meta_key, $value, $this->is_single );
34
  }
35
 
36
+
37
  /**
38
  * Delete field value from the database.
39
  *
embedded/classes/field/datamapper/abstract.php CHANGED
@@ -8,6 +8,9 @@
8
  *
9
  * The correct data mapper for a field is chosen in WPCF_Field_Definition::get_data_mapper().
10
  *
 
 
 
11
  * @since 1.9
12
  */
13
  abstract class WPCF_Field_DataMapper_Abstract {
8
  *
9
  * The correct data mapper for a field is chosen in WPCF_Field_Definition::get_data_mapper().
10
  *
11
+ * Note that data mappers do not deal with displaying field values (except in form inputs). To properly display a field,
12
+ * use one of existing renderers (WPCF_Field_Renderer_Factory) or create new one.
13
+ *
14
  * @since 1.9
15
  */
16
  abstract class WPCF_Field_DataMapper_Abstract {
embedded/classes/field/datamapper/checkboxes.php CHANGED
@@ -13,7 +13,7 @@ class WPCF_Field_DataMapper_Checkboxes extends WPCF_Field_DataMapper_Abstract {
13
  public function __construct( $field_definition ) {
14
  parent::__construct( $field_definition );
15
 
16
- if( $field_definition->get_type()->get_slug() != WPCF_Field_Definition::TYPE_CHECKBOXES ) {
17
  throw new InvalidArgumentException( 'Wrong field definition type.' );
18
  }
19
  }
@@ -37,12 +37,12 @@ class WPCF_Field_DataMapper_Checkboxes extends WPCF_Field_DataMapper_Abstract {
37
 
38
  $result = array();
39
 
40
- foreach( $options as $option_id => $ignored ) {
41
  $option_is_checked = isset( $value[ $option_id ] );
42
 
43
- if( $option_is_checked ) {
44
  $result[ $option_id ] = $value[ $option_id ];
45
- } else if( $this->field_definition->get_should_save_empty_value() ) {
46
  $result[ $option_id ] = 0;
47
  }
48
 
@@ -51,18 +51,4 @@ class WPCF_Field_DataMapper_Checkboxes extends WPCF_Field_DataMapper_Abstract {
51
  return $result;
52
  }
53
 
54
-
55
- /**
56
- * Since meta data (for posts and users, anyway) was historically loaded by get_*_meta() with $single = false,
57
- * it always returned an array even for single fields. New accessors don't do that - and we need to fix it
58
- * especially for checkboxes.
59
- *
60
- * @param array|mixed $value Expected array of checkboxes states, like
61
- * array( "unchecked_option_hash" => 0, "checked_option_hash" => array( 0 => "option_value" ) )
62
- *
63
- * @return array
64
- */
65
- public function database_to_intermediate( $value ) {
66
- return array( $value );
67
- }
68
  }
13
  public function __construct( $field_definition ) {
14
  parent::__construct( $field_definition );
15
 
16
+ if( $field_definition->get_type()->get_slug() != WPCF_Field_Type_Definition_Factory::CHECKBOXES ) {
17
  throw new InvalidArgumentException( 'Wrong field definition type.' );
18
  }
19
  }
37
 
38
  $result = array();
39
 
40
+ foreach ( $options as $option_id => $ignored ) {
41
  $option_is_checked = isset( $value[ $option_id ] );
42
 
43
+ if ( $option_is_checked ) {
44
  $result[ $option_id ] = $value[ $option_id ];
45
+ } else if ( $this->field_definition->get_should_save_empty_value() ) {
46
  $result[ $option_id ] = 0;
47
  }
48
 
51
  return $result;
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
embedded/classes/field/definition.php CHANGED
@@ -24,11 +24,6 @@ abstract class WPCF_Field_Definition extends WPCF_Field_Definition_Abstract {
24
  const FIELD_META_KEY_PREFIX = 'wpcf-';
25
 
26
 
27
- const TYPE_CHECKBOXES = 'checkboxes';
28
-
29
- const TYPE_CHECKBOX = 'checkbox';
30
-
31
-
32
  /**
33
  * @var WPCF_Field_Type_Definition Type definition.
34
  */
@@ -90,10 +85,18 @@ abstract class WPCF_Field_Definition extends WPCF_Field_Definition_Abstract {
90
  *
91
  * @param WPCF_Field_Type_Definition $type Field type definition.
92
  * @param array $definition_array The underlying array with complete information about this field.
 
 
93
  */
94
  public function __construct( $type, $definition_array ) {
 
 
 
 
 
95
  $this->type = $type;
96
- $this->definition_array = $definition_array;
 
97
 
98
  $this->slug = wpcf_getarr( $definition_array, 'slug' );
99
  if( sanitize_title( $this->slug ) != $this->slug ) {
@@ -202,6 +205,7 @@ abstract class WPCF_Field_Definition extends WPCF_Field_Definition_Abstract {
202
  * Stored in $cf['data']['set_save'].
203
  *
204
  * @return mixed|null The value or null if none is defined (make sure to compare with ===).
 
205
  */
206
  public function get_forced_value() {
207
  return wpcf_getnest( $this->definition_array, array( 'data', 'set_value' ), null );
@@ -224,10 +228,70 @@ abstract class WPCF_Field_Definition extends WPCF_Field_Definition_Abstract {
224
 
225
 
226
  /**
227
- * @return array An option_id => option_data array.
 
 
 
 
 
 
 
228
  */
229
  public function get_field_options() {
230
- return wpcf_ensarr( wpcf_getnest( $this->definition_array, array( 'data', 'options' ) ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  }
232
 
233
 
@@ -255,9 +319,9 @@ abstract class WPCF_Field_Definition extends WPCF_Field_Definition_Abstract {
255
  */
256
  public function get_data_mapper() {
257
  switch( $this->get_type()->get_slug() ) {
258
- case self::TYPE_CHECKBOXES:
259
  return new WPCF_Field_DataMapper_Checkboxes( $this );
260
- case self::TYPE_CHECKBOX:
261
  return new WPCF_Field_DataMapper_Checkbox( $this );
262
  default:
263
  return new WPCF_Field_DataMapper_Identity( $this );
@@ -272,4 +336,27 @@ abstract class WPCF_Field_Definition extends WPCF_Field_Definition_Abstract {
272
  */
273
  public abstract function delete_all_fields();
274
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  }
24
  const FIELD_META_KEY_PREFIX = 'wpcf-';
25
 
26
 
 
 
 
 
 
27
  /**
28
  * @var WPCF_Field_Type_Definition Type definition.
29
  */
85
  *
86
  * @param WPCF_Field_Type_Definition $type Field type definition.
87
  * @param array $definition_array The underlying array with complete information about this field.
88
+ * @throws InvalidArgumentException
89
+ * @since 1.9
90
  */
91
  public function __construct( $type, $definition_array ) {
92
+
93
+ if( ! $type instanceof WPCF_Field_Type_Definition ) {
94
+ throw new InvalidArgumentException( 'Invalid field type.' );
95
+ }
96
+
97
  $this->type = $type;
98
+
99
+ $this->definition_array = wpcf_ensarr( $definition_array );
100
 
101
  $this->slug = wpcf_getarr( $definition_array, 'slug' );
102
  if( sanitize_title( $this->slug ) != $this->slug ) {
205
  * Stored in $cf['data']['set_save'].
206
  *
207
  * @return mixed|null The value or null if none is defined (make sure to compare with ===).
208
+ * @since 1.9
209
  */
210
  public function get_forced_value() {
211
  return wpcf_getnest( $this->definition_array, array( 'data', 'set_value' ), null );
228
 
229
 
230
  /**
231
+ * Retrieve an array of option definitions.
232
+ *
233
+ * Allowed only for the checkboxes and radio field types.
234
+ *
235
+ * @throws RuntimeException when the field type is invalid
236
+ * @throws InvalidArgumentException when option definitions are corrupted
237
+ * @return WPCF_Field_Option_Checkboxes[] An option_id => option_data array.
238
+ * @since 1.9
239
  */
240
  public function get_field_options() {
241
+ $this->check_allowed_types(
242
+ array(
243
+ WPCF_Field_Type_Definition_Factory::CHECKBOXES,
244
+ WPCF_Field_Type_Definition_Factory::RADIO,
245
+ WPCF_Field_Type_Definition_Factory::SELECT
246
+ )
247
+ );
248
+ $options_definition = wpcf_ensarr( wpcf_getnest( $this->definition_array, array( 'data', 'options' ) ) );
249
+ $results = array();
250
+
251
+ $has_default = array_key_exists( 'default', $options_definition );
252
+ $default = wpcf_getarr( $options_definition, 'default', 'no-default' );
253
+ if( $has_default ) {
254
+ unset( $options_definition[ 'default' ] );
255
+ }
256
+
257
+ foreach( $options_definition as $option_id => $option_config ) {
258
+ try {
259
+ switch( $this->get_type()->get_slug() ) {
260
+ case WPCF_Field_Type_Definition_Factory::RADIO:
261
+ $option = new WPCF_Field_Option_Radio( $option_id, $option_config, $default, $this );
262
+ break;
263
+ case WPCF_Field_Type_Definition_Factory::SELECT:
264
+ $option = new WPCF_Field_Option_Select( $option_id, $option_config, $default, $this );
265
+ break;
266
+ case WPCF_Field_Type_Definition_Factory::CHECKBOXES:
267
+ $option = new WPCF_Field_Option_Checkboxes( $option_id, $option_config, $default );
268
+ break;
269
+ default:
270
+ throw new InvalidArgumentException( 'Invalid field type' );
271
+ }
272
+ $results[ $option_id ] = $option;
273
+ } catch( Exception $e ) {
274
+ // Corrupted data, can't do anything but skip the option.
275
+ }
276
+ }
277
+ return $results;
278
+ }
279
+
280
+
281
+ /**
282
+ * Determines whether the field should display both time and date or date only.
283
+ *
284
+ * Allowed field type: date.
285
+ *
286
+ * @throws RuntimeException
287
+ * @return string 'date'|'date_and_time' (note that for 'date_and_time' the actual value stored is 'and_time',
288
+ * we're translating it to sound more sensible)
289
+ * @since 1.9.1
290
+ */
291
+ public function get_datetime_option() {
292
+ $this->check_allowed_types( WPCF_Field_Type_Definition_Factory::DATE );
293
+ $value = wpcf_getnest( $this->definition_array, array( 'data', 'date_and_time' ) );
294
+ return ( 'and_time' == $value ? 'date_and_time' : 'date' );
295
  }
296
 
297
 
319
  */
320
  public function get_data_mapper() {
321
  switch( $this->get_type()->get_slug() ) {
322
+ case WPCF_Field_Type_Definition_Factory::CHECKBOXES:
323
  return new WPCF_Field_DataMapper_Checkboxes( $this );
324
+ case WPCF_Field_Type_Definition_Factory::CHECKBOX:
325
  return new WPCF_Field_DataMapper_Checkbox( $this );
326
  default:
327
  return new WPCF_Field_DataMapper_Identity( $this );
336
  */
337
  public abstract function delete_all_fields();
338
 
339
+
340
+ /**
341
+ * Throw a RuntimeException if current field type doesn't match the list of allowed ones.
342
+ *
343
+ * @param string|string[] $allowed_field_types Field type slugs
344
+ * @throws RuntimeException
345
+ * @since 1.9.1
346
+ */
347
+ protected function check_allowed_types( $allowed_field_types ) {
348
+
349
+ $allowed_field_types = wpcf_wraparr( $allowed_field_types );
350
+
351
+ if( !in_array( $this->type->get_slug(), $allowed_field_types ) ) {
352
+ throw new RuntimeException(
353
+ sprintf(
354
+ 'Invalid operation for this field type "%s", expected one of the following: %s.',
355
+ $this->type->get_slug(),
356
+ implode( ', ', $allowed_field_types )
357
+ )
358
+ );
359
+ }
360
+ }
361
+
362
  }
embedded/classes/field/instance_term.php CHANGED
@@ -9,6 +9,7 @@
9
  */
10
  final class WPCF_Field_Instance_Term extends WPCF_Field_Instance {
11
 
 
12
  /**
13
  * Add a single field value to the database.
14
  *
9
  */
10
  final class WPCF_Field_Instance_Term extends WPCF_Field_Instance {
11
 
12
+
13
  /**
14
  * Add a single field value to the database.
15
  *
embedded/classes/field/option_checkboxes.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Definition of a single option in checkboxes field.
5
+ *
6
+ * This should be exclusively used for accessing option properties and determining display value.
7
+ *
8
+ * @since 1.9.1
9
+ */
10
+ class WPCF_Field_Option_Checkboxes {
11
+
12
+
13
+ /** @var string Unique ID of the option. */
14
+ private $option_id;
15
+
16
+ /**
17
+ * @var string[] Option configuration:
18
+ *
19
+ * - title => Label for the option (when entering data)
20
+ * - set_value => Value to be stored in database when this option is selected
21
+ * - display => Display mode, either 'db' for displaying raw database value or 'value' for displaying
22
+ * custom values (below)
23
+ * - display_value_selected
24
+ * - display_value_not_selected
25
+ */
26
+ protected $config;
27
+
28
+
29
+ /**
30
+ * WPCF_Field_Value_Option constructor.
31
+ *
32
+ * @param string $option_id Unique ID of the option.
33
+ * @param string[] $config Option configuration.
34
+ * @param string $default Default field value
35
+ */
36
+ public function __construct( $option_id, $config, $default ) {
37
+
38
+ if( !is_string( $option_id ) || empty( $option_id ) ) {
39
+ throw new InvalidArgumentException( 'Invalid option ID.' );
40
+ }
41
+ $this->option_id = $option_id;
42
+
43
+ if( !is_array( $config ) ) {
44
+ throw new InvalidArgumentException( 'Invalid option configuration.' );
45
+ }
46
+ $this->config = $config;
47
+ }
48
+
49
+
50
+ /**
51
+ * @param array $field_value Checkboxes field value in the "intermediate" format.
52
+ * @return bool Whether this option is checked in the field whose value is provided.
53
+ * @since 1.9.1
54
+ */
55
+ public function is_option_checked( $field_value ) {
56
+ // Value that should be stored in database if this option is checked
57
+ $option_value = wpcf_getnest( $field_value, array( $this->option_id, 0 ), null );
58
+ $is_checked = ( null !== $option_value && $this->get_value_to_store() == $option_value );
59
+ return $is_checked;
60
+ }
61
+
62
+
63
+ /**
64
+ * @return string Option label.
65
+ * @since 1.9.1
66
+ */
67
+ public function get_label() {
68
+ $value = wpcf_getarr( $this->config, 'title' );
69
+ if( !is_string( $value ) ) {
70
+ $value = '';
71
+ }
72
+
73
+ return sanitize_text_field( $value );
74
+ }
75
+
76
+
77
+ /**
78
+ * Determine value to be displayed for this option.
79
+ *
80
+ * @param bool $is_checked For which value should the output be rendered.
81
+ * @return string Display value depending on option definition. For unselected options in 'db' mode, empty string
82
+ * will be returned disregarding the field's "save zero to database" option.
83
+ * @since 1.9.1
84
+ */
85
+ public function get_display_value( $is_checked = true ) {
86
+ $display_mode = wpcf_getarr( $this->config, 'display', 'db', array( 'value', 'db' ) );
87
+ if( 'db' == $display_mode ) {
88
+ return ( $is_checked ? $this->get_value_to_store() : '' );
89
+ } else {
90
+ if ( $is_checked ) {
91
+ return wpcf_getarr( $this->config, 'display_value_selected' );
92
+ } else {
93
+ return wpcf_getarr( $this->config, 'display_value_not_selected' );
94
+ }
95
+ }
96
+ }
97
+
98
+
99
+ /**
100
+ * @return string Value that should be stored to database when this option is selected.
101
+ * @since 1.9.1
102
+ */
103
+ public function get_value_to_store() {
104
+ $value = wpcf_getarr( $this->config, 'set_value' );
105
+ if( !is_string( $value ) ) {
106
+ return '';
107
+ }
108
+
109
+ return $value;
110
+ }
111
+
112
+ }
embedded/classes/field/option_radio.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Definition of a single option in radio field.
5
+ *
6
+ * This should be exclusively used for accessing option properties and determining display value.
7
+ *
8
+ * @since 1.9.1
9
+ */
10
+ class WPCF_Field_Option_Radio extends WPCF_Field_Option_Checkboxes {
11
+
12
+ /* $config difference in comparison with checkboxes field option:
13
+ * - instead of 'set_value', the value to be stored in database for selected option has the key 'value'
14
+ */
15
+
16
+ /** @var WPCF_Field_Definition */
17
+ private $field_definition;
18
+
19
+
20
+ public function __construct( $option_id, $config, $default, $field_definition ) {
21
+ parent::__construct( $option_id, $config, $default );
22
+ $this->field_definition = $field_definition;
23
+ }
24
+
25
+ /**
26
+ * @return string Value that should be stored to database when this option is selected.
27
+ * @since 1.9.1
28
+ */
29
+ public function get_value_to_store() {
30
+ $value = wpcf_getarr( $this->config, 'value' );
31
+ if( !is_string( $value ) ) {
32
+ return '';
33
+ }
34
+
35
+ return $value;
36
+ }
37
+
38
+
39
+ /**
40
+ * Determine value to be displayed for this option.
41
+ *
42
+ * @param bool $is_checked For which value should the output be rendered.
43
+ * @return string Display value depending on option definition and field display mode
44
+ * @since 1.9.1
45
+ */
46
+ public function get_display_value( $is_checked = true ) {
47
+ $field_definition_array = $this->field_definition->get_definition_array();
48
+ $display_mode = wpcf_getnest( $field_definition_array, array( 'data', 'display' ), 'db' );
49
+ $display_mode = ( 'value' == $display_mode ? 'value' : 'db' );
50
+
51
+ if( 'db' == $display_mode ) {
52
+ return ( $is_checked ? $this->get_value_to_store() : '' );
53
+ } else {
54
+ if ( $is_checked ) {
55
+ return wpcf_getarr( $this->config, 'display_value' );
56
+ } else {
57
+ return '';
58
+ }
59
+ }
60
+ }
61
+
62
+ }
embedded/classes/field/option_select.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Definition of a single option in select field.
5
+ *
6
+ * This should be exclusively used for accessing option properties and determining display value.
7
+ *
8
+ * @since 1.9.1
9
+ */
10
+ final class WPCF_Field_Option_Select extends WPCF_Field_Option_Radio {
11
+
12
+
13
+ /**
14
+ * Determine value to be displayed for this option.
15
+ *
16
+ * @param bool $is_checked For which value should the output be rendered.
17
+ * @return string Display value depending on option definition and field display mode
18
+ * @since 1.9.1
19
+ */
20
+ public function get_display_value( $is_checked = true ) {
21
+ if( $is_checked ) {
22
+ return $this->get_value_to_store();
23
+ } else {
24
+ return '';
25
+ }
26
+ }
27
+ }
embedded/classes/field/renderer/abstract.php CHANGED
@@ -7,6 +7,8 @@ abstract class WPCF_Field_Renderer_Abstract {
7
  protected $field = null;
8
 
9
  public function __construct( $field ) {
 
 
10
  $this->field = $field;
11
  }
12
 
7
  protected $field = null;
8
 
9
  public function __construct( $field ) {
10
+
11
+ // todo sanitize
12
  $this->field = $field;
13
  }
14
 
embedded/classes/field/renderer/factory.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Factory for field renderers.
5
+ *
6
+ * This is especially useful because in most cases different types of fields have to use different renderers in
7
+ * different context. The logic for choosing the right renderer should be completely encapsulated in this class.
8
+ *
9
+ * @since 1.9.1
10
+ */
11
+ final class WPCF_Field_Renderer_Factory {
12
+
13
+ private static $instance = null;
14
+
15
+ private function __construct() { }
16
+
17
+ public static function get_instance() {
18
+ if( null == self::$instance ) {
19
+ self::$instance = new self();
20
+ }
21
+ return self::$instance;
22
+ }
23
+
24
+
25
+ /**
26
+ * Get a preview renderer for given field.
27
+ *
28
+ * @param WPCF_Field_Instance_Abstract $field
29
+ * @param array $args Arguments for the preview renderer.
30
+ * @return WPCF_Field_Renderer_Preview_Base Preview renderer for a specific field.
31
+ * @throws InvalidArgumentException
32
+ * @since 1.9.1
33
+ */
34
+ public function create_preview_renderer( $field, $args = array() ) {
35
+
36
+ if( ! $field instanceof WPCF_Field_Instance_Abstract ) {
37
+ throw new InvalidArgumentException( 'Not a field instance.' );
38
+ }
39
+
40
+ if( ! is_array( $args ) ) {
41
+ throw new InvalidArgumentException( 'Not an array.' );
42
+ }
43
+
44
+ $field_type = $field->get_field_type();
45
+ switch( $field_type->get_slug() ) {
46
+
47
+ case WPCF_Field_Type_Definition_Factory::GOOGLE_ADDRESS:
48
+ return new WPCF_Field_Renderer_Preview_Address( $field, $args );
49
+
50
+ case WPCF_Field_Type_Definition_Factory::AUDIO:
51
+ case WPCF_Field_Type_Definition_Factory::FILE:
52
+ case WPCF_Field_Type_Definition_Factory::VIDEO:
53
+ return new WPCF_Field_Renderer_Preview_File( $field, $args );
54
+
55
+ case WPCF_Field_Type_Definition_Factory::COLORPICKER:
56
+ return new WPCF_Field_Renderer_Preview_Colorpicker( $field, $args );
57
+
58
+ case WPCF_Field_Type_Definition_Factory::DATE:
59
+ return new WPCF_Field_Renderer_Preview_Date( $field, $args );
60
+
61
+ case WPCF_Field_Type_Definition_Factory::EMBED:
62
+ case WPCF_Field_Type_Definition_Factory::URL:
63
+ return new WPCF_Field_Renderer_Preview_URL( $field, $args );
64
+
65
+ case WPCF_Field_Type_Definition_Factory::CHECKBOX:
66
+ return new WPCF_Field_Renderer_Preview_Checkbox( $field, $args );
67
+
68
+ case WPCF_Field_Type_Definition_Factory::CHECKBOXES:
69
+ return new WPCF_Field_Renderer_Preview_Checkboxes( $field, $args );
70
+
71
+ case WPCF_Field_Type_Definition_Factory::IMAGE:
72
+ return new WPCF_Field_Renderer_Preview_Image( $field, $args );
73
+
74
+ case WPCF_Field_Type_Definition_Factory::RADIO:
75
+ case WPCF_Field_Type_Definition_Factory::SELECT:
76
+ return new WPCF_Field_Renderer_Preview_Radio( $field, $args );
77
+
78
+ case WPCF_Field_Type_Definition_Factory::SKYPE:
79
+ return new WPCF_Field_Renderer_Preview_Skype( $field, $args );
80
+
81
+ default:
82
+ return new WPCF_Field_Renderer_Preview_Textfield( $field, $args );
83
+ break;
84
+ }
85
+ }
86
+ }
embedded/classes/field/renderer/preview/address.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Google address preview renderer.
5
+ *
6
+ * Displays excerpt of the address with a link to Google Maps.
7
+ *
8
+ * @since 1.9.1
9
+ */
10
+ final class WPCF_Field_Renderer_Preview_Address extends WPCF_Field_Renderer_Preview_Base {
11
+
12
+ /**
13
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
14
+ *
15
+ * @return string Rendered HTML
16
+ */
17
+ protected function render_single( $value ) {
18
+
19
+ if( !is_string( $value ) ) {
20
+ return '';
21
+ }
22
+
23
+ $label = $value;
24
+
25
+ // Keep maximum length per item
26
+ $max_length = $this->get_maximum_item_length();
27
+ if( 0 < $max_length && $max_length < strlen( $label ) ) {
28
+ $label = substr( $label, 0, $max_length - 3 ) . '...';
29
+ }
30
+
31
+ $link = sprintf(
32
+ '<a target="_blank" href="http://maps.google.com/?q=%s">%s</a>',
33
+ esc_attr( $value ),
34
+ sanitize_text_field( $label )
35
+ );
36
+
37
+ return $link;
38
+ }
39
+
40
+
41
+ protected function get_maximum_total_length() {
42
+ return 0;
43
+ }
44
+
45
+ }
embedded/classes/field/renderer/preview/base.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Base for preview renderer fields.
5
+ *
6
+ * Preview renderers are to be used mainly in admin, for example in post/user/term listings. Their task is to really
7
+ * render a simple preview for the value, nothing more. In some cases the output may not even contain the complete
8
+ * information (e.g. lots of images in a repetitive field).
9
+ *
10
+ * This class handles displaying repetitive fields, other preview renderers are supposed to inherit from it and
11
+ * implement only the render_single() method.
12
+ *
13
+ * @since 1.9.1
14
+ */
15
+ abstract class WPCF_Field_Renderer_Preview_Base extends WPCF_Field_Renderer_Abstract {
16
+
17
+
18
+ protected $args;
19
+
20
+
21
+ /**
22
+ * WPCF_Field_Renderer_Preview_Base constructor.
23
+ *
24
+ * @param WPCF_Field_Instance_Abstract $field
25
+ * @param array $args Preview renderer settings:
26
+ * - maximum_item_count => Maximum count of field values that should be displayed.
27
+ * - maximum_item_length => Maximum length of single item.
28
+ * - value_separator => Separator to be used between multiple field values.
29
+ * - ellipsis => Ellipsis to be added when some field values are omitted.
30
+ *
31
+ * Specialized renderers may interpret the settings in a different way or add their own.
32
+ *
33
+ * @since 1.9.1
34
+ */
35
+ public function __construct( $field, $args = array() ) {
36
+ parent::__construct( $field );
37
+
38
+ $this->args = wpcf_ensarr( $args );
39
+ }
40
+
41
+ /**
42
+ * Render the field value. Handle both single and repetitive fields.
43
+ *
44
+ * Rendering of a single value is defined in render_single() and multiple values are concatenated by
45
+ * separator provided by get_value_separator().
46
+ *
47
+ * @param bool $echo Echo the output?
48
+ * @return string Rendered HTML.
49
+ * @since 1.9.1
50
+ */
51
+ public function render( $echo = false ) {
52
+
53
+ $field_value = $this->field->get_value();
54
+
55
+ // Handle all fields as repetitive, we allways have array of individual field values.
56
+ $output_values = array();
57
+
58
+ // Optionally limit the number of rendered items
59
+ $max_item_count = $this->get_maximum_item_count();
60
+ $loop_limit = (
61
+ $max_item_count > 0
62
+ ? min( $max_item_count, count( $field_value ) )
63
+ : count( $field_value )
64
+ );
65
+
66
+ $is_limited_by_max_count = ( $loop_limit < count( $field_value ) );
67
+ for( $i = 0; $i < $loop_limit; ++$i ) {
68
+ $value = array_shift( $field_value );
69
+ $output_values[] = $this->render_single( $value );
70
+ }
71
+
72
+ $output = implode( $this->get_value_separator(), $output_values );
73
+
74
+ $maximum_total_length = $this->get_maximum_total_length();
75
+ $is_limited_by_max_total_length = ( 0 < $maximum_total_length && $maximum_total_length < strlen( $output ) );
76
+ if( $is_limited_by_max_total_length ) {
77
+ $output = substr( $output, 0, $maximum_total_length );
78
+ }
79
+
80
+ $needs_ellipsis = ( $is_limited_by_max_count || $is_limited_by_max_total_length );
81
+ if( $needs_ellipsis ) {
82
+ $output .= $this->get_ellipsis();
83
+ }
84
+
85
+ if( $echo ) {
86
+ echo $output;
87
+ }
88
+
89
+ return $output;
90
+ }
91
+
92
+
93
+ /**
94
+ * @return string Separator to be used between multiple field values.
95
+ */
96
+ protected function get_value_separator() {
97
+ return wpcf_getarr( $this->args, 'value_separator', ', ' );
98
+ }
99
+
100
+
101
+ /**
102
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
103
+ * @return string Rendered HTML
104
+ */
105
+ protected abstract function render_single( $value );
106
+
107
+
108
+ /**
109
+ * @return int Maximum count of field values that should be displayed. Zero means no limit.
110
+ * @since 1.9.1
111
+ */
112
+ protected function get_maximum_item_count() {
113
+ return absint( wpcf_getarr( $this->args, 'maximum_item_count' ) );
114
+ }
115
+
116
+
117
+ /**
118
+ * @return int Maximum length of single item. Interpretation depends on specific renderer (on a field type); it
119
+ * may be completely ignored. Zero means no limit.
120
+ * @since 1.9.1
121
+ */
122
+ protected function get_maximum_item_length() {
123
+ return absint( wpcf_getarr( $this->args, 'maximum_item_length' ) );
124
+ }
125
+
126
+
127
+ /**
128
+ * @return int Maximum length of the final output. Zero means no limit. When some HTML is rendered, this method
129
+ * needs to be overridden to allways return zero, otherwise the markup might be broken.
130
+ * @since 1.9.1
131
+ */
132
+ protected function get_maximum_total_length() {
133
+ return absint( wpcf_getarr( $this->args, 'maximum_total_length' ) );
134
+ }
135
+
136
+
137
+
138
+ /**
139
+ * @return string Ellipsis to be added when some field values are omitted.
140
+ * @since 1.9.1
141
+ */
142
+ protected function get_ellipsis() {
143
+ return wpcf_getarr( $this->args, 'ellipsis', $this->get_value_separator() . '...' );
144
+ }
145
+
146
+ }
embedded/classes/field/renderer/preview/checkbox.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Checkbox field preview renderer.
5
+ *
6
+ * Displays a check mark for checked field (when it has the proper value, not just nonzero one). Otherwise, display nothing.
7
+ *
8
+ * @since 1.9.1
9
+ */
10
+ final class WPCF_Field_Renderer_Preview_Checkbox extends WPCF_Field_Renderer_Preview_Base {
11
+
12
+
13
+ /**
14
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
15
+ *
16
+ * @return string Rendered HTML
17
+ */
18
+ protected function render_single( $value ) {
19
+
20
+ $value_of_checked = $this->field->get_definition()->get_forced_value();
21
+ if( null != $value_of_checked && $value_of_checked == $value ) {
22
+ return '&#10004;'; // ballot box with check - checkbox - checkmark - miscellaneous symbols
23
+ }
24
+
25
+ // We may not even get here without the checkbox being checked (when no value is saved to database)
26
+ return '';
27
+ }
28
+
29
+
30
+ protected function get_maximum_total_length() {
31
+ return 0;
32
+ }
33
+
34
+ }
embedded/classes/field/renderer/preview/checkboxes.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Preview renderer for checkboxes field.
5
+ *
6
+ * @since 1.9.1
7
+ */
8
+ final class WPCF_Field_Renderer_Preview_Checkboxes extends WPCF_Field_Renderer_Preview_Base {
9
+
10
+ /**
11
+ * Render preview for whole checkboxes field. Slightly confusingly, checkboxes fields are allways single
12
+ * and all options are part of one field value.
13
+ *
14
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
15
+ *
16
+ * @return string Rendered HTML
17
+ */
18
+ protected function render_single( $value ) {
19
+
20
+ $options = $this->field->get_definition()->get_field_options();
21
+ $output = array();
22
+
23
+ // Let each checkbox option definition handle how it should be displayed.
24
+ foreach( $options as $option ) {
25
+ $display_value = ( $option->is_option_checked( $value ) ? $option->get_label() : '' );
26
+ if( !empty( $display_value ) ) {
27
+ $output[] = $display_value;
28
+ }
29
+ }
30
+
31
+ // Apply maximum count here
32
+ $max_item_count = $this->get_maximum_item_count();
33
+ $is_limited_by_max_count = ( 0 < $max_item_count && $max_item_count < count( $output ) );
34
+ if( $is_limited_by_max_count ) {
35
+ $output = array_slice( $output, 0, $this->get_maximum_item_count() );
36
+ }
37
+
38
+ $output = implode( $this->get_value_separator(), $output );
39
+
40
+ if( $is_limited_by_max_count ) {
41
+ $output .= $this->get_ellipsis();
42
+ }
43
+
44
+ return sanitize_text_field( $output );
45
+ }
46
+
47
+
48
+ }
embedded/classes/field/renderer/preview/colorpicker.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Preview renderer for colorpicker fields.
5
+ *
6
+ * @since 1.9.1
7
+ */
8
+ final class WPCF_Field_Renderer_Preview_Colorpicker extends WPCF_Field_Renderer_Preview_Base {
9
+
10
+
11
+ /**
12
+ * Display a small box filled with selected colour and colour hex code as a title on hover.
13
+ *
14
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
15
+ *
16
+ * @return string Rendered HTML
17
+ */
18
+ protected function render_single( $value ) {
19
+
20
+ $is_valid_hex_color = preg_match('/^#([a-f0-9]{3}){1,2}$/i', $value );
21
+ if( ! $is_valid_hex_color ) {
22
+ return '';
23
+ }
24
+
25
+ $result = sprintf(
26
+ '<div style="background-color: %s; display: inline-block; width: 1em; height: 1em; border: 1px grey solid;" title="%s"></div>',
27
+ $value,
28
+ $value
29
+ );
30
+
31
+ return $result;
32
+ }
33
+
34
+
35
+ protected function get_value_separator() {
36
+ return '&nbsp;';
37
+ }
38
+
39
+
40
+ /**
41
+ * @inheritdoc
42
+ * @return int
43
+ */
44
+ protected function get_maximum_total_length() {
45
+ return 0;
46
+ }
47
+
48
+ }
embedded/classes/field/renderer/preview/date.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class WPCF_Field_Renderer_Preview_Date extends WPCF_Field_Renderer_Preview_Base {
4
+
5
+ /**
6
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
7
+ *
8
+ * @return string Rendered HTML
9
+ */
10
+ protected function render_single( $value ) {
11
+
12
+ $timestamp = (int) $value;
13
+
14
+ // Skip empty values
15
+ if( 0 == $timestamp ) {
16
+ return '';
17
+ }
18
+
19
+ $output = date( get_option( 'date_format' ), $timestamp );
20
+
21
+ $add_time = ( $this->field->get_definition()->get_datetime_option() == 'date_and_time' );
22
+ if( $add_time ) {
23
+ $output .= ' ' . date( get_option( 'time_format' ), $timestamp );
24
+ }
25
+
26
+ return sanitize_text_field( $output );
27
+ }
28
+
29
+
30
+ /**
31
+ * @inheritdoc
32
+ *
33
+ * @return string
34
+ */
35
+ protected function get_value_separator() {
36
+ // Semicolon is less likely to cause conflicts with date and time formats.
37
+ return '; ';
38
+ }
39
+
40
+ }
embedded/classes/field/renderer/preview/file.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Preview renderer for all "file" fields.
5
+ *
6
+ * By file field it is meant those fields that contain URL to any (generic) file. The result is the same as for
7
+ * URL field, but with only filename being displayed as a link label.
8
+ *
9
+ * @since 1.9.1
10
+ */
11
+ final class WPCF_Field_Renderer_Preview_File extends WPCF_Field_Renderer_Preview_URL {
12
+
13
+ /**
14
+ * @param string[] $url_components Result of parse_url().
15
+ * @return string Label of the resulting link.
16
+ * @since 1.9.1
17
+ */
18
+ protected function get_link_label( $url_components ) {
19
+
20
+ $file_name = sanitize_text_field( basename( wpcf_getarr( $url_components, 'path' ) ) );
21
+
22
+ return $file_name;
23
+ }
24
+
25
+ }
embedded/classes/field/renderer/preview/image.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Preview renderer for image fields.
5
+ *
6
+ * Tries to be clever about WP attachments and use thumbnails instead of full size images whenever possible.
7
+ *
8
+ * For displaying the full image on clicking on the preview, you need to enqueue the 'wpcf-js' script and
9
+ * the 'wptoolset-forms-admin' style
10
+ *
11
+ * @since 1.9.1
12
+ */
13
+ final class WPCF_Field_Renderer_Preview_Image extends WPCF_Field_Renderer_Preview_Base {
14
+
15
+
16
+ /** Maximum width and height of an image. */
17
+ const DEFAULT_MAX_IMAGE_SIZE = '60px';
18
+
19
+
20
+ /**
21
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
22
+ *
23
+ * @return string Rendered HTML
24
+ */
25
+ protected function render_single( $value ) {
26
+
27
+ if( !is_string( $value ) ) {
28
+ return '';
29
+ }
30
+
31
+ $original_image_url = $value;
32
+ $image_url = $this->try_finding_attachment( $original_image_url );
33
+ $image_size = esc_attr( $this->get_maximum_image_size() );
34
+
35
+ $output = sprintf(
36
+ '<div class="js-wpt-file-preview wpt-file-preview">
37
+ <img src="%s" style="max-width: %s; max-height: %s; border: 1px grey solid;" data-full-src="%s" />
38
+ </div>',
39
+ esc_url( $image_url ),
40
+ $image_size,
41
+ $image_size,
42
+ esc_url( $original_image_url )
43
+ );
44
+
45
+ return $output;
46
+ }
47
+
48
+
49
+ /**
50
+ * For given URL, try to find an attachment with this file and if successful, try finding thumbnail URL.
51
+ *
52
+ * Returns original URL on failure.
53
+ *
54
+ * @param string $url Image URL
55
+ * @return string URl of the thumbnail or original image.
56
+ * @since 1.9.1
57
+ */
58
+ protected function try_finding_attachment( $url ) {
59
+ $attachment_id = WPCF_Utils::get_attachment_id_by_url( $url );
60
+ if( 0 == $attachment_id ) {
61
+ return $url;
62
+ }
63
+
64
+ $attachment_src = wp_get_attachment_image_src( $attachment_id, 'thumbnail' );
65
+ if( false == $attachment_src ) {
66
+ return $url;
67
+ }
68
+
69
+ return ( is_string( $attachment_src[0] ) ? $attachment_src[0] : $url );
70
+ }
71
+
72
+
73
+ protected function get_value_separator() {
74
+ return '&nbsp;';
75
+ }
76
+
77
+
78
+ protected function get_maximum_image_size() {
79
+ return wpcf_getarr( $this->args, 'maximum_image_size', self::DEFAULT_MAX_IMAGE_SIZE );
80
+ }
81
+
82
+ /**
83
+ * @inheritdoc
84
+ * @return int
85
+ */
86
+ protected function get_maximum_total_length() {
87
+ return 0;
88
+ }
89
+
90
+ }
embedded/classes/field/renderer/preview/radio.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * Preview renderer for radio fields.
6
+ *
7
+ * @since 1.9.1
8
+ */
9
+ final class WPCF_Field_Renderer_Preview_Radio extends WPCF_Field_Renderer_Preview_Base {
10
+
11
+ /**
12
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
13
+ *
14
+ * @return string Rendered HTML
15
+ */
16
+ protected function render_single( $value ) {
17
+
18
+ $option = $this->get_option_for_value( $value );
19
+ if( null == $option ) {
20
+ return '';
21
+ }
22
+
23
+ $output = $option->get_label();
24
+
25
+ return sanitize_text_field( $output );
26
+ }
27
+
28
+
29
+ /**
30
+ * Get radio field option definition from field value.
31
+ *
32
+ * @param string $value Value stored in the database.
33
+ * @return WPCF_Field_Option_Radio Corresponding option definition.
34
+ */
35
+ private function get_option_for_value( $value ) {
36
+ $options = $this->field->get_definition()->get_field_options();
37
+ foreach( $options as $option ) {
38
+ if( $value == $option->get_value_to_store() ) {
39
+ return $option;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+
45
+ }
embedded/classes/field/renderer/preview/skype.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Preview renderer for Skype fields.
5
+ *
6
+ * @since 1.9.1
7
+ */
8
+ final class WPCF_Field_Renderer_Preview_Skype extends WPCF_Field_Renderer_Preview_Base {
9
+
10
+
11
+ /**
12
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
13
+ *
14
+ * @return string Rendered HTML
15
+ */
16
+ protected function render_single( $value ) {
17
+ // Simply get the Skype name.
18
+ $skype_name = wpcf_getarr( $value, 'skypename' );
19
+ $skype_name = is_string( $skype_name ) ? $skype_name : '';
20
+ return sanitize_text_field( $skype_name );
21
+ }
22
+
23
+
24
+ }
embedded/classes/field/renderer/preview/textfield.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Render preview of a single field or other field type that doesn't require any additional processing.
5
+ *
6
+ * @since 1.9.1
7
+ */
8
+ class WPCF_Field_Renderer_Preview_Textfield extends WPCF_Field_Renderer_Preview_Base {
9
+
10
+
11
+ /**
12
+ * @param mixed $value Single field value.
13
+ * @return string Sanitized field value. If the value is not a string, this will result into an empty string.
14
+ */
15
+ protected function render_single( $value ) {
16
+ if( !is_string( $value ) ) {
17
+ $value = '';
18
+ }
19
+
20
+ $value = sanitize_text_field( $value );
21
+
22
+ // Keep maximum length per item
23
+ $max_length = $this->get_maximum_item_length();
24
+ if( 0 < $max_length && $max_length < strlen( $value ) ) {
25
+ $value = substr( $value, 0, $max_length - 3 ) . '...';
26
+ }
27
+
28
+ return $value;
29
+ }
30
+
31
+ }
embedded/classes/field/renderer/preview/url.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WPCF_Field_Renderer_Preview_URL extends WPCF_Field_Renderer_Preview_Base {
4
+
5
+ /**
6
+ * @param mixed $value Single field value in the intermediate format (see data mappers for details)
7
+ *
8
+ * @return string Rendered HTML
9
+ */
10
+ protected function render_single( $value ) {
11
+
12
+ if( is_string( $value ) && !empty( $value ) ) {
13
+
14
+ $url_components = parse_url( $value );
15
+ if( false == $url_components ) {
16
+ return '';
17
+ }
18
+
19
+ $label = $this->get_link_label( $url_components );
20
+
21
+ // Apply maximum item length on the link label, not the whole output
22
+ $max_length = $this->get_maximum_item_length();
23
+ if( 0 < $max_length && $max_length < strlen( $label ) ) {
24
+ $label = substr( $label, 0, $max_length - 3 ) . '...';
25
+ }
26
+
27
+ // Build the actual link
28
+ $link = sprintf(
29
+ '<a href="%s" target="_blank">%s</a>',
30
+ esc_url( $value ),
31
+ sanitize_text_field( $label )
32
+ );
33
+
34
+ return $link;
35
+ } else {
36
+ return '';
37
+ }
38
+ }
39
+
40
+
41
+ protected function get_maximum_total_length() {
42
+ return 0;
43
+ }
44
+
45
+
46
+ /**
47
+ * @param string[] $url_components Result of parse_url().
48
+ * @return string Label of the resulting link.
49
+ * @since 1.9.1
50
+ */
51
+ protected function get_link_label( $url_components ) {
52
+
53
+ // Build link label only from host, path and query.
54
+ $url_query = wpcf_getarr( $url_components, 'query' );
55
+ $url_query = ( empty( $url_query ) ? '' : '?' . $url_query );
56
+
57
+ $url_path = wpcf_getarr( $url_components, 'path' );
58
+ if( empty( $url_query ) ) {
59
+ // Omit last slash when it would be the last label character
60
+ $url_path = substr( $url_path, 0, strlen( $url_path ) -1 );
61
+ }
62
+
63
+ $label = sprintf(
64
+ '%s%s%s',
65
+ wpcf_getarr( $url_components, 'host' ),
66
+ $url_path,
67
+ $url_query
68
+ );
69
+
70
+ return $label;
71
+ }
72
+
73
+ }
embedded/classes/field/type_definition_factory.php CHANGED
@@ -8,9 +8,26 @@
8
  * Currently it is only possible to load existing field types, not create new ones. We're depending on the legacy code
9
  * in WPCF_Fields and field types defined through specially named functions. But that is hidden from anyone who uses
10
  * this class.
 
 
11
  */
12
  final class WPCF_Field_Type_Definition_Factory {
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  private static $instance = null;
15
 
16
  private function __construct() { }
@@ -67,20 +84,24 @@ final class WPCF_Field_Type_Definition_Factory {
67
  }
68
 
69
  // Check if we can use cached version.
70
- if( !in_array( $field_type_slug, $this->field_type_definitions ) ) {
71
 
72
  // now it gets hacky
73
  $field_types = $this->get_legacy_field_types();
74
- if( !in_array( $field_type_slug, array_keys( $field_types ) ) ) {
75
  // Field slug not recognized. Maybe we got a field identifier instead. Check if we can remove
76
  // the wpcf- prefix and try again.
77
  $prefix = 'wpcf-';
78
  if( substr( $field_type_slug, 0, strlen( $prefix ) ) == $prefix ) {
79
  $field_type_slug = substr( $field_type_slug, strlen( $prefix ) );
80
- if( !in_array( $field_type_slug, $field_types ) ) {
81
  // Removing prefix didn't help
82
  return null;
83
  }
 
 
 
 
84
  } else {
85
  // There was no prefix to remove.
86
  return null;
8
  * Currently it is only possible to load existing field types, not create new ones. We're depending on the legacy code
9
  * in WPCF_Fields and field types defined through specially named functions. But that is hidden from anyone who uses
10
  * this class.
11
+ *
12
+ * @since 1.9
13
  */
14
  final class WPCF_Field_Type_Definition_Factory {
15
 
16
+ const AUDIO = 'audio';
17
+ const COLORPICKER = 'colorpicker';
18
+ const DATE = 'date';
19
+ const EMBED = 'embed';
20
+ const FILE = 'file';
21
+ const GOOGLE_ADDRESS = 'google_address';
22
+ const CHECKBOX = 'checkbox';
23
+ const CHECKBOXES = 'checkboxes';
24
+ const IMAGE = 'image';
25
+ const RADIO = 'radio';
26
+ const SELECT = 'select';
27
+ const SKYPE = 'skype';
28
+ const URL = 'url';
29
+ const VIDEO = 'video';
30
+
31
  private static $instance = null;
32
 
33
  private function __construct() { }
84
  }
85
 
86
  // Check if we can use cached version.
87
+ if( !array_key_exists( $field_type_slug, $this->field_type_definitions ) ) {
88
 
89
  // now it gets hacky
90
  $field_types = $this->get_legacy_field_types();
91
+ if( !array_key_exists( $field_type_slug, $field_types ) ) {
92
  // Field slug not recognized. Maybe we got a field identifier instead. Check if we can remove
93
  // the wpcf- prefix and try again.
94
  $prefix = 'wpcf-';
95
  if( substr( $field_type_slug, 0, strlen( $prefix ) ) == $prefix ) {
96
  $field_type_slug = substr( $field_type_slug, strlen( $prefix ) );
97
+ if( !array_key_exists( $field_type_slug, $field_types ) ) {
98
  // Removing prefix didn't help
99
  return null;
100
  }
101
+ // Check the cache again (now with correct slug).
102
+ if( array_key_exists( $field_type_slug, $this->field_type_definitions ) ) {
103
+ return $this->field_type_definitions[ $field_type_slug ];
104
+ }
105
  } else {
106
  // There was no prefix to remove.
107
  return null;
embedded/classes/field/utils.php CHANGED
@@ -20,7 +20,7 @@ final class WPCF_Field_Utils {
20
  */
21
  public static function create_term_field_instance( $field_slug, $term_id ) {
22
  try {
23
- return new WPCF_Field_Instance( WPCF_Field_Term_Definition_Factory::load( $field_slug ), $term_id );
24
  } catch( Exception $e ) {
25
  return null;
26
  }
@@ -62,5 +62,4 @@ final class WPCF_Field_Utils {
62
  }
63
  return $field_definitions;
64
  }
65
-
66
  }
20
  */
21
  public static function create_term_field_instance( $field_slug, $term_id ) {
22
  try {
23
+ return new WPCF_Field_Instance_Term( WPCF_Field_Term_Definition_Factory::load( $field_slug ), $term_id );
24
  } catch( Exception $e ) {
25
  return null;
26
  }
62
  }
63
  return $field_definitions;
64
  }
 
65
  }
embedded/classes/gui/term_field_editing.php CHANGED
@@ -47,6 +47,7 @@ final class WPCF_GUI_Term_Field_Editing {
47
 
48
  $is_toolset_forms_support_needed = false;
49
 
 
50
  foreach( $groups_by_taxonomies as $taxonomy => $groups ) {
51
  if( !empty( $groups ) ) {
52
 
@@ -59,6 +60,14 @@ final class WPCF_GUI_Term_Field_Editing {
59
  }
60
  }
61
 
 
 
 
 
 
 
 
 
62
  if( $is_toolset_forms_support_needed ) {
63
  $this->add_toolset_forms_support();
64
  }
@@ -231,6 +240,12 @@ final class WPCF_GUI_Term_Field_Editing {
231
 
232
  // We need to append form-specific data for the JS validation script.
233
  add_action( 'admin_footer', array( $this, 'render_js_validation_data' ) );
 
 
 
 
 
 
234
  }
235
 
236
 
@@ -317,4 +332,80 @@ final class WPCF_GUI_Term_Field_Editing {
317
  return $tf_renderer->render( false );
318
 
319
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  }
47
 
48
  $is_toolset_forms_support_needed = false;
49
 
50
+ // Hooks for editing term fields
51
  foreach( $groups_by_taxonomies as $taxonomy => $groups ) {
52
  if( !empty( $groups ) ) {
53
 
60
  }
61
  }
62
 
63
+ // Columns on the term listing
64
+ $is_term_listing_page = ( 'edit' != wpcf_getget( 'action' ) );
65
+ if( $is_term_listing_page ) {
66
+ $screen = get_current_screen();
67
+ add_action( "manage_{$screen->id}_columns", array( $this, 'manage_term_listing_columns' ) );
68
+ add_filter( "manage_{$screen->taxonomy}_custom_column", array( $this, 'manage_term_listing_cell'), 10, 3 );
69
+ }
70
+
71
  if( $is_toolset_forms_support_needed ) {
72
  $this->add_toolset_forms_support();
73
  }
240
 
241
  // We need to append form-specific data for the JS validation script.
242
  add_action( 'admin_footer', array( $this, 'render_js_validation_data' ) );
243
+
244
+ // Pretend we're about to create new form via toolset-forms, even if we're not going to.
245
+ // This will load some assets needed for image field preview (specifically the 'wptoolset-forms-admin' style).
246
+ // Hacky, but better than re-registering the toolset-forms stylesheet elsewhere.
247
+ $faux_form_bootstrap = new WPToolset_Forms_Bootstrap();
248
+ $faux_form_bootstrap->form( 'faux' );
249
  }
250
 
251
 
332
  return $tf_renderer->render( false );
333
 
334
  }
335
+
336
+
337
+ /** Prefix for column names so we have no conflicts beyond any doubt. */
338
+ const LISTING_COLUMN_PREFIX = 'wpcf_field_';
339
+
340
+
341
+ /**
342
+ * Add a column for each term field on the term listing page.
343
+ *
344
+ * @param string[string] $columns Column definitions (column name => display name).
345
+ * @return string[string] Updated column definitions.
346
+ * @link https://make.wordpress.org/docs/plugin-developer-handbook/10-plugin-components/custom-list-table-columns/
347
+ * @since 1.9.1
348
+ */
349
+ public function manage_term_listing_columns( $columns ) {
350
+
351
+ $taxonomy_slug = wpcf_getget( 'taxonomy' );
352
+ $groups = WPCF_Field_Group_Term_Factory::get_instance()->get_groups_by_taxonomy( $taxonomy_slug );
353
+
354
+ $columns_to_insert = array();
355
+ foreach( $groups as $group ) {
356
+ foreach( $group->get_field_definitions() as $field_definition ) {
357
+ $columns_to_insert[ self::LISTING_COLUMN_PREFIX . $field_definition->get_slug() ] = $field_definition->get_display_name();
358
+ }
359
+ }
360
+
361
+ // Insert before the last column, which displays counts of posts using the term (that's probably why column
362
+ // has the label "Count" and name "posts" :-P).
363
+ $columns = WPCF_Utils::insert_at_position( $columns, $columns_to_insert, array( 'key' => 'posts', 'where' => 'before' ) );
364
+ return $columns;
365
+ }
366
+
367
+
368
+ /**
369
+ * Render single cell in a term listing table.
370
+ *
371
+ * Catch field columns by their name prefix and render field values with preview renderer.
372
+ *
373
+ * @param mixed $value ""
374
+ * @param string $column_name
375
+ * @param int $term_id
376
+ * @link https://make.wordpress.org/docs/plugin-developer-handbook/10-plugin-components/custom-list-table-columns/
377
+ * @return string Rendered HTML with the table cell content.
378
+ * @since 1.9.1
379
+ */
380
+ public function manage_term_listing_cell( $value, $column_name, $term_id ) {
381
+
382
+ // Deal only with our custom columns.
383
+ $is_term_field_cell = ( substr( $column_name, 0, strlen( self::LISTING_COLUMN_PREFIX ) ) == self::LISTING_COLUMN_PREFIX );
384
+
385
+ if( $is_term_field_cell ) {
386
+
387
+ try {
388
+
389
+ $field_slug = substr( $column_name, strlen( self::LISTING_COLUMN_PREFIX ) );
390
+ $field_definition = WPCF_Field_Term_Definition_Factory::load( $field_slug );
391
+ $field = new WPCF_Field_Instance_Term( $field_definition, $term_id );
392
+
393
+ $renderer_args = array(
394
+ 'maximum_item_count' => 5,
395
+ 'maximum_item_length' => 30,
396
+ 'maximum_total_length' => 100
397
+ );
398
+
399
+ $renderer = WPCF_Field_Renderer_Factory::get_instance()->create_preview_renderer( $field, $renderer_args );
400
+
401
+ $value = $renderer->render();
402
+
403
+ } catch( Exception $e ) {
404
+ // Do nothing when we're unable to load the field.
405
+ }
406
+
407
+ }
408
+
409
+ return $value;
410
+ }
411
  }
embedded/classes/utils.php CHANGED
@@ -2,6 +2,8 @@
2
 
3
  /**
4
  * Class of helper functions that don't fit anywhere else.
 
 
5
  */
6
  final class WPCF_Utils {
7
 
@@ -12,8 +14,9 @@ final class WPCF_Utils {
12
  * @param string $output_mode 'objects'|'names'
13
  *
14
  * @return object[] Array of taxonomy objects or names.
 
15
  */
16
- static function get_builtin_taxonomies( $output_mode = 'objects' ) {
17
  // todo add simple caching
18
  return get_taxonomies( array( 'public' => true, '_builtin' => true ), $output_mode );
19
  }
@@ -25,8 +28,9 @@ final class WPCF_Utils {
25
  * Respects if some builtin taxonomy is overridden by Types.
26
  *
27
  * @return array
 
28
  */
29
- static function get_all_taxonomies() {
30
  // todo add simple caching
31
  $taxonomies = array();
32
 
@@ -63,8 +67,9 @@ final class WPCF_Utils {
63
  *
64
  * @param object|array $object The object or array of objects to transform.
65
  * @return array
 
66
  */
67
- static function object_to_array_deep( $object ) {
68
  if ( is_array( $object ) || is_object( $object ) ) {
69
  $result = array();
70
  foreach ( $object as $key => $value ) {
@@ -87,8 +92,9 @@ final class WPCF_Utils {
87
  * @link https://codex.wordpress.org/Function_Reference/get_taxonomies Taxonomy object description.
88
  *
89
  * @return string Selected taxonomy label or slug if the label was not found.
 
90
  */
91
- static function taxonomy_slug_to_label( $slug, $label_name = 'name' ) {
92
  $all_taxonomies = self::get_all_taxonomies();
93
 
94
  $taxonomy_display_name = wpcf_getnest( $all_taxonomies, array( $slug, 'labels', $label_name ), $slug );
@@ -103,9 +109,113 @@ final class WPCF_Utils {
103
  * @param string $search_string
104
  * @param string $value
105
  * @return bool
 
106
  */
107
- static function is_string_match( $search_string, $value ) {
108
  return ( false !== strpos( mb_strtolower( $value ), mb_strtolower( trim( $search_string ) ) ) );
109
  }
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
2
 
3
  /**
4
  * Class of helper functions that don't fit anywhere else.
5
+ *
6
+ * @since 1.9
7
  */
8
  final class WPCF_Utils {
9
 
14
  * @param string $output_mode 'objects'|'names'
15
  *
16
  * @return object[] Array of taxonomy objects or names.
17
+ * @since 1.9
18
  */
19
+ public static function get_builtin_taxonomies( $output_mode = 'objects' ) {
20
  // todo add simple caching
21
  return get_taxonomies( array( 'public' => true, '_builtin' => true ), $output_mode );
22
  }
28
  * Respects if some builtin taxonomy is overridden by Types.
29
  *
30
  * @return array
31
+ * @since 1.9
32
  */
33
+ public static function get_all_taxonomies() {
34
  // todo add simple caching
35
  $taxonomies = array();
36
 
67
  *
68
  * @param object|array $object The object or array of objects to transform.
69
  * @return array
70
+ * @since 1.9
71
  */
72
+ public static function object_to_array_deep( $object ) {
73
  if ( is_array( $object ) || is_object( $object ) ) {
74
  $result = array();
75
  foreach ( $object as $key => $value ) {
92
  * @link https://codex.wordpress.org/Function_Reference/get_taxonomies Taxonomy object description.
93
  *
94
  * @return string Selected taxonomy label or slug if the label was not found.
95
+ * @since 1.9
96
  */
97
+ public static function taxonomy_slug_to_label( $slug, $label_name = 'name' ) {
98
  $all_taxonomies = self::get_all_taxonomies();
99
 
100
  $taxonomy_display_name = wpcf_getnest( $all_taxonomies, array( $slug, 'labels', $label_name ), $slug );
109
  * @param string $search_string
110
  * @param string $value
111
  * @return bool
112
+ * @since 1.9
113
  */
114
+ public static function is_string_match( $search_string, $value ) {
115
  return ( false !== strpos( mb_strtolower( $value ), mb_strtolower( trim( $search_string ) ) ) );
116
  }
117
 
118
+
119
+ /**
120
+ * Insert elements into source array at a specified position.
121
+ *
122
+ * @param array $source Source array.
123
+ * @param array $to_insert Array of elements to insert.
124
+ * @param int|array $position When integer is provided, zero or positive value means index of the first element that
125
+ * will not be included before $to_insert. Negative value defines the position from the end of the source array
126
+ * (-1 will insert at the very end, -2 before last element, etc.). When an array is provided, it is expected to
127
+ * have form:
128
+ * - 'key': Key to select an element in the source array
129
+ * - 'where': Insert 'before'|'after' the selected element
130
+ *
131
+ * @return array
132
+ * @since 1.9.1
133
+ */
134
+ public static function insert_at_position( $source, $to_insert, $position) {
135
+
136
+ if( is_array( $position ) ) {
137
+ $pivot_key = wpcf_getarr( $position, 'key', null );
138
+ $direction = wpcf_getarr( $position, 'where', 'after', array( 'after', 'before' ) );
139
+
140
+ if( array_key_exists( $pivot_key, $source ) ) {
141
+ $pivot_index = array_search( $pivot_key, array_keys( $source ) );
142
+ $position = ( 'before' == $direction ) ? $pivot_index : $pivot_index + 1;
143
+ } else {
144
+ $position = ( 'before' == $direction ) ? 0 : -1;
145
+ }
146
+ }
147
+
148
+ // $position should be index of the first element that will NOT be included before $to_insert.
149
+ $position = (int) $position;
150
+
151
+ if( 0 > $position ) {
152
+ // E.g.: When $position == -1, the inserted elements should be placed after the last element of $source.
153
+ // $position will point after the last element of $source, new elements will be inserted after it.
154
+ $position = count( $source ) + 1 + $position;
155
+ //echo "pos=$position\n";
156
+
157
+ // Handle too low $position value - insert elements before whole $source.
158
+ if( 0 > $position ) {
159
+ $position = 0;
160
+ }
161
+ }
162
+
163
+ $first_source_part = array_slice( $source, 0, $position );
164
+ $second_source_part = array_slice( $source, $position );
165
+ $result = array_merge( $first_source_part, $to_insert, $second_source_part );
166
+
167
+ return $result;
168
+ }
169
+
170
+
171
+ /**
172
+ * Return an ID of an attachment by searching the database with the file URL.
173
+ *
174
+ * First checks to see if the $url is pointing to a file that exists in
175
+ * the wp-content directory. If so, then we search the database for a
176
+ * partial match consisting of the remaining path AFTER the wp-content
177
+ * directory. Finally, if a match is found the attachment ID will be
178
+ * returned.
179
+ *
180
+ * Taken from:
181
+ * @link http://frankiejarrett.com/get-an-attachment-id-by-url-in-wordpress/
182
+ *
183
+ * @param string $url URL of the file.
184
+ * @return int|null Attachment ID if it exists.
185
+ * @since 1.9.1
186
+ */
187
+ public static function get_attachment_id_by_url( $url ) {
188
+
189
+ // Split the $url into two parts with the wp-content directory as the separator.
190
+ $parsed_url = explode( parse_url( WP_CONTENT_URL, PHP_URL_PATH ), $url );
191
+
192
+ // Get the host of the current site and the host of the $url, ignoring www.
193
+ $this_host = str_ireplace( 'www.', '', parse_url( home_url(), PHP_URL_HOST ) );
194
+ $file_host = str_ireplace( 'www.', '', parse_url( $url, PHP_URL_HOST ) );
195
+
196
+ // Return nothing if there aren't any $url parts or if the current host and $url host do not match.
197
+ $attachment_path = $parsed_url[1];
198
+ if ( ! isset( $attachment_path ) || empty( $attachment_path ) || ( $this_host != $file_host ) ) {
199
+ return null;
200
+ }
201
+
202
+ // Now we're going to quickly search the DB for any attachment GUID with a partial path match.
203
+ // Example: /uploads/2013/05/test-image.jpg
204
+ global $wpdb;
205
+
206
+ $query = $wpdb->prepare(
207
+ "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND guid LIKE %s",
208
+ '%' . $attachment_path
209
+ );
210
+
211
+ $attachment = $wpdb->get_col( $query );
212
+
213
+ if ( is_array( $attachment ) && ! empty( $attachment ) ) {
214
+ return array_shift( $attachment );
215
+ }
216
+
217
+ return null;
218
+ }
219
+
220
+
221
  }
embedded/composer/installed.json CHANGED
@@ -197,12 +197,12 @@
197
  },
198
  {
199
  "name": "otgs/installer",
200
- "version": "1.7.5",
201
- "version_normalized": "1.7.5.0",
202
  "source": {
203
  "type": "git",
204
  "url": "git@git.onthegosystems.com:installer/installer.git",
205
- "reference": "d8cca1e015fab641e590a186460953bbdfb76603"
206
  },
207
  "require": {
208
  "composer/installers": "~1.0",
@@ -211,7 +211,7 @@
211
  "require-dev": {
212
  "phpunit/phpunit": "~4.5"
213
  },
214
- "time": "2016-01-29 12:21:17",
215
  "type": "wordpress-plugin",
216
  "extra": {
217
  "branch-alias": {
197
  },
198
  {
199
  "name": "otgs/installer",
200
+ "version": "1.7.6",
201
+ "version_normalized": "1.7.6.0",
202
  "source": {
203
  "type": "git",
204
  "url": "git@git.onthegosystems.com:installer/installer.git",
205
+ "reference": "61f0d3178e84f9c96cd8580a5e28d30a84ff4e5a"
206
  },
207
  "require": {
208
  "composer/installers": "~1.0",
211
  "require-dev": {
212
  "phpunit/phpunit": "~4.5"
213
  },
214
+ "time": "2016-02-23 13:04:37",
215
  "type": "wordpress-plugin",
216
  "extra": {
217
  "branch-alias": {
embedded/frontend.php CHANGED
@@ -812,21 +812,21 @@ function wpcf_views_user_query( $query, $view_settings ) {
812
  * @param type $view_settings
813
  * @return string
814
  */
815
- function wpcf_views_query( $query, $view_settings, $key = 'wpcf-fields' ) {
816
 
817
- if ( ! in_array( $key, array( 'wpcf-fields', 'wpcf-usermeta', 'wpcf-termmeta' ) ) ) {
818
  return $query;
819
  }
820
 
821
  $meta_filter_required = false;
822
 
823
- $opt = get_option( $key );
824
 
825
  if ( isset( $query['meta_query'] ) ) {
826
  foreach ( $query['meta_query'] as $index => $meta ) {
827
  if ( is_array( $meta ) && isset( $meta['key'] ) ) {
828
  $field_name = $meta['key'];
829
- if ( _wpcf_is_checkboxes_field( $field_name, $key ) ) {
830
 
831
  $orginal = $query['meta_query'][$index];
832
 
812
  * @param type $view_settings
813
  * @return string
814
  */
815
+ function wpcf_views_query( $query, $view_settings, $meta_key = 'wpcf-fields' ) {
816
 
817
+ if ( ! in_array( $meta_key, array( 'wpcf-fields', 'wpcf-usermeta', 'wpcf-termmeta' ) ) ) {
818
  return $query;
819
  }
820
 
821
  $meta_filter_required = false;
822
 
823
+ $opt = get_option( $meta_key );
824
 
825
  if ( isset( $query['meta_query'] ) ) {
826
  foreach ( $query['meta_query'] as $index => $meta ) {
827
  if ( is_array( $meta ) && isset( $meta['key'] ) ) {
828
  $field_name = $meta['key'];
829
+ if ( _wpcf_is_checkboxes_field( $field_name, $meta_key ) ) {
830
 
831
  $orginal = $query['meta_query'][$index];
832
 
embedded/functions.php CHANGED
@@ -121,12 +121,28 @@ function types_get_field_type($type)
121
 
122
  /**
123
  * Imports settings.
 
 
 
124
  */
125
  function wpcf_embedded_check_import()
126
  {
127
- if ( file_exists( WPCF_EMBEDDED_ABSPATH . '/settings.php' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  require_once WPCF_EMBEDDED_ABSPATH . '/admin.php';
129
- require_once WPCF_EMBEDDED_ABSPATH . '/settings.php';
130
  $dismissed = get_option( 'wpcf_dismissed_messages', array() );
131
  if ( in_array( $timestamp, $dismissed ) ) {
132
  return false;
@@ -137,7 +153,7 @@ function wpcf_embedded_check_import()
137
  && isset( $_GET['_wpnonce'] )
138
  && wp_verify_nonce( $_GET['_wpnonce'], 'embedded-import')
139
  ) {
140
- if ( file_exists( WPCF_EMBEDDED_ABSPATH . '/settings.xml' ) ) {
141
  $_POST['overwrite-groups'] = 1;
142
  $_POST['overwrite-fields'] = 1;
143
  $_POST['overwrite-types'] = 1;
@@ -145,7 +161,7 @@ function wpcf_embedded_check_import()
145
  $_POST['post_relationship'] = 1;
146
  require_once WPCF_EMBEDDED_INC_ABSPATH . '/fields.php';
147
  require_once WPCF_EMBEDDED_INC_ABSPATH . '/import-export.php';
148
- $data = @file_get_contents( WPCF_EMBEDDED_ABSPATH . '/settings.xml' );
149
  wpcf_admin_import_data( $data, false, 'types-auto-import' );
150
  update_option( 'wpcf-types-embedded-import', $timestamp );
151
  wp_safe_redirect( esc_url_raw(admin_url() ));
@@ -1014,6 +1030,18 @@ function wpcf_ensarr( $array, $default = array() ) {
1014
  }
1015
 
1016
 
 
 
 
 
 
 
 
 
 
 
 
 
1017
  /**
1018
  * Get a value from nested associative array.
1019
  *
121
 
122
  /**
123
  * Imports settings.
124
+ *
125
+ * @fixme Are we touching this on EVERY page load?!
126
+ * @since unknown
127
  */
128
  function wpcf_embedded_check_import()
129
  {
130
+
131
+ if( !defined( 'WPCF_EMBEDDED_CONFIG_ABSPATH' ) ) {
132
+
133
+ /**
134
+ * Allow for overriding path to settings.php and settings.xml by a third party.
135
+ *
136
+ * Falls back to WPCF_EMBEDDED_ABSPATH if not defined.
137
+ *
138
+ * @since 1.9.1
139
+ */
140
+ define( 'WPCF_EMBEDDED_CONFIG_ABSPATH', WPCF_EMBEDDED_ABSPATH );
141
+ }
142
+
143
+ if ( file_exists( WPCF_EMBEDDED_CONFIG_ABSPATH . '/settings.php' ) ) {
144
  require_once WPCF_EMBEDDED_ABSPATH . '/admin.php';
145
+ require_once WPCF_EMBEDDED_CONFIG_ABSPATH . '/settings.php';
146
  $dismissed = get_option( 'wpcf_dismissed_messages', array() );
147
  if ( in_array( $timestamp, $dismissed ) ) {
148
  return false;
153
  && isset( $_GET['_wpnonce'] )
154
  && wp_verify_nonce( $_GET['_wpnonce'], 'embedded-import')
155
  ) {
156
+ if ( file_exists( WPCF_EMBEDDED_CONFIG_ABSPATH . '/settings.xml' ) ) {
157
  $_POST['overwrite-groups'] = 1;
158
  $_POST['overwrite-fields'] = 1;
159
  $_POST['overwrite-types'] = 1;
161
  $_POST['post_relationship'] = 1;
162
  require_once WPCF_EMBEDDED_INC_ABSPATH . '/fields.php';
163
  require_once WPCF_EMBEDDED_INC_ABSPATH . '/import-export.php';
164
+ $data = @file_get_contents( WPCF_EMBEDDED_CONFIG_ABSPATH . '/settings.xml' );
165
  wpcf_admin_import_data( $data, false, 'types-auto-import' );
166
  update_option( 'wpcf-types-embedded-import', $timestamp );
167
  wp_safe_redirect( esc_url_raw(admin_url() ));
1030
  }
1031
 
1032
 
1033
+ /**
1034
+ * Wrap a variable value in an array if it's not array already.
1035
+ *
1036
+ * @param mixed $input
1037
+ * @return array
1038
+ * @since 1.9.1
1039
+ */
1040
+ function wpcf_wraparr( $input ) {
1041
+ return ( is_array( $input ) ? $input : array( $input ) );
1042
+ }
1043
+
1044
+
1045
  /**
1046
  * Get a value from nested associative array.
1047
  *
embedded/includes/conditional-display.php CHANGED
@@ -197,14 +197,14 @@ function wpcf_cd_post_edit_field_filter( $element, $field, $post,
197
  */
198
  function wpcf_cd_admin_operations() {
199
  return array(
200
- '=' => '=',
201
- '>' => '>',
202
- '<' => '<',
203
- '>=' => '>=',
204
- '<=' => '<=',
205
- '===' => '===',
206
- '<>' => '!=',
207
- '!==' => '!==',
208
  // 'between' => __('between', 'wpcf'),
209
  );
210
  }
197
  */
198
  function wpcf_cd_admin_operations() {
199
  return array(
200
+ '=' => '= (' . __( 'equal to', 'wpcf' ) . ')',
201
+ '>' => '> (' . __( 'larger than', 'wpcf' ) . ')',
202
+ '<' => '< (' . __( 'less than', 'wpcf' ) . ')',
203
+ '>=' => '>= (' . __( 'larger or equal to', 'wpcf' ) . ')',
204
+ '<=' => '<= (' . __( 'less or equal to', 'wpcf' ) . ')',
205
+ '===' => '=== (' . __( 'identical to', 'wpcf' ) . ')',
206
+ '<>' => '!= (' . __( 'not identical to', 'wpcf' ) . ')',
207
+ '!==' => '!== (' . __( 'strictly not equal', 'wpcf' ) . ')',
208
  // 'between' => __('between', 'wpcf'),
209
  );
210
  }
embedded/includes/custom-types.php CHANGED
@@ -102,14 +102,14 @@ function wpcf_custom_types_init() {
102
 
103
  // rearrange menu items
104
  add_filter( 'custom_menu_order' , '__return_true');
105
- add_filter( 'menu_order', 'wpcf_custom_types_menu_order_set' );
106
  // rearrange menu items - end
107
 
108
  /** This filter is documented in wp-admin/wp-admin/edit-form-advanced.php */
109
  add_filter('enter_title_here', 'wpcf_filter_enter_title_here', 10, 2);
110
  }
111
 
112
- function wpcf_custom_types_menu_order_set( $menu ) {
113
  $custom_types = get_option( WPCF_OPTION_NAME_CUSTOM_TYPES, array() );
114
 
115
  if ( !empty( $custom_types ) ) {
@@ -120,30 +120,72 @@ function wpcf_custom_types_menu_order_set( $menu ) {
120
  continue;
121
 
122
  // at this point we have not only an integer as menu position
123
- $menu_position = explode( '--wpcf-add-menu-after--', $data['menu_position'] );
124
 
125
- if( !isset( $menu_position[1] ) || empty( $menu_position[1] ) )
126
  continue;
127
 
128
- $current_index = array_search( 'edit.php?post_type=' . $data['slug'], $menu );
129
 
130
- // remove all items of $menu which are not matching selected menu
131
- $menu_filtered = array_keys( $menu, $menu_position[1] );
 
 
 
 
 
 
 
 
 
 
132
 
133
- // use last match for resorting
134
- // https://onthegosystems.myjetbrains.com/youtrack/issue/types-591
135
- $add_menu_after_index = array_pop( $menu_filtered );
136
 
137
- // if both found resort menu
138
- if( $current_index && $add_menu_after_index )
139
- wpcf_custom_types_menu_order_move( $menu, $current_index, $add_menu_after_index );
 
 
140
 
 
 
 
 
 
 
 
 
141
  }
142
  }
143
 
144
  return $menu;
145
  }
146
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  /**
148
  * This function is be used to rearrange the admin menu order
149
  *
@@ -405,20 +447,32 @@ add_filter('dashboard_glance_items', 'wpcf_dashboard_glance_items');
405
  */
406
  function wpcf_dashboard_glance_items($elements)
407
  {
 
 
 
 
408
  $custom_types = get_option( WPCF_OPTION_NAME_CUSTOM_TYPES, array() );
409
  if ( empty( $custom_types ) ) {
410
  return $elements;
411
  }
412
  ksort($custom_types);
413
  foreach ( $custom_types as $post_type => $data ) {
414
- if ( !isset($data['dashboard_glance']) || !$data['dashboard_glance']) {
415
  continue;
416
  }
417
  if ( isset($data['disabled']) && $data['disabled'] ) {
418
  continue;
419
  }
 
 
 
 
420
  $num_posts = wp_count_posts($post_type);
421
- $num = number_format_i18n($num_posts->publish);
 
 
 
 
422
  $text = _n( $data['labels']['singular_name'], $data['labels']['name'], intval($num_posts->publish) );
423
  $elements[] = sprintf(
424
  '<a href="%s"%s>%d %s</a>',
@@ -617,4 +671,29 @@ function types_rename_build_in_post_types() {
617
  }
618
  }
619
 
620
- add_action( 'init', 'types_rename_build_in_post_types' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  // rearrange menu items
104
  add_filter( 'custom_menu_order' , '__return_true');
105
+ add_filter( 'menu_order', 'types_menu_order' );
106
  // rearrange menu items - end
107
 
108
  /** This filter is documented in wp-admin/wp-admin/edit-form-advanced.php */
109
  add_filter('enter_title_here', 'wpcf_filter_enter_title_here', 10, 2);
110
  }
111
 
112
+ function types_menu_order( $menu ) {
113
  $custom_types = get_option( WPCF_OPTION_NAME_CUSTOM_TYPES, array() );
114
 
115
  if ( !empty( $custom_types ) ) {
120
  continue;
121
 
122
  // at this point we have not only an integer as menu position
123
+ $target_url = explode( '--wpcf-add-menu-after--', $data['menu_position'] );
124
 
125
+ if( !isset( $target_url[1] ) || empty( $target_url[1] ) )
126
  continue;
127
 
128
+ $target_url = $target_url[1];
129
 
130
+ // current url
131
+ switch( $data['slug'] ) {
132
+ case 'post':
133
+ $current_url = 'edit.php';
134
+ break;
135
+ case 'attachment':
136
+ $current_url = 'upload.php';
137
+ break;
138
+ default:
139
+ $current_url = 'edit.php?post_type=' . $data['slug'];
140
+ break;
141
+ }
142
 
143
+ types_menu_order_item_sort( $menu, $current_url, $target_url );
 
 
144
 
145
+ // store already reordered items
146
+ $reordered[$target_url][] = array(
147
+ 'current_url' => $current_url,
148
+ 'menu_position' => $target_url
149
+ );
150
 
151
+ // sort previous sorted items which depend on current again
152
+ if( isset( $reordered[$current_url] ) ) {
153
+ foreach( $reordered[$current_url] as $post_type ) {
154
+ types_menu_order_item_sort( $menu, $post_type['current_url'], $post_type['menu_position'] );
155
+ }
156
+
157
+ unset( $reordered[$current_url] );
158
+ }
159
  }
160
  }
161
 
162
  return $menu;
163
  }
164
 
165
+ /**
166
+ * @param $menu
167
+ * @param $data
168
+ * @param $menu_position
169
+ *
170
+ * @return mixed
171
+ */
172
+ function types_menu_order_item_sort( &$menu, $current_url, $target_url ) {
173
+
174
+ // current index
175
+ $current_index = array_search( $current_url, $menu );
176
+
177
+ // remove all items of $menu which are not matching selected menu
178
+ $menu_filtered = array_keys( $menu, $target_url );
179
+
180
+ // use last match for resorting
181
+ // https://onthegosystems.myjetbrains.com/youtrack/issue/types-591
182
+ $add_menu_after_index = array_pop( $menu_filtered );
183
+
184
+ // if both found resort menu
185
+ if( $current_index && $add_menu_after_index )
186
+ wpcf_custom_types_menu_order_move( $menu, $current_index, $add_menu_after_index );return $menu;
187
+ }
188
+
189
  /**
190
  * This function is be used to rearrange the admin menu order
191
  *
447
  */
448
  function wpcf_dashboard_glance_items($elements)
449
  {
450
+ // remove when https://core.trac.wordpress.org/ticket/27414 is fixed
451
+ wp_register_style( 'wpcf-fix-wordpress-core', WPCF_EMBEDDED_RES_RELPATH . '/css/fix-wordpress-core.css', array(), WPCF_VERSION );
452
+ wp_enqueue_style( 'wpcf-fix-wordpress-core' );
453
+
454
  $custom_types = get_option( WPCF_OPTION_NAME_CUSTOM_TYPES, array() );
455
  if ( empty( $custom_types ) ) {
456
  return $elements;
457
  }
458
  ksort($custom_types);
459
  foreach ( $custom_types as $post_type => $data ) {
460
+ if ( !isset($data['dashboard_glance']) || !$data['dashboard_glance'] || $post_type == 'post' || $post_type == 'page' ) {
461
  continue;
462
  }
463
  if ( isset($data['disabled']) && $data['disabled'] ) {
464
  continue;
465
  }
466
+
467
+ if( $post_type == 'attachment' )
468
+ $data['icon'] = 'admin-media';
469
+
470
  $num_posts = wp_count_posts($post_type);
471
+
472
+ $num = $post_type == 'attachment'
473
+ ? number_format_i18n($num_posts->inherit)
474
+ : number_format_i18n($num_posts->publish);
475
+
476
  $text = _n( $data['labels']['singular_name'], $data['labels']['name'], intval($num_posts->publish) );
477
  $elements[] = sprintf(
478
  '<a href="%s"%s>%d %s</a>',
671
  }
672
  }
673
 
674
+ add_action( 'init', 'types_rename_build_in_post_types' );
675
+
676
+
677
+ /**
678
+ * Visibility of inbuild types
679
+ */
680
+ function types_visibility_build_in_types() {
681
+ $custom_types = get_option( WPCF_OPTION_NAME_CUSTOM_TYPES, array() );
682
+
683
+ // Type: Posts
684
+ if( isset( $custom_types['post']['public'] )
685
+ && $custom_types['post']['public'] == 'hidden' )
686
+ remove_menu_page( 'edit.php' );
687
+
688
+ // Type: Pages
689
+ if( isset( $custom_types['page']['public'] )
690
+ && $custom_types['page']['public'] == 'hidden' )
691
+ remove_menu_page( 'edit.php?post_type=page' );
692
+
693
+ // Type: Media
694
+ if( isset( $custom_types['attachment']['public'] )
695
+ && $custom_types['attachment']['public'] == 'hidden' )
696
+ remove_menu_page( 'upload.php' );
697
+ }
698
+
699
+ add_action( 'admin_menu', 'types_visibility_build_in_types' );
embedded/includes/wpml.php CHANGED
@@ -299,12 +299,15 @@ function wpcf_admin_bulk_string_translation() {
299
 
300
  // Register groups
301
  $groups = wpcf_admin_fields_get_groups();
302
- foreach ( $groups as $group_id => $group ) {
 
 
 
303
  wpcf_translate_register_string( 'plugin Types',
304
- 'group ' . $group_id . ' name', $group['name'] );
305
  if ( isset( $group['description'] ) ) {
306
  wpcf_translate_register_string( 'plugin Types',
307
- 'group ' . $group_id . ' description', $group['description'] );
308
  }
309
  }
310
 
299
 
300
  // Register groups
301
  $groups = wpcf_admin_fields_get_groups();
302
+ foreach ( $groups as $group_key => $group ) {
303
+ //Get correct group ID
304
+ $group_id = isset( $group['id'] ) ? $group['id'] : $group_key;
305
+
306
  wpcf_translate_register_string( 'plugin Types',
307
+ 'group ' . $group_id . ' name', $group['name'] );
308
  if ( isset( $group['description'] ) ) {
309
  wpcf_translate_register_string( 'plugin Types',
310
+ 'group ' . $group_id . ' description', $group['description'] );
311
  }
312
  }
313
 
embedded/plugin.php CHANGED
@@ -5,7 +5,7 @@
5
  Description: Toolset Types use previously defined custom content in WordPress. Easily use custom post types, fields and taxonomy and connect everything together.
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com
8
- Version: 1.9
9
  */
10
  /**
11
  *
5
  Description: Toolset Types use previously defined custom content in WordPress. Easily use custom post types, fields and taxonomy and connect everything together.
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com
8
+ Version: 1.9.1
9
  */
10
  /**
11
  *
embedded/readme.txt CHANGED
@@ -1,11 +1,13 @@
1
  === Toolset Types Embedded ===
2
- Contributors: brucepearson, AmirHelzer, jadpm, jozik, mihaimihai, jans-1, christianglingener, iworks
3
  Donate link: http://wp-types.com
4
  Tags: CMS, custom field, custom fields, custom post type, custom post types, field, fields post, post type, post types, taxonomies, taxonomy, toolset
 
 
5
  License: GPLv2
6
  Requires at least: 3.7
7
  Tested up to: 4.4.1
8
- Stable tag: 1.9
9
 
10
  The Embedded version lets you create custom types, taxonomies and fields for your theme or plugin, without requiring any plugin.
11
 
1
  === Toolset Types Embedded ===
2
+ Contributors: AmirHelzer, brucepearson, christianglingener, jadpm, zaantar
3
  Donate link: http://wp-types.com
4
  Tags: CMS, custom field, custom fields, custom post type, custom post types, field, fields post, post type, post types, taxonomies, taxonomy, toolset
5
+ Text Domain: wpcf
6
+ Domain Path: /locale
7
  License: GPLv2
8
  Requires at least: 3.7
9
  Tested up to: 4.4.1
10
+ Stable tag: 1.9.1
11
 
12
  The Embedded version lets you create custom types, taxonomies and fields for your theme or plugin, without requiring any plugin.
13
 
embedded/resources/css/basic.css CHANGED
@@ -334,7 +334,7 @@ td>.wpcf-form-description-fieldset
334
  margin: 10px 0;
335
  }
336
  .wpcf-form-textarea {
337
- width: 100%;
338
  }
339
  .wpcf-form-description-textarea,
340
  .wpcf-form-description-checkboxes,
@@ -1398,4 +1398,8 @@ div.message p:empty {
1398
 
1399
  .types-field-icon-select {
1400
  background-image: url( '../images/fields/select.png' );
 
 
 
 
1401
  }
334
  margin: 10px 0;
335
  }
336
  .wpcf-form-textarea {
337
+ width: 99%;
338
  }
339
  .wpcf-form-description-textarea,
340
  .wpcf-form-description-checkboxes,
1398
 
1399
  .types-field-icon-select {
1400
  background-image: url( '../images/fields/select.png' );
1401
+ }
1402
+
1403
+ input#slug+p.wpcf-form-description {
1404
+ margin-bottom: 0;
1405
  }
embedded/resources/css/fix-wordpress-core.css ADDED
@@ -0,0 +1,985 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* On "Dashboard" > "At a Glance" section all icons are overwritten by wordpress core.
2
+ This can be remove when https://core.trac.wordpress.org/ticket/27414 is solved */
3
+
4
+ /* Admin Menu Icons */
5
+
6
+ #dashboard_right_now li a.dashicons-menu:before {
7
+ content: "\f333";
8
+ }
9
+
10
+ #dashboard_right_now li a.dashicons-admin-site:before {
11
+ content: "\f319";
12
+ }
13
+
14
+ #dashboard_right_now li a.dashicons-dashboard:before {
15
+ content: "\f226";
16
+ }
17
+
18
+ #dashboard_right_now li a.dashicons-admin-media:before {
19
+ content: "\f104";
20
+ }
21
+
22
+ #dashboard_right_now li a.dashicons-admin-page:before {
23
+ content: "\f105";
24
+ }
25
+
26
+ #dashboard_right_now li a.dashicons-admin-comments:before {
27
+ content: "\f101";
28
+ }
29
+
30
+ #dashboard_right_now li a.dashicons-admin-appearance:before {
31
+ content: "\f100";
32
+ }
33
+
34
+ #dashboard_right_now li a.dashicons-admin-plugins:before {
35
+ content: "\f106";
36
+ }
37
+
38
+ #dashboard_right_now li a.dashicons-admin-users:before {
39
+ content: "\f110";
40
+ }
41
+
42
+ #dashboard_right_now li a.dashicons-admin-tools:before {
43
+ content: "\f107";
44
+ }
45
+
46
+ #dashboard_right_now li a.dashicons-admin-settings:before {
47
+ content: "\f108";
48
+ }
49
+
50
+ #dashboard_right_now li a.dashicons-admin-network:before {
51
+ content: "\f112";
52
+ }
53
+
54
+ #dashboard_right_now li a.dashicons-admin-generic:before {
55
+ content: "\f111";
56
+ }
57
+
58
+ #dashboard_right_now li a.dashicons-admin-home:before {
59
+ content: "\f102";
60
+ }
61
+
62
+ #dashboard_right_now li a.dashicons-admin-collapse:before {
63
+ content: "\f148";
64
+ }
65
+
66
+ #dashboard_right_now li a.dashicons-filter:before {
67
+ content: "\f536";
68
+ }
69
+
70
+ #dashboard_right_now li a.dashicons-admin-customizer:before {
71
+ content: "\f540";
72
+ }
73
+
74
+ #dashboard_right_now li a.dashicons-admin-multisite:before {
75
+ content: "\f541";
76
+ }
77
+
78
+
79
+ /* Both Admin Menu and Post Formats */
80
+
81
+ #dashboard_right_now li a.dashicons-admin-links:before,
82
+ #dashboard_right_now li a.dashicons-format-links:before {
83
+ content: "\f103";
84
+ }
85
+
86
+ #dashboard_right_now li a.dashicons-admin-post:before,
87
+ #dashboard_right_now li a.dashicons-format-standard:before {
88
+ content: "\f109";
89
+ }
90
+
91
+
92
+ /* Post Format Icons */
93
+
94
+ #dashboard_right_now li a.dashicons-format-image:before {
95
+ content: "\f128";
96
+ }
97
+
98
+ #dashboard_right_now li a.dashicons-format-gallery:before {
99
+ content: "\f161";
100
+ }
101
+
102
+ #dashboard_right_now li a.dashicons-format-audio:before {
103
+ content: "\f127";
104
+ }
105
+
106
+ #dashboard_right_now li a.dashicons-format-video:before {
107
+ content: "\f126";
108
+ }
109
+
110
+ #dashboard_right_now li a.dashicons-format-chat:before {
111
+ content: "\f125";
112
+ }
113
+
114
+ #dashboard_right_now li a.dashicons-format-status:before {
115
+ content: "\f130";
116
+ }
117
+
118
+ #dashboard_right_now li a.dashicons-format-aside:before {
119
+ content: "\f123";
120
+ }
121
+
122
+ #dashboard_right_now li a.dashicons-format-quote:before {
123
+ content: "\f122";
124
+ }
125
+
126
+
127
+ /* Welcome Screen Icons */
128
+
129
+ #dashboard_right_now li a.dashicons-welcome-write-blog:before,
130
+ #dashboard_right_now li a.dashicons-welcome-edit-page:before {
131
+ content: "\f119";
132
+ }
133
+
134
+ #dashboard_right_now li a.dashicons-welcome-add-page:before {
135
+ content: "\f133";
136
+ }
137
+
138
+ #dashboard_right_now li a.dashicons-welcome-view-site:before {
139
+ content: "\f115";
140
+ }
141
+
142
+ #dashboard_right_now li a.dashicons-welcome-widgets-menus:before {
143
+ content: "\f116";
144
+ }
145
+
146
+ #dashboard_right_now li a.dashicons-welcome-comments:before {
147
+ content: "\f117";
148
+ }
149
+
150
+ #dashboard_right_now li a.dashicons-welcome-learn-more:before {
151
+ content: "\f118";
152
+ }
153
+
154
+
155
+ /* Image Editing Icons */
156
+
157
+ #dashboard_right_now li a.dashicons-image-crop:before {
158
+ content: "\f165";
159
+ }
160
+
161
+ #dashboard_right_now li a.dashicons-image-rotate:before {
162
+ content: "\f531";
163
+ }
164
+
165
+
166
+ #dashboard_right_now li a.dashicons-image-rotate-left:before {
167
+ content: "\f166";
168
+ }
169
+
170
+ #dashboard_right_now li a.dashicons-image-rotate-right:before {
171
+ content: "\f167";
172
+ }
173
+
174
+ #dashboard_right_now li a.dashicons-image-flip-vertical:before {
175
+ content: "\f168";
176
+ }
177
+
178
+ #dashboard_right_now li a.dashicons-image-flip-horizontal:before {
179
+ content: "\f169";
180
+ }
181
+
182
+ #dashboard_right_now li a.dashicons-image-filter:before {
183
+ content: "\f533";
184
+ }
185
+
186
+
187
+ /* Both Image Editing and TinyMCE */
188
+
189
+ #dashboard_right_now li a.dashicons-undo:before {
190
+ content: "\f171";
191
+ }
192
+
193
+ #dashboard_right_now li a.dashicons-redo:before {
194
+ content: "\f172";
195
+ }
196
+
197
+ /* TinyMCE Icons */
198
+
199
+ #dashboard_right_now li a.dashicons-editor-bold:before {
200
+ content: "\f200";
201
+ }
202
+
203
+ #dashboard_right_now li a.dashicons-editor-italic:before {
204
+ content: "\f201";
205
+ }
206
+
207
+ #dashboard_right_now li a.dashicons-editor-ul:before {
208
+ content: "\f203";
209
+ }
210
+
211
+ #dashboard_right_now li a.dashicons-editor-ol:before {
212
+ content: "\f204";
213
+ }
214
+
215
+ #dashboard_right_now li a.dashicons-editor-quote:before {
216
+ content: "\f205";
217
+ }
218
+
219
+ #dashboard_right_now li a.dashicons-editor-alignleft:before {
220
+ content: "\f206";
221
+ }
222
+
223
+ #dashboard_right_now li a.dashicons-editor-aligncenter:before {
224
+ content: "\f207";
225
+ }
226
+
227
+ #dashboard_right_now li a.dashicons-editor-alignright:before {
228
+ content: "\f208";
229
+ }
230
+
231
+ #dashboard_right_now li a.dashicons-editor-insertmore:before {
232
+ content: "\f209";
233
+ }
234
+
235
+ #dashboard_right_now li a.dashicons-editor-spellcheck:before {
236
+ content: "\f210";
237
+ }
238
+
239
+ #dashboard_right_now li a.dashicons-editor-distractionfree:before,
240
+ #dashboard_right_now li a.dashicons-editor-expand:before {
241
+ content: "\f211";
242
+ }
243
+
244
+ #dashboard_right_now li a.dashicons-editor-contract:before {
245
+ content: "\f506";
246
+ }
247
+
248
+ #dashboard_right_now li a.dashicons-editor-kitchensink:before {
249
+ content: "\f212";
250
+ }
251
+
252
+ #dashboard_right_now li a.dashicons-editor-underline:before {
253
+ content: "\f213";
254
+ }
255
+
256
+ #dashboard_right_now li a.dashicons-editor-justify:before {
257
+ content: "\f214";
258
+ }
259
+
260
+ #dashboard_right_now li a.dashicons-editor-textcolor:before {
261
+ content: "\f215";
262
+ }
263
+
264
+ #dashboard_right_now li a.dashicons-editor-paste-word:before {
265
+ content: "\f216";
266
+ }
267
+
268
+ #dashboard_right_now li a.dashicons-editor-paste-text:before {
269
+ content: "\f217";
270
+ }
271
+
272
+ #dashboard_right_now li a.dashicons-editor-removeformatting:before {
273
+ content: "\f218";
274
+ }
275
+
276
+ #dashboard_right_now li a.dashicons-editor-video:before {
277
+ content: "\f219";
278
+ }
279
+
280
+ #dashboard_right_now li a.dashicons-editor-customchar:before {
281
+ content: "\f220";
282
+ }
283
+
284
+ #dashboard_right_now li a.dashicons-editor-outdent:before {
285
+ content: "\f221";
286
+ }
287
+
288
+ #dashboard_right_now li a.dashicons-editor-indent:before {
289
+ content: "\f222";
290
+ }
291
+
292
+ #dashboard_right_now li a.dashicons-editor-help:before {
293
+ content: "\f223";
294
+ }
295
+
296
+ #dashboard_right_now li a.dashicons-editor-strikethrough:before {
297
+ content: "\f224";
298
+ }
299
+
300
+ #dashboard_right_now li a.dashicons-editor-unlink:before {
301
+ content: "\f225";
302
+ }
303
+
304
+ #dashboard_right_now li a.dashicons-editor-rtl:before {
305
+ content: "\f320";
306
+ }
307
+
308
+ #dashboard_right_now li a.dashicons-editor-break:before {
309
+ content: "\f474";
310
+ }
311
+
312
+ #dashboard_right_now li a.dashicons-editor-code:before {
313
+ content: "\f475";
314
+ }
315
+
316
+ #dashboard_right_now li a.dashicons-editor-paragraph:before {
317
+ content: "\f476";
318
+ }
319
+
320
+ #dashboard_right_now li a.dashicons-editor-table:before {
321
+ content: "\f535";
322
+ }
323
+
324
+ /* Post Icons */
325
+
326
+ #dashboard_right_now li a.dashicons-align-left:before {
327
+ content: "\f135";
328
+ }
329
+
330
+ #dashboard_right_now li a.dashicons-align-right:before {
331
+ content: "\f136";
332
+ }
333
+
334
+ #dashboard_right_now li a.dashicons-align-center:before {
335
+ content: "\f134";
336
+ }
337
+
338
+ #dashboard_right_now li a.dashicons-align-none:before {
339
+ content: "\f138";
340
+ }
341
+
342
+ #dashboard_right_now li a.dashicons-lock:before {
343
+ content: "\f160";
344
+ }
345
+
346
+ #dashboard_right_now li a.dashicons-unlock:before {
347
+ content: "\f528";
348
+ }
349
+
350
+ #dashboard_right_now li a.dashicons-calendar:before {
351
+ content: "\f145";
352
+ }
353
+
354
+ #dashboard_right_now li a.dashicons-calendar-alt:before {
355
+ content: "\f508";
356
+ }
357
+
358
+ #dashboard_right_now li a.dashicons-visibility:before {
359
+ content: "\f177";
360
+ }
361
+
362
+ #dashboard_right_now li a.dashicons-hidden:before {
363
+ content: "\f530";
364
+ }
365
+
366
+ #dashboard_right_now li a.dashicons-post-status:before {
367
+ content: "\f173";
368
+ }
369
+
370
+ #dashboard_right_now li a.dashicons-edit:before {
371
+ content: "\f464";
372
+ }
373
+
374
+ #dashboard_right_now li a.dashicons-post-trash:before,
375
+ #dashboard_right_now li a.dashicons-trash:before {
376
+ content: "\f182";
377
+ }
378
+
379
+ #dashboard_right_now li a.dashicons-sticky:before {
380
+ content: "\f537";
381
+ }
382
+
383
+
384
+ /* Sorting */
385
+
386
+ #dashboard_right_now li a.dashicons-external:before {
387
+ content: "\f504";
388
+ }
389
+
390
+ #dashboard_right_now li a.dashicons-arrow-up:before {
391
+ content: "\f142";
392
+ }
393
+
394
+ #dashboard_right_now li a.dashicons-arrow-down:before {
395
+ content: "\f140";
396
+ }
397
+
398
+ #dashboard_right_now li a.dashicons-arrow-left:before {
399
+ content: "\f141";
400
+ }
401
+
402
+ #dashboard_right_now li a.dashicons-arrow-right:before {
403
+ content: "\f139";
404
+ }
405
+
406
+ #dashboard_right_now li a.dashicons-arrow-up-alt:before {
407
+ content: "\f342";
408
+ }
409
+
410
+ #dashboard_right_now li a.dashicons-arrow-down-alt:before {
411
+ content: "\f346";
412
+ }
413
+
414
+ #dashboard_right_now li a.dashicons-arrow-left-alt:before {
415
+ content: "\f340";
416
+ }
417
+
418
+ #dashboard_right_now li a.dashicons-arrow-right-alt:before {
419
+ content: "\f344";
420
+ }
421
+
422
+ #dashboard_right_now li a.dashicons-arrow-up-alt2:before {
423
+ content: "\f343";
424
+ }
425
+
426
+ #dashboard_right_now li a.dashicons-arrow-down-alt2:before {
427
+ content: "\f347";
428
+ }
429
+
430
+ #dashboard_right_now li a.dashicons-arrow-left-alt2:before {
431
+ content: "\f341";
432
+ }
433
+
434
+ #dashboard_right_now li a.dashicons-arrow-right-alt2:before {
435
+ content: "\f345";
436
+ }
437
+
438
+ #dashboard_right_now li a.dashicons-leftright:before {
439
+ content: "\f229";
440
+ }
441
+
442
+ #dashboard_right_now li a.dashicons-sort:before {
443
+ content: "\f156";
444
+ }
445
+
446
+ #dashboard_right_now li a.dashicons-randomize:before {
447
+ content: "\f503";
448
+ }
449
+
450
+ #dashboard_right_now li a.dashicons-list-view:before {
451
+ content: "\f163";
452
+ }
453
+
454
+ #dashboard_right_now li a.dashicons-exerpt-view:before, /* Misspelled. Use #dashboard_right_now li a.dashicons-excerpt-view instead. */
455
+ #dashboard_right_now li a.dashicons-excerpt-view:before {
456
+ content: "\f164";
457
+ }
458
+
459
+ #dashboard_right_now li a.dashicons-grid-view:before {
460
+ content: "\f509";
461
+ }
462
+
463
+
464
+ /* WPorg specific icons: Jobs, Profiles, WordCamps */
465
+
466
+ #dashboard_right_now li a.dashicons-hammer:before {
467
+ content: "\f308";
468
+ }
469
+
470
+ #dashboard_right_now li a.dashicons-art:before {
471
+ content: "\f309";
472
+ }
473
+
474
+ #dashboard_right_now li a.dashicons-migrate:before {
475
+ content: "\f310";
476
+ }
477
+
478
+ #dashboard_right_now li a.dashicons-performance:before {
479
+ content: "\f311";
480
+ }
481
+
482
+ #dashboard_right_now li a.dashicons-universal-access:before {
483
+ content: "\f483";
484
+ }
485
+
486
+ #dashboard_right_now li a.dashicons-universal-access-alt:before {
487
+ content: "\f507";
488
+ }
489
+
490
+ #dashboard_right_now li a.dashicons-tickets:before {
491
+ content: "\f486";
492
+ }
493
+
494
+ #dashboard_right_now li a.dashicons-nametag:before {
495
+ content: "\f484";
496
+ }
497
+
498
+ #dashboard_right_now li a.dashicons-clipboard:before {
499
+ content: "\f481";
500
+ }
501
+
502
+ #dashboard_right_now li a.dashicons-heart:before {
503
+ content: "\f487";
504
+ }
505
+
506
+ #dashboard_right_now li a.dashicons-megaphone:before {
507
+ content: "\f488";
508
+ }
509
+
510
+ #dashboard_right_now li a.dashicons-schedule:before {
511
+ content: "\f489";
512
+ }
513
+
514
+
515
+ /* Internal/Products */
516
+
517
+ #dashboard_right_now li a.dashicons-wordpress:before {
518
+ content: "\f120";
519
+ }
520
+
521
+ #dashboard_right_now li a.dashicons-wordpress-alt:before {
522
+ content: "\f324";
523
+ }
524
+
525
+ #dashboard_right_now li a.dashicons-pressthis:before {
526
+ content: "\f157";
527
+ }
528
+
529
+ #dashboard_right_now li a.dashicons-update:before {
530
+ content: "\f463";
531
+ }
532
+
533
+ #dashboard_right_now li a.dashicons-screenoptions:before {
534
+ content: "\f180";
535
+ }
536
+
537
+ #dashboard_right_now li a.dashicons-cart:before {
538
+ content: "\f174";
539
+ }
540
+
541
+ #dashboard_right_now li a.dashicons-feedback:before {
542
+ content: "\f175";
543
+ }
544
+
545
+ #dashboard_right_now li a.dashicons-cloud:before {
546
+ content: "\f176";
547
+ }
548
+
549
+ #dashboard_right_now li a.dashicons-translation:before {
550
+ content: "\f326";
551
+ }
552
+
553
+
554
+ /* Taxonomies */
555
+
556
+ #dashboard_right_now li a.dashicons-tag:before {
557
+ content: "\f323";
558
+ }
559
+
560
+ #dashboard_right_now li a.dashicons-category:before {
561
+ content: "\f318";
562
+ }
563
+
564
+
565
+ /* Widget icons */
566
+
567
+ #dashboard_right_now li a.dashicons-archive:before {
568
+ content: "\f480";
569
+ }
570
+
571
+ #dashboard_right_now li a.dashicons-tagcloud:before {
572
+ content: "\f479";
573
+ }
574
+
575
+ #dashboard_right_now li a.dashicons-text:before {
576
+ content: "\f478";
577
+ }
578
+
579
+
580
+ /* Media icons */
581
+
582
+ #dashboard_right_now li a.dashicons-media-archive:before {
583
+ content: "\f501";
584
+ }
585
+
586
+ #dashboard_right_now li a.dashicons-media-audio:before {
587
+ content: "\f500";
588
+ }
589
+
590
+ #dashboard_right_now li a.dashicons-media-code:before {
591
+ content: "\f499";
592
+ }
593
+
594
+ #dashboard_right_now li a.dashicons-media-default:before {
595
+ content: "\f498";
596
+ }
597
+
598
+ #dashboard_right_now li a.dashicons-media-document:before {
599
+ content: "\f497";
600
+ }
601
+
602
+ #dashboard_right_now li a.dashicons-media-interactive:before {
603
+ content: "\f496";
604
+ }
605
+
606
+ #dashboard_right_now li a.dashicons-media-spreadsheet:before {
607
+ content: "\f495";
608
+ }
609
+
610
+ #dashboard_right_now li a.dashicons-media-text:before {
611
+ content: "\f491";
612
+ }
613
+
614
+ #dashboard_right_now li a.dashicons-media-video:before {
615
+ content: "\f490";
616
+ }
617
+
618
+ #dashboard_right_now li a.dashicons-playlist-audio:before {
619
+ content: "\f492";
620
+ }
621
+
622
+ #dashboard_right_now li a.dashicons-playlist-video:before {
623
+ content: "\f493";
624
+ }
625
+
626
+ #dashboard_right_now li a.dashicons-controls-play:before {
627
+ content: "\f522";
628
+ }
629
+
630
+ #dashboard_right_now li a.dashicons-controls-pause:before {
631
+ content: "\f523";
632
+ }
633
+
634
+ #dashboard_right_now li a.dashicons-controls-forward:before {
635
+ content: "\f519";
636
+ }
637
+
638
+ #dashboard_right_now li a.dashicons-controls-skipforward:before {
639
+ content: "\f517";
640
+ }
641
+
642
+ #dashboard_right_now li a.dashicons-controls-back:before {
643
+ content: "\f518";
644
+ }
645
+
646
+ #dashboard_right_now li a.dashicons-controls-skipback:before {
647
+ content: "\f516";
648
+ }
649
+
650
+ #dashboard_right_now li a.dashicons-controls-repeat:before {
651
+ content: "\f515";
652
+ }
653
+
654
+ #dashboard_right_now li a.dashicons-controls-volumeon:before {
655
+ content: "\f521";
656
+ }
657
+
658
+ #dashboard_right_now li a.dashicons-controls-volumeoff:before {
659
+ content: "\f520";
660
+ }
661
+
662
+
663
+ /* Alerts/Notifications/Flags */
664
+
665
+ #dashboard_right_now li a.dashicons-yes:before {
666
+ content: "\f147";
667
+ }
668
+
669
+ #dashboard_right_now li a.dashicons-no:before {
670
+ content: "\f158";
671
+ }
672
+
673
+ #dashboard_right_now li a.dashicons-no-alt:before {
674
+ content: "\f335";
675
+ }
676
+
677
+ #dashboard_right_now li a.dashicons-plus:before {
678
+ content: "\f132";
679
+ }
680
+
681
+ #dashboard_right_now li a.dashicons-plus-alt:before {
682
+ content: "\f502";
683
+ }
684
+
685
+ #dashboard_right_now li a.dashicons-plus-alt2:before {
686
+ content: "\f543";
687
+ }
688
+
689
+ #dashboard_right_now li a.dashicons-minus:before {
690
+ content: "\f460";
691
+ }
692
+
693
+ #dashboard_right_now li a.dashicons-dismiss:before {
694
+ content: "\f153";
695
+ }
696
+
697
+ #dashboard_right_now li a.dashicons-marker:before {
698
+ content: "\f159";
699
+ }
700
+
701
+ #dashboard_right_now li a.dashicons-star-filled:before {
702
+ content: "\f155";
703
+ }
704
+
705
+ #dashboard_right_now li a.dashicons-star-half:before {
706
+ content: "\f459";
707
+ }
708
+
709
+ #dashboard_right_now li a.dashicons-star-empty:before {
710
+ content: "\f154";
711
+ }
712
+
713
+ #dashboard_right_now li a.dashicons-flag:before {
714
+ content: "\f227";
715
+ }
716
+
717
+ #dashboard_right_now li a.dashicons-info:before {
718
+ content: "\f348";
719
+ }
720
+
721
+ #dashboard_right_now li a.dashicons-warning:before {
722
+ content: "\f534";
723
+ }
724
+
725
+
726
+ /* Social Icons */
727
+
728
+ #dashboard_right_now li a.dashicons-share:before {
729
+ content: "\f237";
730
+ }
731
+
732
+ #dashboard_right_now li a.dashicons-share1:before {
733
+ content: "\f237";
734
+ }
735
+
736
+ #dashboard_right_now li a.dashicons-share-alt:before {
737
+ content: "\f240";
738
+ }
739
+
740
+ #dashboard_right_now li a.dashicons-share-alt2:before {
741
+ content: "\f242";
742
+ }
743
+
744
+ #dashboard_right_now li a.dashicons-twitter:before {
745
+ content: "\f301";
746
+ }
747
+
748
+ #dashboard_right_now li a.dashicons-rss:before {
749
+ content: "\f303";
750
+ }
751
+
752
+ #dashboard_right_now li a.dashicons-email:before {
753
+ content: "\f465";
754
+ }
755
+
756
+ #dashboard_right_now li a.dashicons-email-alt:before {
757
+ content: "\f466";
758
+ }
759
+
760
+ #dashboard_right_now li a.dashicons-facebook:before {
761
+ content: "\f304";
762
+ }
763
+
764
+ #dashboard_right_now li a.dashicons-facebook-alt:before {
765
+ content: "\f305";
766
+ }
767
+
768
+ #dashboard_right_now li a.dashicons-networking:before {
769
+ content: "\f325";
770
+ }
771
+
772
+ #dashboard_right_now li a.dashicons-googleplus:before {
773
+ content: "\f462";
774
+ }
775
+
776
+
777
+ /* Misc/CPT */
778
+
779
+ #dashboard_right_now li a.dashicons-location:before {
780
+ content: "\f230";
781
+ }
782
+
783
+ #dashboard_right_now li a.dashicons-location-alt:before {
784
+ content: "\f231";
785
+ }
786
+
787
+ #dashboard_right_now li a.dashicons-camera:before {
788
+ content: "\f306";
789
+ }
790
+
791
+ #dashboard_right_now li a.dashicons-images-alt:before {
792
+ content: "\f232";
793
+ }
794
+
795
+ #dashboard_right_now li a.dashicons-images-alt2:before {
796
+ content: "\f233";
797
+ }
798
+
799
+ #dashboard_right_now li a.dashicons-video-alt:before {
800
+ content: "\f234";
801
+ }
802
+
803
+ #dashboard_right_now li a.dashicons-video-alt2:before {
804
+ content: "\f235";
805
+ }
806
+
807
+ #dashboard_right_now li a.dashicons-video-alt3:before {
808
+ content: "\f236";
809
+ }
810
+
811
+ #dashboard_right_now li a.dashicons-vault:before {
812
+ content: "\f178";
813
+ }
814
+
815
+ #dashboard_right_now li a.dashicons-shield:before {
816
+ content: "\f332";
817
+ }
818
+
819
+ #dashboard_right_now li a.dashicons-shield-alt:before {
820
+ content: "\f334";
821
+ }
822
+
823
+ #dashboard_right_now li a.dashicons-sos:before {
824
+ content: "\f468";
825
+ }
826
+
827
+ #dashboard_right_now li a.dashicons-search:before {
828
+ content: "\f179";
829
+ }
830
+
831
+ #dashboard_right_now li a.dashicons-slides:before {
832
+ content: "\f181";
833
+ }
834
+
835
+ #dashboard_right_now li a.dashicons-analytics:before {
836
+ content: "\f183";
837
+ }
838
+
839
+ #dashboard_right_now li a.dashicons-chart-pie:before {
840
+ content: "\f184";
841
+ }
842
+
843
+ #dashboard_right_now li a.dashicons-chart-bar:before {
844
+ content: "\f185";
845
+ }
846
+
847
+ #dashboard_right_now li a.dashicons-chart-line:before {
848
+ content: "\f238";
849
+ }
850
+
851
+ #dashboard_right_now li a.dashicons-chart-area:before {
852
+ content: "\f239";
853
+ }
854
+
855
+ #dashboard_right_now li a.dashicons-groups:before {
856
+ content: "\f307";
857
+ }
858
+
859
+ #dashboard_right_now li a.dashicons-businessman:before {
860
+ content: "\f338";
861
+ }
862
+
863
+ #dashboard_right_now li a.dashicons-id:before {
864
+ content: "\f336";
865
+ }
866
+
867
+ #dashboard_right_now li a.dashicons-id-alt:before {
868
+ content: "\f337";
869
+ }
870
+
871
+ #dashboard_right_now li a.dashicons-products:before {
872
+ content: "\f312";
873
+ }
874
+
875
+ #dashboard_right_now li a.dashicons-awards:before {
876
+ content: "\f313";
877
+ }
878
+
879
+ #dashboard_right_now li a.dashicons-forms:before {
880
+ content: "\f314";
881
+ }
882
+
883
+ #dashboard_right_now li a.dashicons-testimonial:before {
884
+ content: "\f473";
885
+ }
886
+
887
+ #dashboard_right_now li a.dashicons-portfolio:before {
888
+ content: "\f322";
889
+ }
890
+
891
+ #dashboard_right_now li a.dashicons-book:before {
892
+ content: "\f330";
893
+ }
894
+
895
+ #dashboard_right_now li a.dashicons-book-alt:before {
896
+ content: "\f331";
897
+ }
898
+
899
+ #dashboard_right_now li a.dashicons-download:before {
900
+ content: "\f316";
901
+ }
902
+
903
+ #dashboard_right_now li a.dashicons-upload:before {
904
+ content: "\f317";
905
+ }
906
+
907
+ #dashboard_right_now li a.dashicons-backup:before {
908
+ content: "\f321";
909
+ }
910
+
911
+ #dashboard_right_now li a.dashicons-clock:before {
912
+ content: "\f469";
913
+ }
914
+
915
+ #dashboard_right_now li a.dashicons-lightbulb:before {
916
+ content: "\f339";
917
+ }
918
+
919
+ #dashboard_right_now li a.dashicons-microphone:before {
920
+ content: "\f482";
921
+ }
922
+
923
+ #dashboard_right_now li a.dashicons-desktop:before {
924
+ content: "\f472";
925
+ }
926
+
927
+ #dashboard_right_now li a.dashicons-tablet:before {
928
+ content: "\f471";
929
+ }
930
+
931
+ #dashboard_right_now li a.dashicons-smartphone:before {
932
+ content: "\f470";
933
+ }
934
+
935
+ #dashboard_right_now li a.dashicons-phone:before {
936
+ content: "\f525";
937
+ }
938
+
939
+ #dashboard_right_now li a.dashicons-smiley:before {
940
+ content: "\f328";
941
+ }
942
+
943
+ #dashboard_right_now li a.dashicons-index-card:before {
944
+ content: "\f510";
945
+ }
946
+
947
+ #dashboard_right_now li a.dashicons-carrot:before {
948
+ content: "\f511";
949
+ }
950
+
951
+ #dashboard_right_now li a.dashicons-building:before {
952
+ content: "\f512";
953
+ }
954
+
955
+ #dashboard_right_now li a.dashicons-store:before {
956
+ content: "\f513";
957
+ }
958
+
959
+ #dashboard_right_now li a.dashicons-album:before {
960
+ content: "\f514";
961
+ }
962
+
963
+ #dashboard_right_now li a.dashicons-palmtree:before {
964
+ content: "\f527";
965
+ }
966
+
967
+ #dashboard_right_now li a.dashicons-tickets-alt:before {
968
+ content: "\f524";
969
+ }
970
+
971
+ #dashboard_right_now li a.dashicons-money:before {
972
+ content: "\f526";
973
+ }
974
+
975
+ #dashboard_right_now li a.dashicons-thumbs-up:before {
976
+ content: "\f529";
977
+ }
978
+
979
+ #dashboard_right_now li a.dashicons-thumbs-down:before {
980
+ content: "\f542";
981
+ }
982
+
983
+ #dashboard_right_now li a.dashicons-layout:before {
984
+ content: "\f538";
985
+ }
embedded/resources/js/basic.js CHANGED
@@ -388,8 +388,11 @@ function wpcfBindAutoCreateSlugs()
388
  slug = jQuery('.js-wpcf-slugize-source', jQuery(this).closest('.js-wpcf-slugize-container')).val();
389
  }
390
  if ( '' != slug ){
391
- val = wpcf_slugize(slug);
392
- jQuery(this).val(val.substring(0,20));
 
 
 
393
  }
394
  });
395
  }
388
  slug = jQuery('.js-wpcf-slugize-source', jQuery(this).closest('.js-wpcf-slugize-container')).val();
389
  }
390
  if ( '' != slug ){
391
+ var validSlug = wpcf_slugize( slug );
392
+
393
+ if( validSlug != slug || jQuery(this).val() == '' ) {
394
+ jQuery( this ).val( validSlug.substring( 0, 200 ) );
395
+ }
396
  }
397
  });
398
  }
embedded/resources/js/fields-form.js CHANGED
@@ -65,23 +65,33 @@ jQuery(document).ready(function($){
65
  }
66
  });
67
 
68
- $('.wpcf-fields-radio-sortable,.wpcf-fields-select-sortable').sortable({
69
- cursor: 'ns-resize',
70
- axis: 'y',
71
- handle: '.js-types-sort-button',
72
- start: function(e, ui){
 
 
73
  ui.placeholder.height(ui.item.height() - 2);
74
  }
75
- });
76
 
77
- $('.wpcf-fields-checkboxes-sortable').sortable({
78
- cursor: 'ns-resize',
79
- axis: 'y',
80
- handle: '.js-types-sort-button',
81
- start: function(e, ui){
82
  ui.placeholder.height(ui.item.height() + 13);
83
  }
84
- });
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  $('[data-wpcf-type="checkbox"],[data-wpcf-type=checkboxes]').each( function() {
87
  $(this).bind('change', function() {
65
  }
66
  });
67
 
68
+ $.fn.typesFieldOptionsSortable = function() {
69
+
70
+ $( '.wpcf-fields-radio-sortable, .wpcf-fields-select-sortable, .wpcf-fields-checkboxes-sortable', this ).sortable({
71
+ cursor: 'ns-resize',
72
+ axis: 'y',
73
+ handle: '.js-types-sort-button',
74
+ start: function(e, ui){
75
  ui.placeholder.height(ui.item.height() - 2);
76
  }
77
+ });
78
 
79
+ $( '.wpcf-fields-checkboxes-sortable', this ).sortable({
80
+ start: function(e, ui){
 
 
 
81
  ui.placeholder.height(ui.item.height() + 13);
82
  }
83
+ });
84
+ }
85
+
86
+ $.fn.typesMarkExistingField = function() {
87
+
88
+ var slug = $( '.wpcf-forms-field-slug', this );
89
+
90
+ if( slug.length && slug.val() != '' )
91
+ slug.attr( 'data-types-existing-field', slug.val() );
92
+ }
93
+
94
+ $( 'body' ).typesFieldOptionsSortable();
95
 
96
  $('[data-wpcf-type="checkbox"],[data-wpcf-type=checkboxes]').each( function() {
97
  $(this).bind('change', function() {
embedded/resources/js/post-relationship.js CHANGED
@@ -380,6 +380,9 @@ jQuery(document).ready(function($) {
380
 
381
  wpcfInitValueOfSelect2DoneClear();
382
  var $button = $(this), $table = $button.parents('.js-types-relationship-child-posts').find('table');
 
 
 
383
  $.ajax({
384
  url: $button.attr('href'),
385
  type: 'get',
@@ -423,6 +426,9 @@ jQuery(document).ready(function($) {
423
  };
424
 
425
  $( document ).trigger( 'js_event_wpcf_types_relationship_child_added', [ data_for_events ] );
 
 
 
426
  }
427
  });
428
  return false;
@@ -438,6 +444,9 @@ jQuery(document).ready(function($) {
438
  return false;
439
  }
440
  var object = jQuery(this);
 
 
 
441
  jQuery.ajax({
442
  url: jQuery(this).attr('href'),
443
  type: 'get',
@@ -474,6 +483,9 @@ jQuery(document).ready(function($) {
474
  * select2
475
  */
476
  wpcfBindSelect2($);
 
 
 
477
  }
478
  });
479
  return false;
@@ -660,6 +672,9 @@ jQuery(document).ready(function($) {
660
  .find('.wpcf-pr-edited').removeClass('wpcf-pr-edited');
661
  var height = $row.height(), rand = Math.round(Math.random() * 10000);
662
  window.wpcf_pr_edited = false;
 
 
 
663
  $.ajax({
664
  url: $button.attr('href'),
665
  type: 'post',
@@ -670,48 +685,51 @@ jQuery(document).ready(function($) {
670
  $row.after('<tr id="wpcf-pr-update-' + rand + '"><td style="height: ' + height + 'px;"><div style="margin-top:20px;" class="wpcf-ajax-loading-small"></div></td></tr>').hide();
671
  },
672
  success: function(data) {
673
- if (data != null) {
674
- if (typeof data.output != 'undefined') {
675
- $row.replaceWith(data.output).show();
676
  wpcfDisableControls();
677
- $('#wpcf-pr-update-' + rand + '').remove();
678
- wpcfRelationshipInit('', 'save');
679
  tChildTable.reset();
680
- if (typeof wptCallbacks != 'undefined') {
681
- wptCallbacks.reset.fire('#'+rowId);
682
  }
683
- if ( 'undefined' != typeof wptFile ) {
684
  wptFile.init();
685
  }
686
  }
687
- if (typeof data.conditionals != 'undefined' && typeof wptCond != 'undefined') {
688
- wptCond.addConditionals(data.conditionals);
689
  }
690
  /**
691
  * rebind images
692
  */
693
- if ( 'function' == typeof bind_colorbox_to_thumbnail_preview ) {
694
  bind_colorbox_to_thumbnail_preview();
695
  }
696
  /**
697
  * show errors
698
  */
699
- $('#wpcf-post-relationship div.message').detach();
700
- if ('undefined' != typeof data.errors && 0 < data.errors.length ) {
701
- $('#wpcf-post-relationship h3.hndle').after(data.errors);
702
  }
703
  /**
704
  * select2
705
  */
706
  wpcfInitValueOfSelect2DoneClear();
707
- wpcfBindSelect2($);
708
-
709
- var data_for_events = {
710
- table: $table
711
- };
712
-
713
- $( document ).trigger( 'js_event_wpcf_types_relationship_child_saved', [ data_for_events ] );
714
  }
 
 
 
715
  }
716
  });
717
  return false;
@@ -1101,12 +1119,12 @@ function wpcfEnableControls() {
1101
  jQuery( 'input[name^="save"]' ).removeAttr( 'disabled' );
1102
  }
1103
 
1104
- jQuery( document ).ajaxStart( function() {
1105
  wpcfDisableControls();
1106
- });
1107
 
1108
- jQuery( document ).ajaxComplete( function() {
1109
  if( jQuery.active == 1 ) {
1110
  wpcfEnableControls();
1111
  }
1112
- });
380
 
381
  wpcfInitValueOfSelect2DoneClear();
382
  var $button = $(this), $table = $button.parents('.js-types-relationship-child-posts').find('table');
383
+
384
+ typesRelationControlsAjaxStart();
385
+
386
  $.ajax({
387
  url: $button.attr('href'),
388
  type: 'get',
426
  };
427
 
428
  $( document ).trigger( 'js_event_wpcf_types_relationship_child_added', [ data_for_events ] );
429
+ },
430
+ complete: function() {
431
+ typesRelationControlsAjaxComplete();
432
  }
433
  });
434
  return false;
444
  return false;
445
  }
446
  var object = jQuery(this);
447
+
448
+ typesRelationControlsAjaxStart();
449
+
450
  jQuery.ajax({
451
  url: jQuery(this).attr('href'),
452
  type: 'get',
483
  * select2
484
  */
485
  wpcfBindSelect2($);
486
+ },
487
+ complete: function() {
488
+ typesRelationControlsAjaxComplete();
489
  }
490
  });
491
  return false;
672
  .find('.wpcf-pr-edited').removeClass('wpcf-pr-edited');
673
  var height = $row.height(), rand = Math.round(Math.random() * 10000);
674
  window.wpcf_pr_edited = false;
675
+
676
+ typesRelationControlsAjaxStart();
677
+
678
  $.ajax({
679
  url: $button.attr('href'),
680
  type: 'post',
685
  $row.after('<tr id="wpcf-pr-update-' + rand + '"><td style="height: ' + height + 'px;"><div style="margin-top:20px;" class="wpcf-ajax-loading-small"></div></td></tr>').hide();
686
  },
687
  success: function(data) {
688
+ if( data != null ) {
689
+ if( typeof data.output != 'undefined' ) {
690
+ $row.replaceWith( data.output ).show();
691
  wpcfDisableControls();
692
+ $( '#wpcf-pr-update-' + rand + '' ).remove();
693
+ wpcfRelationshipInit( '', 'save' );
694
  tChildTable.reset();
695
+ if( typeof wptCallbacks != 'undefined' ) {
696
+ wptCallbacks.reset.fire( '#' + rowId );
697
  }
698
+ if( 'undefined' != typeof wptFile ) {
699
  wptFile.init();
700
  }
701
  }
702
+ if( typeof data.conditionals != 'undefined' && typeof wptCond != 'undefined' ) {
703
+ wptCond.addConditionals( data.conditionals );
704
  }
705
  /**
706
  * rebind images
707
  */
708
+ if( 'function' == typeof bind_colorbox_to_thumbnail_preview ) {
709
  bind_colorbox_to_thumbnail_preview();
710
  }
711
  /**
712
  * show errors
713
  */
714
+ $( '#wpcf-post-relationship div.message' ).detach();
715
+ if( 'undefined' != typeof data.errors && 0 < data.errors.length ) {
716
+ $( '#wpcf-post-relationship h3.hndle' ).after( data.errors );
717
  }
718
  /**
719
  * select2
720
  */
721
  wpcfInitValueOfSelect2DoneClear();
722
+ wpcfBindSelect2( $ );
723
+
724
+ var data_for_events = {
725
+ table: $table
726
+ };
727
+
728
+ $( document ).trigger( 'js_event_wpcf_types_relationship_child_saved', [ data_for_events ] );
729
  }
730
+ },
731
+ complete: function() {
732
+ typesRelationControlsAjaxComplete();
733
  }
734
  });
735
  return false;
1119
  jQuery( 'input[name^="save"]' ).removeAttr( 'disabled' );
1120
  }
1121
 
1122
+ function typesRelationControlsAjaxStart() {
1123
  wpcfDisableControls();
1124
+ }
1125
 
1126
+ function typesRelationControlsAjaxComplete() {
1127
  if( jQuery.active == 1 ) {
1128
  wpcfEnableControls();
1129
  }
1130
+ }
help.php CHANGED
@@ -244,7 +244,7 @@ function wpcf_admin_help($page, $contextual_help)
244
  .'<dd>'.__('Choose which taxonomies are to be associated with this post type.', 'wpcf').'</dd>'
245
  .'<dt>'.__('Labels', 'wpcf').'</dt>'
246
  .'<dd>'.__('Labels are the text that is attached to your post type name. Examples of them in use are “Add New Post” (where “Add New” is the label”) and “Edit Post” (where “Edit” is the label). In normal circumstances the defaults will suffice.', 'wpcf').'</dd>'
247
- .'<dt>'.__('Custom Post Properites', 'wpcf').'</dt>'
248
  .'<dd>'.__('Choose which sections to display on your “Add New” page.', 'wpcf').'</dd>'
249
  .'<dt>'.__('Advanced Settings', 'wpcf').'</dt>'
250
  .'<dd>'.__('Advanced settings give you even more control over your post type. You can read in detail what all of these settings do on our tutorial.', 'wpcf').'</dd>'
244
  .'<dd>'.__('Choose which taxonomies are to be associated with this post type.', 'wpcf').'</dd>'
245
  .'<dt>'.__('Labels', 'wpcf').'</dt>'
246
  .'<dd>'.__('Labels are the text that is attached to your post type name. Examples of them in use are “Add New Post” (where “Add New” is the label”) and “Edit Post” (where “Edit” is the label). In normal circumstances the defaults will suffice.', 'wpcf').'</dd>'
247
+ .'<dt>'.__('Custom Post Properties', 'wpcf').'</dt>'
248
  .'<dd>'.__('Choose which sections to display on your “Add New” page.', 'wpcf').'</dd>'
249
  .'<dt>'.__('Advanced Settings', 'wpcf').'</dt>'
250
  .'<dd>'.__('Advanced settings give you even more control over your post type. You can read in detail what all of these settings do on our tutorial.', 'wpcf').'</dd>'
includes/classes/class.types.admin.edit.fields.php CHANGED
@@ -628,11 +628,6 @@ abstract class Types_Admin_Edit_Fields extends Types_Admin
628
  protected function fields_begin()
629
  {
630
  $form = array();
631
- $form['fields-header'] = array(
632
- '#type' => 'markup',
633
- '#markup' => sprintf('<h2>%s</h2>', __('Fields', 'wpcf')),
634
- '_builtin' => true,
635
- );
636
  $form += $this->button_add_new();
637
  return $form;
638
  }
628
  protected function fields_begin()
629
  {
630
  $form = array();
 
 
 
 
 
631
  $form += $this->button_add_new();
632
  return $form;
633
  }
includes/classes/class.types.admin.edit.post.type.php CHANGED
@@ -219,10 +219,24 @@ class Types_Admin_Edit_Post_Type extends Types_Admin
219
  update_option( WPCF_OPTION_NAME_CUSTOM_TAXONOMIES, $custom_taxonomies);
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  /**
223
  * post icon field
224
  */
225
- $menu_icon = isset( $this->ct['icon']) && !empty($this->ct['icon']) ? $this->ct['icon'] : 'admin-post';
226
  $form['icon'] = array(
227
  '#type' => 'hidden',
228
  '#name' => 'ct[icon]',
@@ -323,9 +337,11 @@ class Types_Admin_Edit_Post_Type extends Types_Admin
323
  );
324
 
325
  // disable for inbuilt
326
- if ( $this->ct['_builtin'] )
327
  $form['slug']['#disable'] = 1;
328
-
 
 
329
 
330
  $form['description'] = array(
331
  '#type' => 'textarea',
@@ -376,7 +392,7 @@ class Types_Admin_Edit_Post_Type extends Types_Admin
376
  */
377
  if ( $this->ct['_builtin'] ) {
378
  $form['choose-icon']['#disable'] = 1;
379
- $form['choose-icon']['#description'] = __('These options are not available for built-in post types.', 'wpcf');
380
  }
381
  }
382
  $form['table-1-close'] = array(
@@ -563,14 +579,16 @@ class Types_Admin_Edit_Post_Type extends Types_Admin
563
  /**
564
  * dashboard glance option to show counters on admin dashbord widget
565
  */
566
- $form['dashboard_glance'] = array(
567
- '#type' => 'checkbox',
568
- '#before' => '<div class="misc-pub-section">',
569
- '#after' => '</div>',
570
- '#name' => 'ct[dashboard_glance]',
571
- '#title' => __( 'Show number of entries on "At a Glance" admin widget.', 'wpcf' ),
572
- '#default_value' => !empty( $this->ct['dashboard_glance'] ),
573
- );
 
 
574
 
575
  $form = $this->submitdiv($button_text, $form);
576
 
@@ -734,7 +752,7 @@ class Types_Admin_Edit_Post_Type extends Types_Admin
734
  '#type' => 'checkbox',
735
  '#name' => 'ct[query_var_enabled]',
736
  '#title' => 'query_var',
737
- '#description' => __( 'False to prevent queries, or string value of the query var to use for this post type.', 'wpcf' ) . '<br />' . __( 'Default: true - set to $post_type.', 'wpcf' ),
738
  '#default_value' => !empty( $this->ct['query_var_enabled'] ),
739
  '#after' => '<div id="wpcf-types-form-queryvar-toggle"' . $hidden . '><input type="text" name="ct[query_var]" value="' . $query_var . '" class="regular-text" /><div class="description wpcf-form-description wpcf-form-description-checkbox description-checkbox">' . __( 'Optional', 'wpcf' ) . '. ' . __( 'String to customize query var', 'wpcf' ) . '</div></div>',
740
  '#inline' => true,
@@ -762,7 +780,7 @@ class Types_Admin_Edit_Post_Type extends Types_Admin
762
  '#type' => 'textfield',
763
  '#name' => 'ct[rest_base]',
764
  '#title' => __( 'Rest Base', 'wpcf' ),
765
- '#description' => __( 'Whether to expose this post type in the REST API.', 'wpcf' ) . '<br />' . __( 'Default: $post_type.', 'wpcf' ),
766
  '#value' => isset( $this->ct['rest_base'] ) ? $this->ct['rest_base'] : '',
767
  '#inline' => true,
768
  );
@@ -1647,6 +1665,15 @@ class Types_Admin_Edit_Post_Type extends Types_Admin
1647
  if ( isset( $fields['fields'] ) && is_array($fields['fields'])) {
1648
  $allowed_keys = wpcf_post_relationship_get_specific_fields_keys($child);
1649
  foreach( $fields['fields'] as $key => $value ) {
 
 
 
 
 
 
 
 
 
1650
  /**
1651
  * sanitize Taxonomy
1652
  */
219
  update_option( WPCF_OPTION_NAME_CUSTOM_TAXONOMIES, $custom_taxonomies);
220
  }
221
 
222
+ /*
223
+ * menu icon
224
+ */
225
+ switch( $this->ct['slug'] ) {
226
+ case 'page':
227
+ $menu_icon = 'admin-page';
228
+ break;
229
+ case 'attachment':
230
+ $menu_icon = 'admin-media';
231
+ break;
232
+ default:
233
+ $menu_icon = isset( $this->ct['icon']) && !empty($this->ct['icon']) ? $this->ct['icon'] : 'admin-post';
234
+ break;
235
+ }
236
+
237
  /**
238
  * post icon field
239
  */
 
240
  $form['icon'] = array(
241
  '#type' => 'hidden',
242
  '#name' => 'ct[icon]',
337
  );
338
 
339
  // disable for inbuilt
340
+ if ( $this->ct['_builtin'] ) {
341
  $form['slug']['#disable'] = 1;
342
+ $form['slug']['#pattern'] = '<tr><td><LABEL></td><td><ERROR><BEFORE><ELEMENT><DESCRIPTION><AFTER></td></tr>';
343
+ $form['slug']['#description'] = __('This option is not available for built-in post types.', 'wpcf');
344
+ }
345
 
346
  $form['description'] = array(
347
  '#type' => 'textarea',
392
  */
393
  if ( $this->ct['_builtin'] ) {
394
  $form['choose-icon']['#disable'] = 1;
395
+ $form['choose-icon']['#description'] = __('This option is not available for built-in post types.', 'wpcf');
396
  }
397
  }
398
  $form['table-1-close'] = array(
579
  /**
580
  * dashboard glance option to show counters on admin dashbord widget
581
  */
582
+ if( $this->ct['slug'] != 'post' && $this->ct['slug'] != 'page' ) {
583
+ $form['dashboard_glance'] = array(
584
+ '#type' => 'checkbox',
585
+ '#before' => '<div class="misc-pub-section">',
586
+ '#after' => '</div>',
587
+ '#name' => 'ct[dashboard_glance]',
588
+ '#title' => __( 'Show number of entries on "At a Glance" admin widget.', 'wpcf' ),
589
+ '#default_value' => !empty( $this->ct['dashboard_glance'] ),
590
+ );
591
+ }
592
 
593
  $form = $this->submitdiv($button_text, $form);
594
 
752
  '#type' => 'checkbox',
753
  '#name' => 'ct[query_var_enabled]',
754
  '#title' => 'query_var',
755
+ '#description' => __( 'Disable to prevent queries like "mysite.com/?post_type=example". Enable to use queries like "mysite.com/?post_type=example". Enable and set a value to use queries like "mysite.com/?query_var_value=example"', 'wpcf' ) . '<br />' . __( 'Default: true - set to $post_type.', 'wpcf' ),
756
  '#default_value' => !empty( $this->ct['query_var_enabled'] ),
757
  '#after' => '<div id="wpcf-types-form-queryvar-toggle"' . $hidden . '><input type="text" name="ct[query_var]" value="' . $query_var . '" class="regular-text" /><div class="description wpcf-form-description wpcf-form-description-checkbox description-checkbox">' . __( 'Optional', 'wpcf' ) . '. ' . __( 'String to customize query var', 'wpcf' ) . '</div></div>',
758
  '#inline' => true,
780
  '#type' => 'textfield',
781
  '#name' => 'ct[rest_base]',
782
  '#title' => __( 'Rest Base', 'wpcf' ),
783
+ '#description' => __( 'The base slug that this post type will use when accessed using the REST API.', 'wpcf' ) . '<br />' . __( 'Default: $post_type.', 'wpcf' ),
784
  '#value' => isset( $this->ct['rest_base'] ) ? $this->ct['rest_base'] : '',
785
  '#inline' => true,
786
  );
1665
  if ( isset( $fields['fields'] ) && is_array($fields['fields'])) {
1666
  $allowed_keys = wpcf_post_relationship_get_specific_fields_keys($child);
1667
  foreach( $fields['fields'] as $key => $value ) {
1668
+
1669
+ // other parent cpts
1670
+ if ( '_wpcf_pr_parents' == $key ) {
1671
+ $relationships[$parent][$child]['fields'][$key] = array();
1672
+ foreach( array_keys($value) as $parents) {
1673
+ $relationships[$parent][$child]['fields'][$key][$parents] = 1;
1674
+ }
1675
+ }
1676
+
1677
  /**
1678
  * sanitize Taxonomy
1679
  */
includes/classes/class.types.admin.edit.taxonomy.php CHANGED
@@ -495,7 +495,7 @@ class Types_Admin_Edit_Taxonomy extends Types_Admin
495
  '#type' => 'checkbox',
496
  '#name' => 'ct[query_var_enabled]',
497
  '#title' => 'query_var',
498
- '#description' => __( 'False to prevent queries, or string to customize query var. Default will use $taxonomy as query var.', 'wpcf' ) . '<br />' . __( 'Default: $taxonomy.', 'wpcf' ),
499
  '#default_value' => !empty( $this->ct['query_var_enabled'] ),
500
  '#after' => '<div id="wpcf-types-form-queryvar-toggle"' . $hidden . '><input type="text" name="ct[query_var]" value="' . $query_var . '" class="regular-text wpcf-form-textfield form-textfield textfield" /><div class="description wpcf-form-description wpcf-form-description-checkbox description-checkbox">' . __( 'Optional', 'wpcf' ) . '. ' . __( 'String to customize query var', 'wpcf' ) . '</div></div>',
501
  '#inline' => true,
495
  '#type' => 'checkbox',
496
  '#name' => 'ct[query_var_enabled]',
497
  '#title' => 'query_var',
498
+ '#description' => __( 'Disable to prevent queries like "mysite.com/?taxonomy=example". Enable to use queries like "mysite.com/?taxonomy=example". Enable and set a value to use queries like "mysite.com/?query_var_value=example"', 'wpcf' ) . '<br />' . __( 'Default: true - set to $taxonomy.', 'wpcf' ),
499
  '#default_value' => !empty( $this->ct['query_var_enabled'] ),
500
  '#after' => '<div id="wpcf-types-form-queryvar-toggle"' . $hidden . '><input type="text" name="ct[query_var]" value="' . $query_var . '" class="regular-text wpcf-form-textfield form-textfield textfield" /><div class="description wpcf-form-description wpcf-form-description-checkbox description-checkbox">' . __( 'Optional', 'wpcf' ) . '. ' . __( 'String to customize query var', 'wpcf' ) . '</div></div>',
501
  '#inline' => true,
includes/classes/class.types.dashboard.php CHANGED
@@ -22,12 +22,6 @@ class Types_Dashboard extends Types_Admin
22
  'title' => __('Types Tools', 'wpcf'),
23
  'default' => 'normal',
24
  ),
25
- 'types_admin_dashboard_site_type' => array(
26
- 'callback' => array($this, 'box_site_type'),
27
- 'title' => __('Do you need a help?', 'wpcf'),
28
- 'default' => 'side',
29
- // 'priority' => 'core',
30
- ),
31
  );
32
  }
33
 
@@ -141,20 +135,5 @@ class Types_Dashboard extends Types_Admin
141
  }
142
  echo '</ul>';
143
  }
144
-
145
- public function box_site_type()
146
- {
147
- $marketing = new WPCF_Types_Marketing_Messages();
148
- ?>
149
- <div class="wrap wp-types select-kind">
150
- <p><?php _e('<b>Select what kind of site you are building</b> and <b>we will advise you</b> about what features are needed and how to use them:', 'wpcf'); ?></p>
151
- <form method="post">
152
- <?php wp_nonce_field('update', 'marketing'); ?>
153
- <?php $marketing->kind_list(); ?>
154
- <a href="#" id="wcpf-getting-started-button" class="button"><?php _e('Show me!', 'wpcf'); ?></a>
155
- </form>
156
- </div>
157
- <?php
158
- }
159
  }
160
 
22
  'title' => __('Types Tools', 'wpcf'),
23
  'default' => 'normal',
24
  ),
 
 
 
 
 
 
25
  );
26
  }
27
 
135
  }
136
  echo '</ul>';
137
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  }
139
 
includes/classes/class.wpcf.marketing.messages.php CHANGED
@@ -28,7 +28,6 @@ class WPCF_Types_Marketing_Messages extends WPCF_Types_Marketing
28
  {
29
  parent::__construct();
30
  add_action('admin_enqueue_scripts', array($this, 'register_scripts'), 1);
31
- add_action('admin_notices', array($this, 'add_message_after_activate'));
32
  $this->set_state();
33
  $this->taxonomies = new Types_Admin_Taxonomies();
34
  }
@@ -65,16 +64,16 @@ class WPCF_Types_Marketing_Messages extends WPCF_Types_Marketing
65
 
66
  private function get_data()
67
  {
68
- /**
69
- * check kind
70
- */
71
- $kind = $this->get_kind();
72
- /**
73
- * get default
74
- */
75
- if ( empty($kind) ) {
76
- $kind = $this->get_default_kind();
77
- }
78
  /**
79
  * check exists?
80
  */
@@ -223,6 +222,7 @@ class WPCF_Types_Marketing_Messages extends WPCF_Types_Marketing
223
  echo '<div class="updated"><p>', $message, '</p></div>';
224
  }
225
 
 
226
  public function update_options()
227
  {
228
  if(!isset($_POST['marketing'])) {
@@ -231,14 +231,6 @@ class WPCF_Types_Marketing_Messages extends WPCF_Types_Marketing
231
  if ( !wp_verify_nonce($_POST['marketing'], 'update')) {
232
  return;
233
  }
234
- if (
235
- array_key_exists($this->option_name, $_POST)
236
- && array_key_exists($_POST[$this->option_name], $this->options)
237
- ) {
238
- if ( !add_option($this->option_name, $_POST[$this->option_name], '', 'no') ) {
239
- update_option($this->option_name, $_POST[$this->option_name]);
240
- }
241
- }
242
  $this->set_state();
243
  }
244
 
@@ -247,37 +239,6 @@ class WPCF_Types_Marketing_Messages extends WPCF_Types_Marketing
247
  delete_option($this->option_name);
248
  }
249
 
250
- public function get_kind_list()
251
- {
252
- $type = get_option($this->option_name);
253
- $content = '<ul class="marketing-kind-list">';
254
- foreach( $this->options as $key => $one ) {
255
- $content .= '<li>';
256
- $content .= sprintf(
257
- '<input type="radio" name="%s" value="%s" id="getting_started_%s" %s/>',
258
- $this->get_option_name(),
259
- $key,
260
- $key,
261
- $type == $key? ' checked="checked" ':''
262
- );
263
- $content .= sprintf(
264
- '<label for="getting_started_%s"> <strong>%s</strong>%s%s</label>',
265
- $key,
266
- $one['title'],
267
- array_key_exists('description', $one)? ' | ':'',
268
- array_key_exists('description', $one)? $one['description']:''
269
- );
270
- $content .= '</li>';
271
- }
272
- $content .= '</ul>';
273
- return $content;
274
- }
275
-
276
- public function kind_list()
277
- {
278
- echo $this->get_kind_list();
279
- }
280
-
281
  public function show_top($update = true)
282
  {
283
  $data = $this->get_data();
@@ -291,7 +252,15 @@ class WPCF_Types_Marketing_Messages extends WPCF_Types_Marketing
291
  if ( isset($data['link']) ) {
292
  $content .= sprintf(
293
  '<a href="%s">%s</a>',
294
- $this->add_ga_campain($data['link'], 'save-updated'),
 
 
 
 
 
 
 
 
295
  $data['description']
296
  );
297
  } else {
@@ -313,41 +282,5 @@ class WPCF_Types_Marketing_Messages extends WPCF_Types_Marketing
313
  return $content;
314
  }
315
 
316
- public function get_content()
317
- {
318
- if ( $url = $this->get_kind_url() ) {
319
- include_once dirname(__FILE__).'/class.wpcf.marketing.tutorial.php';
320
- $tutorial = new WPCF_Types_Marketing_Tutorial();
321
- return $tutorial->get_content('kind');
322
- }
323
- return;
324
- }
325
-
326
- public function add_message_after_activate()
327
- {
328
- if ( !isset($_GET['activate']) ) {
329
- return;
330
- }
331
- if ( is_multisite() ) {
332
- return;
333
- }
334
- if ( 'show' != get_option('types_show_on_activate') ) {
335
- return;
336
- }
337
- wp_enqueue_style('onthego-admin-styles');
338
- wp_enqueue_style('wpcf-css-embedded');
339
- $data = array(
340
- 'header' => __('Need help with <em>Types</em>?', 'wpcf'),
341
- 'text' => __('Types plugin includes a lot of options. Tell us what kind of site you are building and we\'ll show you how to use Types in the best way.', 'wpcf'),
342
- 'button_primary_url' => esc_url(add_query_arg( 'page', basename(dirname(dirname(__FILE__))).'/marketing/getting-started/index.php', admin_url('admin.php') )),
343
- 'button_primary_text' => __('Get Started', 'wpcf'),
344
- 'button_dismiss_url' => '',
345
- 'button_dismiss_text' => __('Dismiss', 'wpcf'),
346
- );
347
- wp_localize_script('marketing-getting-started', 'types_activate', $data);
348
- wp_enqueue_script('marketing-getting-started');
349
- update_option('types_show_on_activate', 'hide');
350
- }
351
-
352
  }
353
 
28
  {
29
  parent::__construct();
30
  add_action('admin_enqueue_scripts', array($this, 'register_scripts'), 1);
 
31
  $this->set_state();
32
  $this->taxonomies = new Types_Admin_Taxonomies();
33
  }
64
 
65
  private function get_data()
66
  {
67
+ /*
68
+ * Legacy
69
+ *
70
+ * THere was a time where we had a weird getting started page, and $kind was stored depending on a user selection
71
+ * It was one of the following values: brochure | directory_classifieds | classifieds | e-commerce | blog
72
+ * It sets which message is shown when updating a post type, taxonomy or fields group
73
+ * As we are reviewing marketing messages it might be a good time to do it.
74
+ */
75
+ $kind = 'brochure';
76
+
77
  /**
78
  * check exists?
79
  */
222
  echo '<div class="updated"><p>', $message, '</p></div>';
223
  }
224
 
225
+ // @todo this might be deprecated, could not locate where this is being triggered...
226
  public function update_options()
227
  {
228
  if(!isset($_POST['marketing'])) {
231
  if ( !wp_verify_nonce($_POST['marketing'], 'update')) {
232
  return;
233
  }
 
 
 
 
 
 
 
 
234
  $this->set_state();
235
  }
236
 
239
  delete_option($this->option_name);
240
  }
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  public function show_top($update = true)
243
  {
244
  $data = $this->get_data();
252
  if ( isset($data['link']) ) {
253
  $content .= sprintf(
254
  '<a href="%s">%s</a>',
255
+ esc_url(
256
+ add_query_arg(
257
+ array(
258
+ 'utm_source' => 'typesplugin',
259
+ 'utm_medium' => 'save-updated',
260
+ ),
261
+ $data['link']
262
+ )
263
+ ),
264
  $data['description']
265
  );
266
  } else {
282
  return $content;
283
  }
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  }
286
 
includes/classes/class.wpcf.marketing.php CHANGED
@@ -25,10 +25,8 @@ class WPCF_Types_Marketing
25
 
26
  public function __construct()
27
  {
28
- $this->options = include WPCF_ABSPATH.'/marketing/etc/types-site-kinds.php';
29
  $this->adverts = include WPCF_ABSPATH.'/marketing/etc/types.php';
30
- add_filter('admin_body_class', array($this, 'admin_body_class'));
31
- add_action( 'wpcf_menu_plus', array( $this, 'add_getting_started_to_admin_menu'), PHP_INT_MAX);
32
  add_filter('editor_addon_dropdown_after_title', array($this, 'add_views_advertising'));
33
  }
34
 
@@ -103,21 +101,6 @@ class WPCF_Types_Marketing
103
  return $content;
104
  }
105
 
106
- public function admin_body_class($classes)
107
- {
108
- $screen = get_current_screen();
109
- if ( isset($screen->id) && preg_match( '@marketing/getting-started/index$@', $screen->id ) ) {
110
- if ( !isset($_GET['kind'] )) {
111
- $classes = 'wpcf-marketing';
112
- }
113
- else if ( isset($_POST['marketing'])) {
114
- $classes = 'wpcf-marketing';
115
- }
116
- }
117
-
118
- return $classes;
119
- }
120
-
121
  protected function get_page_type() {
122
  $screen = get_current_screen();
123
  switch ( $screen->id ) {
@@ -144,48 +127,6 @@ class WPCF_Types_Marketing
144
  return $this->option_name;
145
  }
146
 
147
- public function get_default_kind()
148
- {
149
- if ( isset($this->options) && is_array($this->options) ) {
150
- foreach ( $this->options as $kind => $options ) {
151
- if ( array_key_exists('default', $options ) && $options['default']) {
152
- return $kind;
153
- }
154
- }
155
- }
156
- return false;
157
- }
158
-
159
- public function get_kind()
160
- {
161
- $kind = get_option($this->option_name, false);
162
- if (
163
- $kind
164
- && isset($this->options)
165
- && is_array($this->options)
166
- && array_key_exists( $kind, $this->options )
167
- ) {
168
- return $kind;
169
- }
170
- return false;
171
- }
172
-
173
- public function get_kind_url($kind = false)
174
- {
175
- if ( empty($kind) ) {
176
- $kind = $this->get_kind();
177
- }
178
- if (
179
- $kind
180
- && isset($this->options)
181
- && is_array($this->options)
182
- && array_key_exists('url', $this->options[$kind] )
183
- ) {
184
- return $this->options[$kind]['url'];
185
- }
186
- return;
187
- }
188
-
189
  public function get_option_disiable_value()
190
  {
191
  return get_option($this->option_disable, 0);
@@ -196,40 +137,4 @@ class WPCF_Types_Marketing
196
  return $this->option_disable;
197
  }
198
 
199
- protected function add_ga_campain($url, $utm_medium = 'getting-started')
200
- {
201
- return esc_url(
202
- add_query_arg(
203
- array(
204
- 'utm_source' => 'typesplugin',
205
- 'utm_medium' => $utm_medium,
206
- 'utm_campaign' => sprintf('%s-howto', $this->get_kind() ),
207
- ),
208
- $url
209
- )
210
- );
211
- }
212
-
213
- /**
214
- * add Getting Started to menu
215
- */
216
- public function add_getting_started_to_admin_menu()
217
- {
218
- if ( !isset($_REQUEST['page']) ) {
219
- return;
220
- }
221
- $slug = basename(dirname(dirname(dirname(__FILE__)))).'/marketing/getting-started/index.php';
222
- if( $_REQUEST['page'] != $slug ) {
223
- return;
224
- }
225
- $menu = array(
226
- 'page_title' => __( 'What kind of site are you building?', 'wpcf' ),
227
- 'menu_title' => __( 'Getting Started', 'wpcf' ),
228
- 'menu_slug' => $slug,
229
- 'hook' => 'wpcf_marketing',
230
- 'load_hook' => 'wpcf_marketing_hook',
231
- );
232
- wpcf_admin_add_submenu_page($menu);
233
- }
234
-
235
  }
25
 
26
  public function __construct()
27
  {
28
+ $this->options = array();
29
  $this->adverts = include WPCF_ABSPATH.'/marketing/etc/types.php';
 
 
30
  add_filter('editor_addon_dropdown_after_title', array($this, 'add_views_advertising'));
31
  }
32
 
101
  return $content;
102
  }
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  protected function get_page_type() {
105
  $screen = get_current_screen();
106
  switch ( $screen->id ) {
127
  return $this->option_name;
128
  }
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  public function get_option_disiable_value()
131
  {
132
  return get_option($this->option_disable, 0);
137
  return $this->option_disable;
138
  }
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
includes/classes/class.wpcf.marketing.tutorial.php DELETED
@@ -1,243 +0,0 @@
1
- <?php
2
- /**
3
- *
4
- * Types Tutorial Class
5
- *
6
- *
7
- */
8
-
9
- include_once dirname(__FILE__).'/class.wpcf.marketing.php';
10
-
11
- /**
12
- * Types Tutorial Class
13
- *
14
- * @since Types 1.6.5
15
- * @package Types
16
- * @subpackage Classes
17
- * @version 0.1
18
- * @category Help
19
- * @author marcin <marcin.p@icanlocalize.com>
20
- */
21
- class WPCF_Types_Marketing_Tutorial extends WPCF_Types_Marketing
22
- {
23
- private $id;
24
- private $cache;
25
- private $tutorials;
26
-
27
- public function __construct()
28
- {
29
- parent::__construct();
30
- }
31
-
32
- private function error($error_id, $message = false)
33
- {
34
- $content = wpcf_add_admin_header(__('Tutorial error', 'wpcf'));
35
- $content .= '<div class="error settings-error"><p><strong>';
36
- switch( $error_id ) {
37
- case 'no id':
38
- case 'wrong id':
39
- $content .= __('Wrong tutorial id.', 'wpcf');
40
- break;
41
- case 'empty url':
42
- case 'wrong response status':
43
- case 'http request failed':
44
- $content .= __('There is a problem with tutorial url.', 'wpcf');
45
- break;
46
- case 'empty body':
47
- $content .= __('Selected tutorial is empty.', 'wpcf');
48
- if ( current_user_can('manage_options') ) {
49
- }
50
- break;
51
- default:
52
- if ( $message ) {
53
- $content .= $message;
54
- } else {
55
- $content .= __('Some error occured.', 'wpcf');
56
- }
57
- }
58
- $content .= '</strong></p></div>';
59
- return $content;
60
- }
61
-
62
- private function produce($url = false)
63
- {
64
- if ( empty( $url ) ) {
65
- $url = $this->get('url');
66
- }
67
- if ( empty($url) ) {
68
- return $this->error('empty url');
69
- }
70
- $url = $this->add_ga_campain($url, 'fetch-data');
71
-
72
- $resp = wp_safe_remote_get($url, array('timeout' => 30));
73
-
74
- if ( is_wp_error( $resp ) ) {
75
- /**
76
- * if user can manage_options then display a real error message
77
- */
78
- if( current_user_can('manage_options') ) {
79
- return $this->error(false, $resp->get_error_message());
80
- } else {
81
- return $this->error('http request failed');
82
- }
83
- }
84
-
85
- if ( 200 != $resp['response']['code'] ) {
86
- return $this->error('wrong response status');
87
- }
88
- $title_temp = preg_split('/<h1>/', $resp['body']);
89
- $title_temp_temp = isset( $title_temp[1] ) ? preg_split('@</h1>@', $title_temp[1]) : array( '' );
90
- $title = $title_temp_temp[0];
91
-
92
- $body = '';
93
- $containers = preg_split( '/<div class="container">/', $resp['body'] );
94
- foreach( $containers as $container ) {
95
- if ( !preg_match('/<div class="col-sm-[\d]+ post-content[^>]+>/', $container) ) {
96
- continue;
97
- }
98
- $body = $container;
99
-
100
- }
101
- if ( empty( $body ) ) {
102
- return $this->error('empty body');
103
- }
104
- $body = preg_split('/<aside/', $body);
105
- $body = $body[0];
106
- if ( empty( $body ) ) {
107
- return $this->error('empty body');
108
- }
109
- $body = sprintf(
110
- '<h1 class="title">%s</h1><div class="container"><div class="post-content">%s',
111
- $title,
112
- $body
113
- );
114
- set_transient( $this->cache, $body, 14 * DAY_IN_SECONDS);
115
- return $body;
116
- }
117
-
118
- private function add_select_site_kind_intruction()
119
- {
120
- $kind = $this->get_kind();
121
- if ( empty($kind) ) {
122
- return;
123
- }
124
- $content = '';
125
- /**
126
- * current url
127
- */
128
- $current_url = esc_url(
129
- add_query_arg(
130
- array( 'page' => basename(WPCF_ABSPATH).'/marketing/getting-started/index.php',),
131
- admin_url('admin.php')
132
- )
133
- );
134
- /**
135
- * add button to change site kind
136
- */
137
- $content .= sprintf(
138
- '<a class="button" href="%s">%s</a>',
139
- esc_url(add_query_arg( array( 'kind' => 'choose',), $current_url)),
140
- __('Select instructions for other kinds of sites', 'wpcf')
141
- );
142
- /**
143
- * add reload link
144
- */
145
- $content .= sprintf(
146
- ' <a class="alignright" href="%s">%s</a>',
147
- wp_nonce_url($current_url, 'reload', 'toolset'),
148
- __('Reload', 'wpcf')
149
- );
150
- return sprintf( '<div class="container wpcf-tutorial-other wpcf-notif"><p>%s</p></div>', $content);
151
- }
152
-
153
- public function get_content()
154
- {
155
- $class = ' class="wp-types-icon-external" ';
156
- $target = ' target="_blank" ';
157
-
158
- $url = $this->get_kind_url();
159
- $this->cache = md5($url);
160
- $content = get_transient($this->cache);
161
- /**
162
- * check force reload
163
- */
164
- $force_reload = isset($_GET['toolset']) && wp_verify_nonce($_GET['toolset'], 'reload');
165
- if ( $force_reload || false === apply_filters( 'tooleset_messages_get_transient', $content ) ) {
166
- $content = $this->produce($url);
167
- }
168
- /**
169
- * create array to replace
170
- */
171
- $replces = array(
172
- 'from' => array(),
173
- 'to' => array(),
174
- );
175
-
176
- $content = preg_replace('/(<a.*?)[ ]?target="_blank"(.*?)/', '$1$2', $content);
177
-
178
- /**
179
- * with '
180
- */
181
- preg_match_all('/href=\'([^\']+)\'/', $content, $matches );
182
- if ( $matches ) {
183
- foreach ( $matches[1] as $url ) {
184
- if ( !preg_match('/wp-types.com/', $url ) ) {
185
- continue;
186
- }
187
- $replces['from'][] = sprintf("|'%s'|", $url);
188
- $replces['to'][] = sprintf( "'%s'", $this->add_ga_campain($url).$class.$target);
189
- }
190
- }
191
- /**
192
- * with "
193
- */
194
- preg_match_all('/href="([^"]+)"/', $content, $matches );
195
- if ( $matches ) {
196
- foreach ( $matches[1] as $url ) {
197
- if ( !preg_match('/wp-types.com/', $url ) ) {
198
- continue;
199
- }
200
- $replces['from'][] = sprintf('|"%s"|', $url);
201
- $replces['to'][] = sprintf( '"%s"', $this->add_ga_campain($url)).$class.$target;
202
- }
203
- }
204
-
205
- //WP-Types External
206
-
207
- /**
208
- * with '
209
- */
210
- preg_match_all('/href=\'([^\']+)\'/', $content, $matches );
211
- if ( $matches ) {
212
- foreach ( $matches[1] as $url ) {
213
- if ( preg_match('/wp-types.com/', $url ) ) {
214
- continue;
215
- }
216
- $replces['from'][] = sprintf("|'%s'|", $url);
217
- $replces['to'][] = sprintf( "'%s'", $this->add_ga_campain($url).$class.$target);
218
- }
219
- }
220
- /**
221
- * with "
222
- */
223
- preg_match_all('/href="([^"]+)"/', $content, $matches );
224
- if ( $matches ) {
225
- foreach ( $matches[1] as $url ) {
226
- if ( preg_match('/wp-types.com/', $url ) ) {
227
- continue;
228
- }
229
- $replces['from'][] = sprintf('|"%s"|', $url);
230
- $replces['to'][] = sprintf( '"%s"', $this->add_ga_campain($url)).$class.$target;
231
- }
232
- }
233
-
234
-
235
-
236
- if (count($replces['from'])) {
237
- $content = preg_replace( $replces['from'], $replces['to'], $content );
238
- }
239
- $content .= $this->add_select_site_kind_intruction();
240
- return $content;
241
- }
242
-
243
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/classes/page/listing/abstract.php CHANGED
@@ -42,7 +42,7 @@ abstract class WPCF_Page_Listing_Abstract extends WPCF_Page_Abstract {
42
  *
43
  * @param array[] $all_submenus
44
  * @param array $submenu_to_add
45
- *
46
  * @return array
47
  */
48
  protected function add_submenu_at_the_end( $all_submenus, $submenu_to_add ) {
42
  *
43
  * @param array[] $all_submenus
44
  * @param array $submenu_to_add
45
+ * @deprecated Use WPCF_Utils::insert_at_position() instead.
46
  * @return array
47
  */
48
  protected function add_submenu_at_the_end( $all_submenus, $submenu_to_add ) {
includes/conditional-display.php CHANGED
@@ -660,6 +660,10 @@ function wpcf_conditional_get_curent($data)
660
  mktime( 0, 0, 0, $condition['date'], $condition['month'], $condition['year'] )
661
  );
662
  }
 
 
 
 
663
  $current .= sprintf(
664
  '<li><span>%s %s %s</span></li>',
665
  esc_html($all_types_fields[$condition['field']]['name']),
660
  mktime( 0, 0, 0, $condition['date'], $condition['month'], $condition['year'] )
661
  );
662
  }
663
+
664
+ /* remove operators description */
665
+ $operation = preg_replace( '#\([^)]+\)#', '', $operation );
666
+
667
  $current .= sprintf(
668
  '<li><span>%s %s %s</span></li>',
669
  esc_html($all_types_fields[$condition['field']]['name']),
marketing/etc/types-site-kinds.php DELETED
@@ -1,36 +0,0 @@
1
- <?php
2
-
3
- return array(
4
- 'brochure' => array(
5
- 'title' => __('Brochure', 'wpcf'),
6
- 'description' => __('static content displayed in different ways', 'wpcf'),
7
- 'url' => __('http://wp-types.com/how-to/develop-brochure-site-wordpress/' , 'wpcf'),
8
- 'default' => true,
9
- ),
10
- // 'directory' => array(
11
- // 'title' => __('Directory', 'wpcf'),
12
- // 'url' => __('http://wp-types.com/how-to/develop-directory-site-toolset/', 'wpcf'),
13
- // ),
14
- // 'classifieds' => array(
15
- // 'title' => __('Classifieds', 'wpcf'),
16
- // 'description' => __('user-submitted content organized by categories', 'wpcf'),
17
- // 'url' => __('http://wp-types.com/how-to/', 'wpcf'),
18
- // ),
19
- 'directory_classifieds' => array(
20
- 'title' => __('Directory and Classifieds', 'wpcf'),
21
- 'url' => __('http://wp-types.com/how-to/develop-directory-site-toolset/', 'wpcf'),
22
- ),
23
- 'e-commerce' => array(
24
- 'title' => __('E-Commerce', 'wpcf'),
25
- 'url' => __('http://wp-types.com/how-to/develop-e-commerce-site-toolset/', 'wpcf'),
26
- ),
27
- 'blog' => array(
28
- 'title' => __('Blog / Magazine', 'wpcf'),
29
- 'description' => __('news sites with unique layouts', 'wpcf'),
30
- 'url' => __('http://wp-types.com/how-to/customise-wordpress-blog/', 'wpcf'),
31
- ),
32
- 'other' => array(
33
- 'title' => __('Something else', 'wpcf'),
34
- 'url' => __('http://wp-types.com/how-to/build-sites-toolset/', 'wpcf'),
35
- ),
36
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
marketing/getting-started/assets/css/getting-started.css DELETED
@@ -1,156 +0,0 @@
1
- body.wpcf-marketing #wpcontent
2
- {
3
- background-color: #fff;
4
- }
5
-
6
- .container:before
7
- ,.row:after
8
- {
9
- content: " ";
10
- display: table;
11
- }
12
-
13
- .row:aftter
14
- {
15
- clear: both;
16
- }
17
-
18
- .wp-types table
19
- {
20
- border-spacing: 30px 0px;
21
- border-collapse: separate;
22
- border-color: #666666;
23
- margin: 30px -30px;
24
- }
25
-
26
- .wp-types
27
- {
28
- max-width: 900px;
29
- text-rendering: optimizeSpeed;
30
- }
31
-
32
- .wp-types.about-wrap h1
33
- {
34
- margin-right: 0;
35
- margin-bottom: 40px;
36
- }
37
-
38
- .wp-types h2
39
- {
40
- margin: 30px 0 15px;
41
- }
42
-
43
-
44
-
45
- .wpcf-tutorial-other
46
- {
47
- border: 0 solid #f05a28;
48
- border-top-width: 1px;
49
- margin-top: 40px;
50
- padding: 5px 10px;
51
- }
52
-
53
- .wp-core-ui .wp-types.select-kind .button
54
- {
55
- background: #f05a28 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwDCxgmb+ZnVQAAAWpJREFUSMetlu9RwkAQxX8wfA8dYAeJFRArEDvQCrQDSmCsIHSAHRgrIB2AFQAVPD+452TiXe5O3JkdJpe3f7K3b5eJJCJSABVQD85b4CNmPB15twQa4AxsLYiTys5kmEXQi6ShFpI2+pZGUunBOC0NI7P5hfE535uOOfYFcnZF/92kdweF1RWr94U86dvf+kq08WWQqYWkg6T1sERLq+MioRS7BMyPL3e4C11S4I6aCK5xGGeUkn1OkFLSyQW4N4PcWseCHCQtZ0aaNrNjLsAK6Oz5yYM5AtXMHs4ewDMwjwRqgcdAkBaYT7lOjr3R4RX3Bb5MXxOJ1Vq5hlIDb1PLov4jazvgLsD6G6DD2jOnTcvcNkXSe5/eCYZZRHOj4pTwFesE595R4cbF/opBNzrscuZMjN371IWz+I+FE8pkZ3eyjgSKrsxZYM482NJ/MZ50pn3mVtbrW/v99BFmkvi3pfaMA0e00dX6BUDZUDXwvghBAAAAAElFTkSuQmCC) no-repeat 98% 50%;
56
- color: #fff;
57
- font-weight: 600;
58
- padding: 7px 45px 7px 11px;
59
- height: auto;
60
- border: 0;
61
- }
62
-
63
- .table>thead>tr>td
64
- ,.table>tbody>tr>td
65
- ,.table>tfoot>tr>td
66
- {
67
- padding: 15px 0;
68
- line-height: 1.42857143;
69
- vertical-align: top;
70
- border-top: 2px solid #333;
71
- }
72
- table>thead>tr>th
73
- ,.table>tbody>tr>th
74
- ,.table>tfoot>tr>th {
75
- font-weight: bold;
76
- color: #fff;
77
- background: #666666;
78
- vertical-align: middle;
79
- border: none;
80
- padding: 8px 15px;
81
- }
82
-
83
- .well
84
- {
85
- border-color: #dcdcdc;
86
- min-height: 20px;
87
- padding: 19px;
88
- margin-bottom: 20px;
89
- background-color: #f5f5f5;
90
- }
91
-
92
- .post-content th
93
- {
94
- text-align: left;
95
- }
96
-
97
- .post-content img
98
- {
99
- margin-top: 10px;
100
- margin-bottom: 10px;
101
- }
102
- .post-content img:not(.no-border) {
103
- padding: 4px;
104
- border: 1px solid #dcdcdc;
105
- background-color: #fafafa;
106
- }
107
- .post-content figure {
108
- margin: 0;
109
- padding-right: 10px
110
- }
111
- .post-content figcaption
112
- {
113
- box-sizing: border-box;
114
- color: #777;;
115
- display: block;
116
- font-size: 13px;
117
- font-style: italic;
118
- text-align: center;
119
- margin-top: -5px;
120
- margin-bottom: 15px;
121
- padding-left: 10px;
122
- }
123
-
124
- .wp-types ul
125
- {
126
- padding-left: 40px;
127
- list-style-type: disc;
128
- overflow: auto;
129
- }
130
-
131
- .wp-types .marketing-kind-list
132
- {
133
- margin-left: 0;
134
- list-style-type: none;
135
- }
136
-
137
- .wp-types .well h3
138
- {
139
- margin-top: 0;
140
- }
141
- .wp-types .alignright {
142
- margin-left: 15px;
143
- }
144
- .wp-types .alignleft {
145
- margin-right: 15px;
146
- padding-right: 10px;
147
- }
148
- .wp-types .alignnone {
149
- display: block;
150
- }
151
-
152
- a[target="_blank"]:after,
153
- .wp-types-icon-external:after {
154
- content: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAVklEQVR4Xn3PgQkAMQhDUXfqTu7kTtkpd5RA8AInfArtQ2iRXFWT2QedAfttj2FsPIOE1eCOlEuoWWjgzYaB/IkeGOrxXhqB+uA9Bfcm0lAZuh+YIeAD+cAqSz4kCMUAAAAASUVORK5CYII=");
155
- margin: 0 0 0 5px;
156
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
marketing/getting-started/assets/images/arrow.png DELETED
Binary file
marketing/getting-started/assets/scripts/getting-started.js DELETED
@@ -1,46 +0,0 @@
1
- /**
2
- *
3
- */
4
- jQuery( document ).ready(function($) {
5
-
6
- if ( 'undefined' != typeof marketing_getting_started ) {
7
- $('[name="'+marketing_getting_started.id+'"]').on('change', function() {
8
- $('#wcpf-getting-started-button').removeClass('disabled');
9
- });
10
- $('#wcpf-getting-started-button').on('click', function() {
11
- $(this).closest('form').submit();
12
- });
13
- }
14
-
15
- if ( 'undefined' != typeof types_activate ) {
16
- var html = '<div>';
17
- html += fill_with_tag('h2',types_activate.header);
18
- html += fill_with_tag('p',types_activate.text);
19
- var buttons = fill_with_tag('a', types_activate.button_primary_text, 'button button-primary');
20
- buttons += ' ';
21
- buttons += fill_with_tag('a', types_activate.button_dismiss_text, 'button-dismiss');
22
- html += fill_with_tag('p', buttons, 'buttons');
23
- html += '</div>';
24
- html += fill_with_tag('span', fill_with_tag('span', '', 'icon-types-logo'), 'logo');
25
- var parent = $('#message').html(html).removeClass('updated').addClass('toolset-message-after-activate');
26
- $('.button-primary', parent).on('click', function() {
27
- document.location = types_activate.button_primary_url;
28
- return false;
29
- });
30
- $('.button-dismiss', parent).on('click', function() {
31
- $('#message').detach();
32
- return false;
33
- });
34
-
35
- }
36
-
37
- function fill_with_tag(tag, text, css_class) {
38
- var html = '<'+tag;
39
- if ( css_class ) {
40
- html += ' class="'+css_class+'"';
41
- }
42
- html += '>'+text+'</'+tag+'>';
43
- return html;
44
- }
45
- });
46
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
marketing/getting-started/index.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
- /**
3
- *
4
- *
5
- */
6
- include_once WPCF_ABSPATH.'/includes/classes/class.wpcf.marketing.messages.php';
7
- $marketing = new WPCF_Types_Marketing_Messages();
8
- $marketing->update_options();
9
- $content = $marketing->get_content();
10
-
11
- if (
12
- empty($content)
13
- || ( isset($_GET['kind']) && !isset($_POST[$marketing->get_option_name()]) )
14
- ) {
15
- $marketing->delete_option_kind();
16
- ?>
17
- <div class="wrap wp-types select-kind">
18
- <h2><?php _e('What kind of site are you building?', 'wpcf') ?></h2>
19
- <?php settings_errors(); ?>
20
- <p><?php _e('Types plugin includes a lot of features and there are many possibilities. By selecting what kind of site you are building, you allow Types to advise you about what features are needed and how to use them.', 'wpcf'); ?></p>
21
- <form method="post">
22
- <?php wp_nonce_field('update', 'marketing'); ?>
23
- <?php $marketing->kind_list(); ?>
24
- <a href="#" id="wcpf-getting-started-button" class="button"><?php _e('Continue', 'wpcf'); ?></a>
25
- </form>
26
- </div>
27
- <?php } else {
28
- echo '<div class="wrap wp-types about-wrap">';
29
- echo $content;
30
- echo '</div>';
31
- }
32
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
plus/installer/changelog.txt CHANGED
@@ -1,3 +1,8 @@
 
 
 
 
 
1
  = 1.7.5 =
2
  * Fixed a bug causing registration to not be recognized for the entire network in the multi-site mode
3
 
1
+ = 1.7.6 =
2
+ * Updated error messages when validating site keys and stopped removing site keys in case of communication errors
3
+ * Added a note for users who renewed or purchased new subscriptions and who need to revalidate their subscription from their websites
4
+ * Fixed a problem with the registrations for multi-site setups when WordPress was installed in a separate folder
5
+
6
  = 1.7.5 =
7
  * Fixed a bug causing registration to not be recognized for the entire network in the multi-site mode
8
 
plus/installer/includes/class-installer-theme.php CHANGED
@@ -453,7 +453,14 @@ class Installer_Theme_Class {
453
  }
454
 
455
  //Let's add themes to the overriden WordPress API Theme response
456
- $res->themes = json_decode( json_encode( $themes ), FALSE );
 
 
 
 
 
 
 
457
  $res->themes = apply_filters( 'installer_theme_hook_response_theme', $res->themes );
458
  return $res;
459
  }
@@ -729,12 +736,16 @@ class Installer_Theme_Class {
729
  }
730
 
731
  /** WP Theme API compatibility- added num ratings */
 
732
  public function installer_theme_add_num_ratings( $themes ) {
733
 
734
  if ( (is_array( $themes )) && (!(empty($themes))) ) {
735
  foreach ( $themes as $k => $v ) {
736
  if ( !(isset($v->num_ratings)) ) {
737
- $themes[$k]->num_ratings = 0;
 
 
 
738
  }
739
  }
740
  }
453
  }
454
 
455
  //Let's add themes to the overriden WordPress API Theme response
456
+ /** Installer 1.7.6: Update to compatible data format response from WP Theme API */
457
+ $theme_compatible_array=array();
458
+ if ((is_array($themes))) {
459
+ foreach ($themes as $k=>$v) {
460
+ $theme_compatible_array[]=(object)($v);
461
+ }
462
+ }
463
+ $res->themes = $theme_compatible_array;
464
  $res->themes = apply_filters( 'installer_theme_hook_response_theme', $res->themes );
465
  return $res;
466
  }
736
  }
737
 
738
  /** WP Theme API compatibility- added num ratings */
739
+ /** Installer 1.7.6+ Added updated 'rating' field */
740
  public function installer_theme_add_num_ratings( $themes ) {
741
 
742
  if ( (is_array( $themes )) && (!(empty($themes))) ) {
743
  foreach ( $themes as $k => $v ) {
744
  if ( !(isset($v->num_ratings)) ) {
745
+ $themes[$k]->num_ratings = 100;
746
+ }
747
+ if ( !(isset($v->rating)) ) {
748
+ $themes[$k]->rating = 100;
749
  }
750
  }
751
  }
plus/installer/includes/installer.class.php CHANGED
@@ -280,57 +280,60 @@ final class WP_Installer{
280
 
281
  $repositories_plugins = array();
282
 
283
- foreach($this->settings['repositories'] as $repository_id => $repository){
284
 
285
- foreach($repository['data']['packages'] as $package){
286
-
287
- foreach($package['products'] as $product){
288
-
289
- foreach($product['plugins'] as $plugin_slug){
290
 
291
- $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
 
 
 
 
 
 
 
 
 
 
 
 
 
292
 
293
- if(!isset($repositories_plugins[$repository_id][$download['slug']])){
294
- $repositories_plugins[$repository_id][$download['slug']] = array(
295
- 'name' => $download['name'],
296
- 'registered' => $this->plugin_is_registered( $repository_id, $download['slug'] ) ? 1 : 0
297
- );
298
  }
299
-
300
  }
301
-
302
  }
303
-
304
- }
305
 
306
- foreach($plugins as $plugin_id => $plugin) {
307
 
308
- $wp_plugin_slug = dirname($plugin_id);
309
- if(empty($wp_plugin_slug)){
310
- $wp_plugin_slug = basename($plugin_id, '.php');
311
- }
312
 
313
- foreach($repositories_plugins as $repository_id => $r_plugins) {
314
 
315
- foreach($r_plugins as $slug => $r_plugin){
316
 
317
- if($wp_plugin_slug == $slug || $r_plugin['name'] == $plugin['Name'] || $r_plugin['name'] == $plugin['Title']) { //match order: slug, name, title
 
 
 
 
 
 
318
 
319
- if($r_plugin['registered']){
320
- add_filter( 'plugin_action_links_' . $plugin_id, array($this, 'plugins_action_links_registered'));
321
- }else{
322
- add_filter( 'plugin_action_links_' . $plugin_id, array($this, 'plugins_action_links_not_registered'));
323
  }
324
 
325
  }
326
 
327
  }
328
 
329
- }
330
 
 
331
 
332
  }
333
-
334
  }
335
 
336
  }
@@ -567,14 +570,17 @@ final class WP_Installer{
567
  }
568
 
569
  public function get_installer_site_url( $repository_id = false ){
 
 
570
  $site_url = get_site_url();
571
 
572
  if( $repository_id && is_multisite() && isset( $this->settings['repositories'] ) ){
573
  $network_settings = maybe_unserialize( get_site_option('wp_installer_network') );
574
 
575
  if ( isset( $network_settings[$repository_id] ) ) {
576
- $site_url = network_site_url();
577
  }
 
578
  }
579
 
580
  return $site_url;
@@ -955,7 +961,7 @@ final class WP_Installer{
955
 
956
  public function append_parameters_to_buy_url($url, $repository_id, $args = array()){
957
 
958
- $url = add_query_arg( array('icl_site_url' => $this->get_installer_site_url() ), $url );
959
 
960
  $affiliate_id = false;
961
  $affiliate_key = false;
@@ -1025,23 +1031,25 @@ final class WP_Installer{
1025
  $site_key = preg_replace("/[^A-Za-z0-9]/", '', $site_key);
1026
 
1027
  if($repository_id && $nonce && wp_create_nonce('save_site_key_' . $repository_id) == $nonce){
1028
-
1029
- $subscription_data = $this->fetch_subscription_data($repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REGISTRATION);
1030
-
1031
- if(is_wp_error($subscription_data)){
1032
- $error = $subscription_data->get_error_message();
1033
- if(preg_match('#Could not resolve host: (.*)#', $error, $matches)){
1034
- $error = sprintf(__("%s cannot access %s to register. Try again to see if it's a temporary problem. If the problem continues, make sure that this site has access to the Internet. You can still use the plugin without registration, but you will not receive automated updates.", 'installer'),
1035
- '<strong><i>' . $this->get_generic_product_name($repository_id) . '</i></strong>',
 
 
 
 
 
 
 
 
1036
  '<strong><i>' . $matches[1]. '</i></strong>'
1037
  ) ;
1038
  }
1039
-
1040
- }elseif($subscription_data){
1041
- $this->settings['repositories'][$repository_id]['subscription'] = array('key' => $site_key, 'data' => $subscription_data);
1042
- $this->save_settings();
1043
- }else{
1044
- $error = __('Invalid site key for the current site.', 'installer');
1045
  }
1046
 
1047
  }
@@ -1113,21 +1121,33 @@ final class WP_Installer{
1113
  $site_key = $this->get_site_key($_POST['repository_id']);
1114
 
1115
  if($site_key){
1116
- $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_UPDATES_CHECK );
1117
-
1118
- if($subscription_data){
1119
- $this->settings['repositories'][$repository_id]['subscription'] = array('key' => $site_key, 'data' => $subscription_data);
1120
 
1121
- //also refresh products information
1122
- $this->refresh_repositories_data();
1123
 
1124
- }else{
1125
- unset($this->settings['repositories'][$repository_id]['subscription']);
1126
- $error = __('Invalid site key for the current site.', 'installer');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1127
  }
1128
 
1129
- $this->save_settings();
1130
-
1131
  }
1132
 
1133
  }
@@ -1158,7 +1178,7 @@ final class WP_Installer{
1158
  $args['body'] = array(
1159
  'action' => 'site_key_validation',
1160
  'site_key' => $site_key,
1161
- 'site_url' => $this->get_installer_site_url($repository_id),
1162
  'source' => $source
1163
  );
1164
 
@@ -1187,13 +1207,13 @@ final class WP_Installer{
1187
  }
1188
 
1189
  $response = wp_remote_post($this->repositories[$repository_id]['api-url'], $args);
1190
-
1191
  $this->api_debug_log("POST {$this->repositories[$repository_id]['api-url']}");
1192
  $this->api_debug_log($args);
1193
 
1194
  $this->log("POST {$this->repositories[$repository_id]['api-url']} - fetch subscription data");
1195
 
1196
- if(!is_wp_error($response)){
1197
  $datas = wp_remote_retrieve_body($response);
1198
 
1199
  if(is_serialized($datas)){
@@ -1212,7 +1232,7 @@ final class WP_Installer{
1212
  }else{
1213
 
1214
  $this->api_debug_log($response);
1215
- $subscription_data = $response;
1216
  }
1217
 
1218
  return $subscription_data;
@@ -1575,7 +1595,7 @@ final class WP_Installer{
1575
  public function append_site_key_to_download_url($url, $key, $repository_id){
1576
 
1577
  $url_params['site_key'] = $key;
1578
- $url_params['site_url'] = $this->get_installer_site_url($repository_id);
1579
 
1580
 
1581
  // Add extra parameters for custom Installer packages
280
 
281
  $repositories_plugins = array();
282
 
283
+ if( !empty($this->settings['repositories']) ) {
284
 
285
+ foreach ( $this->settings['repositories'] as $repository_id => $repository ) {
 
 
 
 
286
 
287
+ foreach ( $repository['data']['packages'] as $package ) {
288
+
289
+ foreach ( $package['products'] as $product ) {
290
+
291
+ foreach ( $product['plugins'] as $plugin_slug ) {
292
+
293
+ $download = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
294
+
295
+ if ( !isset($repositories_plugins[$repository_id][$download['slug']]) ) {
296
+ $repositories_plugins[$repository_id][$download['slug']] = array(
297
+ 'name' => $download['name'],
298
+ 'registered' => $this->plugin_is_registered( $repository_id, $download['slug'] ) ? 1 : 0
299
+ );
300
+ }
301
 
 
 
 
 
 
302
  }
303
+
304
  }
305
+
306
  }
 
 
307
 
308
+ foreach ( $plugins as $plugin_id => $plugin ) {
309
 
310
+ $wp_plugin_slug = dirname( $plugin_id );
311
+ if ( empty($wp_plugin_slug) ) {
312
+ $wp_plugin_slug = basename( $plugin_id, '.php' );
313
+ }
314
 
315
+ foreach ( $repositories_plugins as $repository_id => $r_plugins ) {
316
 
317
+ foreach ( $r_plugins as $slug => $r_plugin ) {
318
 
319
+ if ( $wp_plugin_slug == $slug || $r_plugin['name'] == $plugin['Name'] || $r_plugin['name'] == $plugin['Title'] ) { //match order: slug, name, title
320
+
321
+ if ( $r_plugin['registered'] ) {
322
+ add_filter( 'plugin_action_links_' . $plugin_id, array($this, 'plugins_action_links_registered') );
323
+ } else {
324
+ add_filter( 'plugin_action_links_' . $plugin_id, array($this, 'plugins_action_links_not_registered') );
325
+ }
326
 
 
 
 
 
327
  }
328
 
329
  }
330
 
331
  }
332
 
 
333
 
334
+ }
335
 
336
  }
 
337
  }
338
 
339
  }
570
  }
571
 
572
  public function get_installer_site_url( $repository_id = false ){
573
+ global $current_site;
574
+
575
  $site_url = get_site_url();
576
 
577
  if( $repository_id && is_multisite() && isset( $this->settings['repositories'] ) ){
578
  $network_settings = maybe_unserialize( get_site_option('wp_installer_network') );
579
 
580
  if ( isset( $network_settings[$repository_id] ) ) {
581
+ $site_url = get_site_url( $current_site->blog_id );
582
  }
583
+
584
  }
585
 
586
  return $site_url;
961
 
962
  public function append_parameters_to_buy_url($url, $repository_id, $args = array()){
963
 
964
+ $url = add_query_arg( array('icl_site_url' => $this->get_installer_site_url( $repository_id ) ), $url );
965
 
966
  $affiliate_id = false;
967
  $affiliate_key = false;
1031
  $site_key = preg_replace("/[^A-Za-z0-9]/", '', $site_key);
1032
 
1033
  if($repository_id && $nonce && wp_create_nonce('save_site_key_' . $repository_id) == $nonce){
1034
+
1035
+ try {
1036
+ $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_REGISTRATION );
1037
+
1038
+ if ( $subscription_data ) {
1039
+ $this->settings['repositories'][$repository_id]['subscription'] = array('key' => $site_key, 'data' => $subscription_data);
1040
+ $this->save_settings();
1041
+ } else {
1042
+ $error = __( 'Invalid site key for the current site.', 'installer' );
1043
+ }
1044
+
1045
+ } catch (Exception $e ){
1046
+ $error = $e->getMessage();
1047
+ if( preg_match('#Could not resolve host: (.*)#', $error, $matches) || preg_match('#Couldn\'t resolve host \'(.*)\'#', $error, $matches) ){
1048
+ $error = sprintf(__("%s cannot access %s to register. Try again to see if it's a temporary problem. If the problem continues, make sure that this site has access to the Internet. You can still use the plugin without registration, but you will not receive automated updates.", 'installer'),
1049
+ '<strong><i>' . $this->get_generic_product_name($repository_id) . '</i></strong>',
1050
  '<strong><i>' . $matches[1]. '</i></strong>'
1051
  ) ;
1052
  }
 
 
 
 
 
 
1053
  }
1054
 
1055
  }
1121
  $site_key = $this->get_site_key($_POST['repository_id']);
1122
 
1123
  if($site_key){
1124
+ try {
1125
+ $subscription_data = $this->fetch_subscription_data( $repository_id, $site_key, self::SITE_KEY_VALIDATION_SOURCE_UPDATES_CHECK );
 
 
1126
 
1127
+ if ( $subscription_data ) {
1128
+ $this->settings['repositories'][$repository_id]['subscription'] = array('key' => $site_key, 'data' => $subscription_data);
1129
 
1130
+ //also refresh products information
1131
+ $this->refresh_repositories_data();
1132
+
1133
+ $this->save_settings();
1134
+
1135
+ } else {
1136
+ unset($this->settings['repositories'][$repository_id]['subscription']);
1137
+ $error = __( 'Invalid site key for the current site. If the error persists, try to unregister first and then register again with the same site key.', 'installer' );
1138
+ }
1139
+
1140
+
1141
+ } catch (Exception $e ){
1142
+ $error = $e->getMessage();
1143
+ if( preg_match('#Could not resolve host: (.*)#', $error, $matches) || preg_match('#Couldn\'t resolve host \'(.*)\'#', $error, $matches) ){
1144
+ $error = sprintf(__("%s cannot access %s to register. Try again to see if it's a temporary problem. If the problem continues, make sure that this site has access to the Internet. You can still use the plugin without registration, but you will not receive automated updates.", 'installer'),
1145
+ '<strong><i>' . $this->get_generic_product_name($repository_id) . '</i></strong>',
1146
+ '<strong><i>' . $matches[1]. '</i></strong>'
1147
+ ) ;
1148
+ }
1149
  }
1150
 
 
 
1151
  }
1152
 
1153
  }
1178
  $args['body'] = array(
1179
  'action' => 'site_key_validation',
1180
  'site_key' => $site_key,
1181
+ 'site_url' => $this->get_installer_site_url( $repository_id ),
1182
  'source' => $source
1183
  );
1184
 
1207
  }
1208
 
1209
  $response = wp_remote_post($this->repositories[$repository_id]['api-url'], $args);
1210
+
1211
  $this->api_debug_log("POST {$this->repositories[$repository_id]['api-url']}");
1212
  $this->api_debug_log($args);
1213
 
1214
  $this->log("POST {$this->repositories[$repository_id]['api-url']} - fetch subscription data");
1215
 
1216
+ if( !is_wp_error($response) ){
1217
  $datas = wp_remote_retrieve_body($response);
1218
 
1219
  if(is_serialized($datas)){
1232
  }else{
1233
 
1234
  $this->api_debug_log($response);
1235
+ throw new Exception( $response->get_error_message() );
1236
  }
1237
 
1238
  return $subscription_data;
1595
  public function append_site_key_to_download_url($url, $key, $repository_id){
1596
 
1597
  $url_params['site_key'] = $key;
1598
+ $url_params['site_url'] = $this->get_installer_site_url( $repository_id );
1599
 
1600
 
1601
  // Add extra parameters for custom Installer packages
plus/installer/installer.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- define('WP_INSTALLER_VERSION', '1.7.5');
3
 
4
  include_once dirname(__FILE__) . '/includes/installer.class.php';
5
 
1
  <?php
2
+ define('WP_INSTALLER_VERSION', '1.7.6');
3
 
4
  include_once dirname(__FILE__) . '/includes/installer.class.php';
5
 
plus/installer/loader.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Installer
4
  Plugin URI: http://wp-compatibility.com/installer-plugin/
5
  Description: Need help buying, installing and upgrading commercial themes and plugins? **Installer** handles all this for you, right from the WordPress admin. Installer lets you find themes and plugins from different sources, then, buy them from within the WordPress admin. Instead of manually uploading and unpacking, you'll see those themes and plugins available, just like any other plugin you're getting from WordPress.org.
6
- Version: 1.7.5
7
  Author: OnTheGoSystems Inc.
8
  Author URI: http://www.onthegosystems.com/
9
  */
@@ -28,7 +28,7 @@ $wp_installer_instance = dirname(__FILE__) . '/installer.php';
28
  global $wp_installer_instances;
29
  $wp_installer_instances[$wp_installer_instance] = array(
30
  'bootfile' => $wp_installer_instance,
31
- 'version' => '1.7.5'
32
  );
33
 
34
 
3
  Plugin Name: Installer
4
  Plugin URI: http://wp-compatibility.com/installer-plugin/
5
  Description: Need help buying, installing and upgrading commercial themes and plugins? **Installer** handles all this for you, right from the WordPress admin. Installer lets you find themes and plugins from different sources, then, buy them from within the WordPress admin. Instead of manually uploading and unpacking, you'll see those themes and plugins available, just like any other plugin you're getting from WordPress.org.
6
+ Version: 1.7.6
7
  Author: OnTheGoSystems Inc.
8
  Author URI: http://www.onthegosystems.com/
9
  */
28
  global $wp_installer_instances;
29
  $wp_installer_instances[$wp_installer_instance] = array(
30
  'bootfile' => $wp_installer_instance,
31
+ 'version' => '1.7.6'
32
  );
33
 
34
 
plus/installer/res/css/admin.css CHANGED
@@ -60,7 +60,15 @@
60
  color: #333;
61
  padding: 5px;
62
  }
 
 
 
 
63
 
 
 
 
 
64
  .installer-error-box p{
65
  margin: 10px 0 10px 0;
66
  -webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;border:1px solid #962722;background-color:#F5C8C6;
@@ -69,10 +77,10 @@
69
  text-align: center;
70
  }
71
 
72
-
73
  .spinner-inline{
74
  float: none;
75
  display: inline-block;
 
76
  }
77
 
78
  .installer-q-icon:before{
60
  color: #333;
61
  padding: 5px;
62
  }
63
+ .installer-warn-box span.details{
64
+ font-style: italic;
65
+ color:#777;
66
+ }
67
 
68
+ .installer-error-box{
69
+ color:#962722;
70
+ margin-top: 10px;
71
+ }
72
  .installer-error-box p{
73
  margin: 10px 0 10px 0;
74
  -webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;border:1px solid #962722;background-color:#F5C8C6;
77
  text-align: center;
78
  }
79
 
 
80
  .spinner-inline{
81
  float: none;
82
  display: inline-block;
83
+ visibility: visible;
84
  }
85
 
86
  .installer-q-icon:before{
plus/installer/res/js/admin.js CHANGED
@@ -71,6 +71,7 @@
71
  form.parent().find('.enter_site_key_js').prev().show();
72
 
73
  form.closest('.otgsi_register_product_wrap').removeClass('otgsi_yellow_bg');
 
74
  return false;
75
  },
76
 
@@ -114,7 +115,7 @@
114
 
115
  if(confirm(jQuery(this).data('confirmation'))){
116
 
117
- jQuery('<span class="spinner"></span>').css({display: 'inline-block', float: 'none'}).prependTo(jQuery(this).parent());
118
  data = {action: 'remove_site_key', repository_id: jQuery(this).data('repository'), nonce: jQuery(this).data('nonce')}
119
  jQuery.ajax({url: ajaxurl, type: 'POST', data: data, success: otgs_wp_installer.removed_site_key});
120
  }
@@ -127,21 +128,36 @@
127
  },
128
 
129
  update_site_key: function(){
130
-
 
 
131
  var spinner = jQuery('<span class="spinner"></span>');
132
- spinner.css({display: 'inline-block', float: 'none'}).prependTo(jQuery(this).parent());
 
133
  data = {action: 'update_site_key', repository_id: jQuery(this).data('repository'), nonce: jQuery(this).data('nonce')}
134
  jQuery.ajax({
135
  url: ajaxurl,
136
  type: 'POST',
137
  data: data,
138
- dataType: 'json',
139
- success: function(ret){
140
- if(ret.error){
141
- alert(ret.error);
 
 
 
 
 
 
 
 
 
 
 
 
142
  spinner.remove();
143
  }
144
- otgs_wp_installer.updated_site_key(ret);
145
  }
146
  });
147
 
71
  form.parent().find('.enter_site_key_js').prev().show();
72
 
73
  form.closest('.otgsi_register_product_wrap').removeClass('otgsi_yellow_bg');
74
+ otgs_wp_installer.reset_errors();
75
  return false;
76
  },
77
 
115
 
116
  if(confirm(jQuery(this).data('confirmation'))){
117
 
118
+ jQuery('<span class="spinner"></span>').css({visibility: 'visible', float: 'none'}).prependTo(jQuery(this).parent());
119
  data = {action: 'remove_site_key', repository_id: jQuery(this).data('repository'), nonce: jQuery(this).data('nonce')}
120
  jQuery.ajax({url: ajaxurl, type: 'POST', data: data, success: otgs_wp_installer.removed_site_key});
121
  }
128
  },
129
 
130
  update_site_key: function(){
131
+ var error_wrap = jQuery(this).closest('.otgsi_register_product_wrap').find('.installer-error-box');
132
+ error_wrap.html('');
133
+
134
  var spinner = jQuery('<span class="spinner"></span>');
135
+
136
+ spinner.css({visibility: 'visible', float: 'none'}).prependTo(jQuery(this).parent());
137
  data = {action: 'update_site_key', repository_id: jQuery(this).data('repository'), nonce: jQuery(this).data('nonce')}
138
  jQuery.ajax({
139
  url: ajaxurl,
140
  type: 'POST',
141
  data: data,
142
+ dataType: 'json',
143
+ complete: function( event, xhr, settings ){
144
+ var error = '';
145
+ if(xhr == 'success') {
146
+ var ret = event.responseJSON;
147
+ if(ret.error){
148
+ error = ret.error;
149
+ }else{
150
+ otgs_wp_installer.updated_site_key(ret);
151
+ }
152
+ }else{
153
+ error = 'Error processing request (' + xhr + '). Please try again!';
154
+ }
155
+
156
+ if( error ){
157
+ error_wrap.html('<p>' + error + '</p>').show();
158
  spinner.remove();
159
  }
160
+
161
  }
162
  });
163
 
plus/installer/templates/repository-listing.php CHANGED
@@ -27,11 +27,8 @@
27
  <input class="button-secondary cancel_site_key_js" type="button" value="<?php esc_attr_e('Cancel', 'installer') ?>" />
28
 
29
  <div class="alignleft" style="margin-top:6px;"><?php printf(__('1. Go to your %s%s account%s and add this site URL: %s', 'installer'),
30
- '<a href="' . $this->settings['repositories'][$repository_id]['data']['site_keys_management_url'] . '?add='.urlencode($this->get_installer_site_url()).'">',
31
- $generic_product_name, '</a>', $this->get_installer_site_url()); ?></div>
32
-
33
- <div class="installer-error-box hidden" style="margin-top:10px;"></div>
34
-
35
  </form>
36
 
37
 
@@ -52,14 +49,27 @@
52
  ?>
53
 
54
  <?php if($this->repository_has_expired_subscription($repository_id)): $expired = true; ?>
55
- <div><p class="installer-warn-box"><?php _e('Subscription is expired. You need to either purchase a new subscription or upgrade if available.', 'installer') ?></p></div>
 
 
 
 
 
 
 
 
 
 
 
56
  <?php else: ?>
57
  <?php $this->show_subscription_renew_warning($repository_id, $subscription_type); ?>
58
  <?php endif; ?>
59
 
60
  <div class="alignright">
61
  <a class="remove_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-confirmation="<?php esc_attr_e('Are you sure you want to unregister?', 'installer') ?>" data-nonce="<?php echo wp_create_nonce('remove_site_key_' . $repository_id) ?>"><?php printf(__("Unregister %s from this site", 'installer'), $generic_product_name) ?></a>&nbsp;
62
- <a class="update_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-nonce="<?php echo wp_create_nonce('update_site_key_' . $repository_id) ?>"><?php _e('Check for updates', 'installer') ?></a>
 
 
63
  </div>
64
 
65
  <?php if(empty($expired)): ?>
@@ -73,6 +83,8 @@
73
  <?php endif; //if(empty($expired)) ?>
74
 
75
  <?php endif; // if(!repository_has_subscription) ?>
 
 
76
 
77
  </td>
78
  </tr>
27
  <input class="button-secondary cancel_site_key_js" type="button" value="<?php esc_attr_e('Cancel', 'installer') ?>" />
28
 
29
  <div class="alignleft" style="margin-top:6px;"><?php printf(__('1. Go to your %s%s account%s and add this site URL: %s', 'installer'),
30
+ '<a href="' . $this->settings['repositories'][$repository_id]['data']['site_keys_management_url'] . '?add='.urlencode($this->get_installer_site_url( $repository_id )).'">',
31
+ $generic_product_name, '</a>', $this->get_installer_site_url( $repository_id )); ?></div>
 
 
 
32
  </form>
33
 
34
 
49
  ?>
50
 
51
  <?php if($this->repository_has_expired_subscription($repository_id)): $expired = true; ?>
52
+ <div>
53
+ <p class="installer-warn-box">
54
+ <?php _e('Subscription expired. You need to either purchase a new subscription or upgrade if available.', 'installer') ?>
55
+ <span class="alignright">
56
+ <a class="update_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-nonce="<?php echo wp_create_nonce('update_site_key_' . $repository_id) ?>">
57
+ <?php _e('Revalidate subscription', 'installer'); ?>
58
+ </a>
59
+ </span>
60
+ <br />
61
+ <span class="details"><?php _e("If you have already purchased or renewed your subscription and you can still see this message, please revalidate your subscription", 'installer') ?></span>
62
+ </p>
63
+ </div>
64
  <?php else: ?>
65
  <?php $this->show_subscription_renew_warning($repository_id, $subscription_type); ?>
66
  <?php endif; ?>
67
 
68
  <div class="alignright">
69
  <a class="remove_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-confirmation="<?php esc_attr_e('Are you sure you want to unregister?', 'installer') ?>" data-nonce="<?php echo wp_create_nonce('remove_site_key_' . $repository_id) ?>"><?php printf(__("Unregister %s from this site", 'installer'), $generic_product_name) ?></a>&nbsp;
70
+ <a class="update_site_key_js button-secondary" href="#" data-repository=<?php echo $repository_id ?> data-nonce="<?php echo wp_create_nonce('update_site_key_' . $repository_id) ?>">
71
+ <?php _e('Check for updates', 'installer'); ?>
72
+ </a>
73
  </div>
74
 
75
  <?php if(empty($expired)): ?>
83
  <?php endif; //if(empty($expired)) ?>
84
 
85
  <?php endif; // if(!repository_has_subscription) ?>
86
+ <br clear="all" />
87
+ <div class="installer-error-box hidden"></div>
88
 
89
  </td>
90
  </tr>
readme.txt CHANGED
@@ -1,11 +1,13 @@
1
  === Toolset Types ===
2
- Contributors: adrianosilva, AmirHelzer, bedas, brucepearson, christianglingener, jadpm, jans-1
3
  Donate link: http://wp-types.com
4
  Tags: CMS, custom field, custom fields, custom post type, custom post types, field, fields post, post type, post types, taxonomies, taxonomy, toolset
 
 
5
  License: GPLv2
6
  Requires at least: 3.7
7
  Tested up to: 4.4.1
8
- Stable tag: 1.9
9
 
10
  The complete and reliable plugin for managing custom post types, custom taxonomies and custom fields.
11
 
@@ -149,6 +151,21 @@ Additionally, Types is the only plugin that lets you define parent/child relatio
149
 
150
  == Changelog ==
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  = 1.9 =
153
 
154
  * Release date: 2016-02-17
@@ -173,7 +190,6 @@ Additionally, Types is the only plugin that lets you define parent/child relatio
173
  * Fix the Next pagination button missing on Fields Tables when the table is set to show N children each time and you have N+1 children assigned to that parent.
174
  * Fix custom taxonomy export/import when it is attached to a post type whose slug starts with a number.
175
 
176
-
177
  = 1.8.10 =
178
 
179
  * Release date: 2015-11-18
1
  === Toolset Types ===
2
+ Contributors: AmirHelzer, brucepearson, christianglingener, jadpm, zaantar
3
  Donate link: http://wp-types.com
4
  Tags: CMS, custom field, custom fields, custom post type, custom post types, field, fields post, post type, post types, taxonomies, taxonomy, toolset
5
+ Text Domain: wpcf
6
+ Domain Path: /embedded/locale
7
  License: GPLv2
8
  Requires at least: 3.7
9
  Tested up to: 4.4.1
10
+ Stable tag: 1.9.1
11
 
12
  The complete and reliable plugin for managing custom post types, custom taxonomies and custom fields.
13
 
151
 
152
  == Changelog ==
153
 
154
+ = 1.9.1 =
155
+
156
+ * Released date: 2016-03-08
157
+ * Fixed javascript infinite loop in post field group edit page.
158
+ * Fixed conflict between post relationship table and WordPress heartbeat ajax call.
159
+ * Fixed field slug limit of 20 characters.
160
+ * Fixed issue with filtering by multiple checkboxes fields that failed to return results.
161
+ * Fixed custom post type icon on "At a Glance" section.
162
+ * Fixed hidden visibility option of post types that did not work for built-in types.
163
+ * Fixed issue when adding an existing field that was always attached to bottom of the list.
164
+ * Fixed issue with parent custom post type that could not be stored in "Select child fields from Child to be displayed in Post Relationship table"
165
+ * Fixed options of unsaved checkbox / select / radio fields weren't sortable.
166
+ * Fixed an issue when adding a existing field to another group.
167
+ * Fixed an issue with cursor that was moved automatically to the end of slug input.
168
+
169
  = 1.9 =
170
 
171
  * Release date: 2016-02-17
190
  * Fix the Next pagination button missing on Fields Tables when the table is set to show N children each time and you have N+1 children assigned to that parent.
191
  * Fix custom taxonomy export/import when it is attached to a post type whose slug starts with a number.
192
 
 
193
  = 1.8.10 =
194
 
195
  * Release date: 2015-11-18
resources/js/fields-form.js CHANGED
@@ -432,6 +432,34 @@ jQuery(document).ready(function($){
432
  ? 'bottom'
433
  : 'top';
434
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
  dialog.load(
436
  ajaxurl,
437
  {
@@ -458,27 +486,7 @@ jQuery(document).ready(function($){
458
  }
459
  })
460
  .done(function(html){
461
- if( position == 'top' ) {
462
- $('#post-body-content .js-wpcf-fields').prepend( html );
463
- //$('.js-wpcf-slugize-source', $('#post-body-content .js-wpcf-fields .postbox:first-of-type')).focus();
464
- $( 'html, body' ).animate( {
465
- scrollTop: $( '#post-body-content .js-wpcf-fields .postbox' ).first().offset().top - 50
466
- }, 1000 );
467
- } else {
468
- $('#post-body-content .js-wpcf-fields .js-wpcf-fields-add-new-last').before( html );
469
- $( 'html, body' ).animate( {
470
- scrollTop: $( '#post-body-content .js-wpcf-fields .postbox' ).last().offset().top - 50
471
- }, 1000 );
472
- }
473
-
474
- dialog.dialog('close');
475
-
476
- wpcfBindAutoCreateSlugs();
477
- wpcfAddPostboxToggles();
478
-
479
- // show bottom "Add new field" and "Save Group Fields" buttons
480
- $( '.js-wpcf-fields-add-new, .js-wpcf-second-submit-container' ).removeClass( 'hidden' );
481
- wpcf_setup_conditions();
482
  });
483
  });
484
  /**
@@ -548,11 +556,7 @@ jQuery(document).ready(function($){
548
  }
549
  })
550
  .done(function(html){
551
- $('#post-body-content .js-wpcf-fields .js-wpcf-fields-add-new-last').before(html);
552
- dialog.dialog('close');
553
- $('.js-wpcf-slugize-source', $('#post-body-content .js-wpcf-fields .postbox:last-of-type')).focus();
554
- wpcfBindAutoCreateSlugs();
555
- wpcfAddPostboxToggles();
556
  });
557
  });
558
  });
@@ -678,6 +682,11 @@ jQuery(document).ready(function($){
678
  checkedArr.push($(this).data('slug'));
679
  });
680
  $('.wpcf-forms-field-slug').each(function(index){
 
 
 
 
 
681
  var currentValue = $(this).val().toLowerCase();
682
  if (currentValue != ''
683
  && $.inArray(currentValue, checkedArr) > -1) {
432
  ? 'bottom'
433
  : 'top';
434
 
435
+ function add_field_to_fields_list( html ) {
436
+ var newField;
437
+
438
+ if( position == 'top' ) {
439
+ $( '#post-body-content .js-wpcf-fields' ).prepend( html );
440
+ newField = $( '#post-body-content .js-wpcf-fields .postbox' ).first();
441
+ } else {
442
+ $( '#post-body-content .js-wpcf-fields .js-wpcf-fields-add-new-last' ).before( html );
443
+ newField = $( '#post-body-content .js-wpcf-fields .postbox' ).last();
444
+ }
445
+
446
+ $( 'html, body' ).animate( {
447
+ scrollTop: newField.offset().top - 50
448
+ }, 1000 );
449
+
450
+ dialog.dialog( 'close' );
451
+
452
+ wpcfBindAutoCreateSlugs();
453
+ wpcfAddPostboxToggles();
454
+
455
+ newField.typesFieldOptionsSortable();
456
+ newField.typesMarkExistingField();
457
+
458
+ // show bottom "Add new field" and "Save Group Fields" buttons
459
+ $( '.js-wpcf-fields-add-new, .js-wpcf-second-submit-container' ).removeClass( 'hidden' );
460
+ wpcf_setup_conditions();
461
+ }
462
+
463
  dialog.load(
464
  ajaxurl,
465
  {
486
  }
487
  })
488
  .done(function(html){
489
+ add_field_to_fields_list( html );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  });
491
  });
492
  /**
556
  }
557
  })
558
  .done(function(html){
559
+ add_field_to_fields_list( html );
 
 
 
 
560
  });
561
  });
562
  });
682
  checkedArr.push($(this).data('slug'));
683
  });
684
  $('.wpcf-forms-field-slug').each(function(index){
685
+
686
+ // skip for "existing fields" if no change in input slug
687
+ if( $( this ).data( 'types-existing-field' ) && $( this ).data( 'types-existing-field' ) == $( this ).val() )
688
+ return true;
689
+
690
  var currentValue = $(this).val().toLowerCase();
691
  if (currentValue != ''
692
  && $.inArray(currentValue, checkedArr) > -1) {
wpcf.php CHANGED
@@ -5,19 +5,23 @@
5
  Description: Toolset Types defines custom content in WordPress. Easily create custom post types, fields and taxonomy and connect everything together.
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com
8
- Version: 1.9
9
  */
 
 
 
 
 
 
 
 
10
  /**
11
  *
12
  *
13
  */
14
- // Added check because of activation hook and theme embedded code
15
- if ( !defined( 'WPCF_VERSION' ) ) {
16
- /**
17
- * make sure that WPCF_VERSION in embedded/bootstrap.php is the same!
18
- */
19
- define( 'WPCF_VERSION', '1.9' );
20
- }
21
 
22
  define( 'WPCF_REPOSITORY', 'http://api.wp-types.com/' );
23
 
@@ -518,4 +522,16 @@ if( empty( $stored_taxonomies ) || !isset( $stored_taxonomies['category'] ) || !
518
  }
519
 
520
  update_option( WPCF_OPTION_NAME_CUSTOM_TAXONOMIES, $stored_taxonomies );
 
 
 
 
 
 
 
 
 
 
 
 
521
  }
5
  Description: Toolset Types defines custom content in WordPress. Easily create custom post types, fields and taxonomy and connect everything together.
6
  Author: OnTheGoSystems
7
  Author URI: http://www.onthegosystems.com
8
+ Version: 1.9.1
9
  */
10
+
11
+ if( ! defined( 'TYPES_VERSION' ) )
12
+ define( 'TYPES_VERSION', '1.9.1' );
13
+
14
+ if( ! defined( 'TYPES_RELEASE_NOTES' ) )
15
+ define( 'TYPES_RELEASE_NOTES', 'https://wp-types.com/version/types-1-9/?utm_source=typesplugin&utm_campaign=types&utm_medium=release-notes-admin-notice&utm_term=Types 1.9 release notes' );
16
+
17
+
18
  /**
19
  *
20
  *
21
  */
22
+ // make sure that WPCF_VERSION in embedded/bootstrap.php is the same!
23
+ if ( ! defined( 'WPCF_VERSION' ) )
24
+ define( 'WPCF_VERSION', TYPES_VERSION );
 
 
 
 
25
 
26
  define( 'WPCF_REPOSITORY', 'http://api.wp-types.com/' );
27
 
522
  }
523
 
524
  update_option( WPCF_OPTION_NAME_CUSTOM_TAXONOMIES, $stored_taxonomies );
525
+ }
526
+
527
+ /* Plugin Meta */
528
+ add_filter( 'plugin_row_meta', 'types_plugin_plugin_row_meta', 10, 4 );
529
+
530
+ function types_plugin_plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) {
531
+ $this_plugin = basename( WPCF_ABSPATH ) . '/wpcf.php';
532
+ if ( $plugin_file == $this_plugin ) {
533
+ $plugin_meta[] = '<a href="' . TYPES_RELEASE_NOTES . '" target="_blank">'
534
+ . sprintf( __( 'Types %s release notes', 'wpcf' ), TYPES_VERSION ) . '</a>';
535
+ }
536
+ return $plugin_meta;
537
  }