PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/includes/CCTM.php

http://wordpress-custom-content-type-manager.googlecode.com/
PHP | 1699 lines | 1135 code | 163 blank | 401 comment | 96 complexity | 6d050238cf0ba2c7e6af35e00f31be6d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*------------------------------------------------------------------------------
  3. CCTM = Custom Content Type Manager
  4. This is the main class for the Custom Content Type Manager plugin.
  5. This class handles the creation and management of custom post-types (also
  6. referred to as 'content-types'). It requires the FormGenerator.php,
  7. StandardizedCustomFields.php, and the CCTMtests.php files/classes to work.
  8. ------------------------------------------------------------------------------*/
  9. class CCTM
  10. {
  11. const name = 'Custom Content Type Manager';
  12. const txtdomain = 'custom-content-type-mgr'; // used for localization
  13. // Required versions (referenced in the CCTMtest class).
  14. const wp_req_ver = '3.0.1';
  15. const php_req_ver = '5.2.6';
  16. const mysql_req_ver = '5.0.41';
  17. // Used to uniquely identify an option_name in the wp_options table
  18. // ALL data describing the post types and their custom fields lives there.
  19. // DELETE FROM `wp_options` WHERE option_name='custom_content_types_mgr_data';
  20. // would clean out everything this plugin knows.
  21. const db_key = 'custom_content_types_mgr_data';
  22. // Used to uniquely identify this plugin's menu page in the WP manager
  23. const admin_menu_slug = 'custom_content_type_mgr';
  24. // These parameters identify where in the $_GET array we can find the values
  25. // and how URLs are constructed, e.g. some-admin-page.php?a=123&pt=xyz
  26. const action_param = 'a';
  27. const post_type_param = 'pt';
  28. // integer iterator used to uniquely identify groups of field definitions for
  29. // CSS and $_POST variables
  30. public static $def_i = 0;
  31. // Built-in post-types that can have custom fields, but cannot be deleted.
  32. public static $built_in_post_types = array('post','page');
  33. // Names that are off-limits for custom post types b/c they're already used by WP
  34. public static $reserved_post_types = array('post','page','attachment','revision'
  35. ,'nav_menu','nav_menu_item');
  36. // Custom field names are not allowed to use the same names as any column in wp_posts
  37. public static $reserved_field_names = array('ID','post_author','post_date','post_date_gmt',
  38. 'post_content','post_title','post_excerpt','post_status','comment_status','ping_status',
  39. 'post_password','post_name','to_ping','pinged','post_modified','post_modified_gmt',
  40. 'post_content_filtered','post_parent','guid','menu_order','post_type','post_mime_type',
  41. 'comment_count');
  42. // Future-proofing: post-type names cannot begin with 'wp_'
  43. // See: http://codex.wordpress.org/Custom_Post_Types
  44. // FUTURE: List any other reserved prefixes here (if any)
  45. public static $reserved_prefixes = array('wp_');
  46. public static $Errors; // used to store WP_Error object (FUTURE TODO)
  47. /*------------------------------------------------------------------------------
  48. This var stores the big definition for the forms that allow users to define
  49. custom post-types. The form is generated in a way so that when it is posted, it
  50. can be easily passed to WP's register_post_type() function.
  51. We populate the value via the setter function, _set_post_type_form_definition(),
  52. but we do not have a getter. Since we are lazy, and PHP doesn't require
  53. getters/setters, we would have forgone the setter function if possible, but we
  54. had to use a setter simply to avoid the PHP syntax errors that would have
  55. errupted had we tried something like this:
  56. public $myvar = array( 'val' => __('somevalue') );
  57. ------------------------------------------------------------------------------*/
  58. public static $post_type_form_definition = array();
  59. /*------------------------------------------------------------------------------
  60. This array defines the form used for all new custom field definitions.
  61. The variable is populated via a setter: _set_custom_field_def_template() for
  62. the same reason as the $post_type_form_definition var above (see above).
  63. See the _page_manage_custom_fields() function for when and how these forms
  64. are used and handled.
  65. ------------------------------------------------------------------------------*/
  66. public static $custom_field_def_template = array();
  67. //! Private Functions
  68. /*------------------------------------------------------------------------------
  69. Generate HTML portion of our manage custom fields form. This is in distinction
  70. to the JS portion of the form, which uses a slightly different format.
  71. self::$def_i is used to track the definition #. All 5 output fields will use
  72. the same $def_i number to identify their place in the $_POST array.
  73. INPUT: $custom_field_defs (mixed) an array of hashes, each hash describing
  74. a custom field.
  75. Array
  76. (
  77. [1] => Array
  78. (
  79. [label] => Rating
  80. [name] => rating
  81. [description] => MPAA rating
  82. [type] => dropdown
  83. [options] => Array
  84. (
  85. [0] => G
  86. [1] => PG
  87. [2] => PG-13
  88. )
  89. [sort_param] =>
  90. )
  91. )
  92. OUTPUT: An HTML form, length depends on the # of field defs.
  93. ------------------------------------------------------------------------------*/
  94. private static function _get_html_field_defs($custom_field_defs)
  95. {
  96. // print_r($def); exit;
  97. $output = '';
  98. foreach ($custom_field_defs as $def)
  99. {
  100. FormGenerator::$before_elements = '
  101. <div id="generated_form_number_'.self::$def_i.'">';
  102. FormGenerator::$after_elements = '
  103. <span class="button custom_content_type_mgr_remove" onClick="javascript:removeDiv(this.parentNode.id);">'.__('Remove This Field').'</span>
  104. <hr/>
  105. </div>';
  106. $translated = self::_transform_data_structure_for_editing($def);
  107. $output .= FormGenerator::generate($translated);
  108. self::$def_i++;
  109. }
  110. return $output;
  111. }
  112. /*------------------------------------------------------------------------------
  113. Gets a field definition ready for use inside of a JS variable. We have to over-
  114. ride some of the names used by the _get_html_field_defs() function so the
  115. resulting HTML/Javascript will inherit values from Javascript variables dynamically
  116. as the user adds new form fields on the fly.
  117. Here +def_i+ represents a JS concatenation, where def_i is a JS variable.
  118. ------------------------------------------------------------------------------*/
  119. private static function _get_javascript_field_defs()
  120. {
  121. $def = self::$custom_field_def_template;
  122. foreach ($def as $row_id => &$field)
  123. {
  124. $name = $row_id;
  125. // alter the Extra part of this for the listener on the dropdown
  126. if($name == 'type')
  127. {
  128. $field['extra'] = str_replace('[+def_i+]', 'def_i', $field['extra']);
  129. }
  130. $field['name'] = "custom_fields['+def_i+'][$name]";
  131. }
  132. FormGenerator::$before_elements = '<div id="generated_form_number_\'+def_i+\'">';
  133. FormGenerator::$after_elements = '
  134. <a class="button" href="#" onClick="javascript:removeDiv(this.parentNode.id);">'
  135. .__('Remove This Field', CCTM::txtdomain).'</a>
  136. <hr/>
  137. </div>';
  138. $output = FormGenerator::generate($def);
  139. // Javascript chokes on newlines...
  140. return str_replace( array("\r\n", "\r", "\n", "\t"), ' ', $output);
  141. }
  142. /*------------------------------------------------------------------------------
  143. Designed to safely retrieve scalar elements out of a hash. Don't use this
  144. if you have a more deeply nested object (e.g. an array of arrays).
  145. INPUT:
  146. $hash : an associative array, e.g. array('animal' => 'Cat');
  147. $key : the key to search for in that array, e.g. 'animal'
  148. $default (optional) : value to return if the value is not set. Default=''
  149. OUTPUT: either safely escaped value from the hash or the default value
  150. ------------------------------------------------------------------------------*/
  151. private static function _get_value($hash, $key, $default='')
  152. {
  153. if ( !isset($hash[$key]) )
  154. {
  155. return $default;
  156. }
  157. else
  158. { // Warning: stripslashes was added to avoid some weird behavior
  159. return esc_html(stripslashes($hash[$key]));
  160. }
  161. }
  162. /*------------------------------------------------------------------------------
  163. SYNOPSIS: checks the custom content data array to see if $post_type exists.
  164. The $data array is structured something like this:
  165. $data = array(
  166. 'movie' => array('name'=>'movie', ... ),
  167. 'book' => array('name'=>'book', ... ),
  168. ...
  169. );
  170. So we can just check the keys of the main array to see if the post type exists.
  171. Built-in post types 'page' and 'post' are considered valid (i.e. existing) by
  172. default, even if they haven't been explicitly defined for use by this plugin
  173. so long as the 2nd argument, $search_built_ins, is not overridden to false.
  174. INPUT:
  175. $post_type (string) the lowercase database slug identifying a post type.
  176. $search_built_ins (boolean) whether or not to search inside the
  177. $built_in_post_types array.
  178. OUTPUT: boolean true | false indicating whether this is a valid post-type
  179. ------------------------------------------------------------------------------*/
  180. private static function _is_existing_post_type($post_type, $search_built_ins=true)
  181. {
  182. $data = get_option( self::db_key );
  183. // If there is no existing data, check against the built-ins
  184. if ( empty($data) && $search_built_ins )
  185. {
  186. return in_array($post_type, self::$built_in_post_types);
  187. }
  188. // If there's no existing $data and we omit the built-ins...
  189. elseif ( empty($data) && !$search_built_ins )
  190. {
  191. return false;
  192. }
  193. // Check to see if we've stored this $post_type before
  194. elseif ( array_key_exists($post_type, $data) )
  195. {
  196. return true;
  197. }
  198. // Check the built-ins
  199. elseif ( $search_built_ins && in_array($post_type, self::$built_in_post_types) )
  200. {
  201. return true;
  202. }
  203. else
  204. {
  205. return false;
  206. }
  207. }
  208. /*------------------------------------------------------------------------------
  209. Manager Page -- called by page_main_controller()
  210. Activating a post type will cause it to show up in the WP menus and its custom
  211. fields will be managed.
  212. ------------------------------------------------------------------------------*/
  213. private static function _page_activate_post_type($post_type)
  214. {
  215. // Validate post type
  216. if (!self::_is_existing_post_type($post_type) )
  217. {
  218. self::_page_display_error();
  219. return;
  220. }
  221. // get current values from database (if any)
  222. $data = get_option( self::db_key, array() );
  223. $data[$post_type]['is_active'] = 1;
  224. update_option( self::db_key, $data );
  225. // Often, PHP scripts use the header() function to refresh a page, but
  226. // WP has already claimed those, so we use a JavaScript refresh instead.
  227. // Refreshing the page ensures that active post types are added to menus.
  228. $msg = '
  229. <script type="text/javascript">
  230. window.location.replace("?page='.self::admin_menu_slug.'");
  231. </script>';
  232. // I think this $msg gets lost, but future TODO: use a 'flash' msg to display it
  233. // even after the page refresh.
  234. self::_page_show_all_post_types($msg);
  235. }
  236. /*------------------------------------------------------------------------------
  237. Manager Page -- called by page_main_controller()
  238. Create a new post type
  239. ------------------------------------------------------------------------------*/
  240. private static function _page_create_new_post_type()
  241. {
  242. // Variables for our template (I'm cheating here, loading in-line styles
  243. // becase the enqueue stuff is too heavy). TODO: use enqueue function to
  244. // load this only on the required pages.
  245. $style = '<style>'
  246. . file_get_contents( self::get_basepath() .'/css/create_or_edit_post_type.css' )
  247. . '</style>';
  248. $page_header = __('Create Custom Content Type', CCTM::txtdomain);
  249. $fields = '';
  250. $action_name = 'custom_content_type_mgr_create_new_content_type';
  251. $nonce_name = 'custom_content_type_mgr_create_new_content_type_nonce';
  252. $submit = __('Create New Content Type', CCTM::txtdomain);
  253. $msg = '';
  254. $def = self::$post_type_form_definition;
  255. // Save data if it was properly submitted
  256. if ( !empty($_POST) && check_admin_referer($action_name,$nonce_name) )
  257. {
  258. $sanitized_vals = self::_sanitize_post_type_def($_POST);
  259. $error_msg = self::_post_type_name_has_errors($sanitized_vals['post_type']);
  260. if ( empty($error_msg) )
  261. {
  262. self::_save_post_type_settings($sanitized_vals);
  263. $msg = '
  264. <div class="updated">
  265. <p>'
  266. . sprintf( __('The content type %s has been created', CCTM::txtdomain), '<em>'.$sanitized_vals['post_type'].'</em>')
  267. . '</p>
  268. </div>';
  269. self::_page_show_all_post_types($msg);
  270. return;
  271. }
  272. else
  273. {
  274. // This is for repopulating the form
  275. foreach ( $def as $node_id => $d )
  276. {
  277. $d['value'] = self::_get_value($sanitized_vals, $d['name']);
  278. }
  279. $msg = "<div class='error'>$error_msg</div>";
  280. }
  281. }
  282. $fields = FormGenerator::generate($def);
  283. include('pages/basic_form.php');
  284. }
  285. /*------------------------------------------------------------------------------
  286. Manager Page -- called by page_main_controller()
  287. Deactivate a post type. This will remove custom post types from the WP menus;
  288. deactivation stops custom fields from being standardized in built-in and custom
  289. post types
  290. ------------------------------------------------------------------------------*/
  291. private static function _page_deactivate_post_type($post_type)
  292. {
  293. // Validate post type
  294. if (!self::_is_existing_post_type($post_type) )
  295. {
  296. self::_page_display_error();
  297. return;
  298. }
  299. // Variables for our template
  300. $style = '';
  301. $page_header = sprintf( __('Deactivate Content Type %s', CCTM::txtdomain), $post_type );
  302. $fields = '';
  303. $action_name = 'custom_content_type_mgr_deactivate_content_type';
  304. $nonce_name = 'custom_content_type_mgr_deactivate_content_type_nonce';
  305. $submit = __('Deactivate', CCTM::txtdomain);
  306. // If properly submitted, Proceed with deleting the post type
  307. if ( !empty($_POST) && check_admin_referer($action_name,$nonce_name) )
  308. {
  309. // get current values from database
  310. $data = get_option( self::db_key, array() );
  311. $data[$post_type]['is_active'] = 0;
  312. update_option( self::db_key, $data );
  313. // A JavaScript refresh ensures that inactive post types are removed from the menus.
  314. $msg = '
  315. <script type="text/javascript">
  316. window.location.replace("?page='.self::admin_menu_slug.'");
  317. </script>';
  318. self::_page_show_all_post_types($msg);
  319. return;
  320. }
  321. $msg = '<div class="error"><p>'
  322. . sprintf( __('You are about to deactivate the %s post type. Deactivation does not delete anything.', CCTM::txtdomain ), "<em>$post_type</em>")
  323. .'</p>';
  324. // If it's a custom post type, we include some additional info.
  325. if ( !in_array($post_type, self::$built_in_post_types) )
  326. {
  327. $msg .= '<p>'
  328. . sprintf( __('After deactivation, %s posts will be unavailable to the outside world. %s will be removed from the administration menus and you will no longer be able to edit them using the WordPress manager.', CCTM::txtdomain), $post_type, "<strong>$post_type</strong>" )
  329. .'</p>';
  330. }
  331. $post_cnt_obj = wp_count_posts($post_type);
  332. $msg .= '<p>'
  333. . sprintf( __('This would affect %1$s published %2$s sposts.'
  334. ,CCTM::txtdomain), '<strong>'.$post_cnt_obj->publish.'</strong>'
  335. , "<em>$post_type</em>")
  336. .'</p>';
  337. $msg .= '<p>'.__('Are you sure you want to do this?',CCTM::txtdomain).'</p>
  338. </div>';
  339. include('pages/basic_form.php');
  340. }
  341. /*------------------------------------------------------------------------------
  342. Manager Page -- called by page_main_controller()
  343. This is only a valid page for custom post types.
  344. ------------------------------------------------------------------------------*/
  345. private static function _page_delete_post_type($post_type)
  346. {
  347. // We can't delete built-in post types
  348. if (!self::_is_existing_post_type($post_type, false ) )
  349. {
  350. self::_page_display_error();
  351. return;
  352. }
  353. // Variables for our template
  354. $style = '';
  355. $page_header = sprintf( __('Delete Content Type: %s', CCTM::txtdomain), $post_type );
  356. $fields = '';
  357. $action_name = 'custom_content_type_mgr_delete_content_type';
  358. $nonce_name = 'custom_content_type_mgr_delete_content_type_nonce';
  359. $submit = __('Delete',CCTM::txtdomain);
  360. // If properly submitted, Proceed with deleting the post type
  361. if ( !empty($_POST) && check_admin_referer($action_name,$nonce_name) )
  362. {
  363. // get current values from database
  364. $data = get_option( self::db_key, array() );
  365. unset($data[$post_type]); // <-- Delete this node of the data structure
  366. update_option( self::db_key, $data );
  367. $msg = '<div class="updated"><p>'
  368. .sprintf( __('The post type %s has been deleted', CCTM::txtdomain), "<em>$post_type</em>")
  369. . '</p></div>';
  370. self::_page_show_all_post_types($msg);
  371. return;
  372. }
  373. $msg = '<div class="error"><p>'
  374. . sprintf( __('You are about to delete the %s post type. This will remove all of its settings from the database, but this will NOT delete any rows from the wp_posts table. However, without a custom post type defined for those rows, they will be essentially invisible to WordPress.', CCTM::txtdomain), "<em>$post_type</em>" )
  375. .'</p>'
  376. . '<p>'.__('Are you sure you want to do this?',CCTM::txtdomain).'</p>';
  377. include('pages/basic_form.php');
  378. }
  379. /*------------------------------------------------------------------------------
  380. Manager Page -- called by page_main_controller()
  381. Returned on errors. Future: accept an argument identifying an error
  382. ------------------------------------------------------------------------------*/
  383. private static function _page_display_error()
  384. {
  385. $msg = '<p>'. __('Invalid post type.', CCTM::txtdomain)
  386. . '</p><a class="button" href="?page='
  387. .self::admin_menu_slug.'">'. __('Back', CCTM::txtdomain). '</a>';
  388. wp_die( $msg );
  389. }
  390. /*------------------------------------------------------------------------------
  391. Manager Page -- called by page_main_controller()
  392. Edit an existing post type. Changing the unique post-type identifier (i.e. name)
  393. is not allowed.
  394. ------------------------------------------------------------------------------*/
  395. private static function _page_edit_post_type($post_type)
  396. {
  397. // We can't edit built-in post types
  398. if (!self::_is_existing_post_type($post_type, false ) )
  399. {
  400. self::_page_display_error();
  401. return;
  402. }
  403. // Variables for our template (TODO: register this instead of this cheap inline trick)
  404. $style = '<style>'
  405. . file_get_contents( self::get_basepath() .'/css/create_or_edit_post_type_class.css' )
  406. . '</style>';
  407. $page_header = __('Edit Content Type: ') . $post_type;
  408. $fields = '';
  409. $action_name = 'custom_content_type_mgr_edit_content_type';
  410. $nonce_name = 'custom_content_type_mgr_edit_content_type_nonce';
  411. $submit = __('Save',CCTM::txtdomain);
  412. $msg = ''; // Any validation errors
  413. $def = self::$post_type_form_definition;
  414. // Save data if it was properly submitted
  415. if ( !empty($_POST) && check_admin_referer($action_name,$nonce_name) )
  416. {
  417. $sanitized_vals = self::_sanitize_post_type_def($_POST);
  418. $error_msg = self::_post_type_name_has_errors($sanitized_vals['post_type']);
  419. if ( empty($error_msg) )
  420. {
  421. self::_save_post_type_settings($sanitized_vals);
  422. $msg = '
  423. <script type="text/javascript">
  424. window.location.replace("?page='.self::admin_menu_slug.'");
  425. </script>';
  426. $msg .= '<div class="updated"><p>'
  427. . sprintf( __('Settings for %s have been updated.', CCTM::txtdomain )
  428. , '<em>'.$sanitized_vals['post_type'].'</em>')
  429. .'</p></div>';
  430. self::_page_show_all_post_types($msg); // TODO: make this message persist across page refreshes
  431. return;
  432. }
  433. else
  434. {
  435. // This is for repopulating the form
  436. $def = self::_populate_form_def_from_data($def, $sanitized_vals);
  437. $msg = "<div class='error'>$error_msg</div>";
  438. }
  439. }
  440. // get current values from database
  441. $data = get_option( self::db_key, array() );
  442. // Populate the form $def with values from the database
  443. $def = self::_populate_form_def_from_data($def, $data[$post_type]);
  444. $fields = FormGenerator::generate($def);
  445. include('pages/basic_form.php');
  446. }
  447. /*------------------------------------------------------------------------------
  448. Manager Page -- called by page_main_controller()
  449. Manage custom fields for any post type, built-in or custom.
  450. ------------------------------------------------------------------------------*/
  451. private static function _page_manage_custom_fields($post_type)
  452. {
  453. // Validate post type
  454. if (!self::_is_existing_post_type($post_type) )
  455. {
  456. self::_page_display_error();
  457. return;
  458. }
  459. $action_name = 'custom_content_type_mgr_manage_custom_fields';
  460. $nonce_name = 'custom_content_type_mgr_manage_custom_fields_nonce';
  461. $msg = ''; // Any validation errors
  462. $def_cnt = ''; // # of custom field definitions
  463. // The set of fields that makes up a custom field definition, but stripped of newlines
  464. // and with some modifications so it can be used inside a javascript variable
  465. $new_field_def_js = '';
  466. // Existing fields
  467. $fields = '';
  468. $data = get_option( self::db_key, array() );
  469. // Validate/Save data if it was properly submitted
  470. if ( !empty($_POST) && check_admin_referer($action_name,$nonce_name) )
  471. {
  472. $error_msg = array(); // used as a flag
  473. if (!isset($_POST['custom_fields']))
  474. {
  475. $data[$post_type]['custom_fields'] = array(); // all custom fields were deleted
  476. }
  477. else
  478. {
  479. $data[$post_type]['custom_fields'] = $_POST['custom_fields'];
  480. foreach ( $data[$post_type]['custom_fields'] as &$cf )
  481. {
  482. if ( preg_match('/[^a-z_]/i', $cf['name']))
  483. {
  484. $error_msg[] = sprintf(
  485. __('%s contains invalid characters.',CCTM::txtdomain)
  486. , '<strong>'.$cf['name'].'</strong>');
  487. $cf['name'] = preg_replace('/[^a-z_]/','',$cf['name']);
  488. }
  489. if ( strlen($cf['name']) > 20 )
  490. {
  491. $cf['name'] = substr($cf['name'], 0 , 20);
  492. $error_msg[] = sprintf(
  493. __('%s is too long.',CCTM::txtdomain)
  494. , '<strong>'.$cf['name'].'</strong>');
  495. }
  496. if ( in_array($cf['name'], self::$reserved_field_names ) )
  497. {
  498. $error_msg[] = sprintf(
  499. __('%s is a reserved name.',CCTM::txtdomain)
  500. , '<strong>'.$cf['name'].'</strong>');
  501. }
  502. }
  503. }
  504. if ($error_msg)
  505. {
  506. foreach ( $error_msg as &$e )
  507. {
  508. $e = '<li>'.$e.'</li>';
  509. }
  510. $msg = sprintf('<div class="error">
  511. <h3>%1$s</h3>
  512. %2$s %3$s %4$s
  513. <ul style="margin-left:30px">
  514. %5$s
  515. </ul>
  516. </div>'
  517. , __('There were errors in the names of your custom fields.', CCTM::txtdomain)
  518. , __('Names must not exceed 20 characters in length.', CCTM::txtdomain)
  519. , __('Names may contain the letters a-z and underscores only.', CCTM::txtdomain)
  520. , __('You cannot name your field using any reserved name.', CCTM::txtdomain)
  521. , implode("\n", $error_msg)
  522. );
  523. }
  524. else
  525. {
  526. update_option( self::db_key, $data );
  527. $msg = sprintf('<div class="updated">%s</p></div>'
  528. , sprintf(__('Custom fields for %s have been updated', CCTM::txtdomain)
  529. , '<em>'.$post_type.'</em>'
  530. )
  531. );
  532. }
  533. }
  534. // We want to extract a $def for only THIS content_type's custom_fields
  535. $def = array();
  536. if ( isset($data[$post_type]['custom_fields']) )
  537. {
  538. $def = $data[$post_type]['custom_fields'];
  539. }
  540. // count # of custom field definitions --> replaces [+def_i+]
  541. $def_cnt = count($def);
  542. // We don't need the exact number of form elements, we just need an integer
  543. // that is sufficiently high so that the ids of Javascript-created elements
  544. // do not conflict with the ids of PHP-created elements.
  545. $element_cnt = count($def, COUNT_RECURSIVE);
  546. if (!$def_cnt)
  547. {
  548. $x = sprintf( __('The %s post type does not have any custom fields yet.', CCTM::txtdomain)
  549. , "<em>$post_type</em>" );
  550. $y = __('Click the button above to add a custom field.', CCTM::txtdomain );
  551. $msg .= sprintf('<div class="updated">%s %s</div>', $x, $y);
  552. }
  553. $fields = self::_get_html_field_defs($def);
  554. // Gets a form definition ready for use inside of a JS variable
  555. $new_field_def_js = self::_get_javascript_field_defs();
  556. include('pages/manage_custom_fields.php');
  557. }
  558. /*------------------------------------------------------------------------------
  559. Manager Page -- called by page_main_controller()
  560. Show what a single page for this custom post-type might look like. This is
  561. me throwing a bone to template editors and creators.
  562. I'm using a tpl and my parse() function because I got to print out sample PHP
  563. code and it's too much of a pain in the ass to include PHP without it executing.
  564. ------------------------------------------------------------------------------*/
  565. private static function _page_sample_template($post_type)
  566. {
  567. // Validate post type
  568. if (!self::_is_existing_post_type($post_type) )
  569. {
  570. self::_page_display_error();
  571. return;
  572. }
  573. $current_theme_name = get_current_theme();
  574. $current_theme_path = get_stylesheet_directory();
  575. $hash = array();
  576. $data = get_option( self::db_key, array() );
  577. $tpl = file_get_contents( CCTM_PATH.'/tpls/sample_template_code.tpl');
  578. $tpl = htmlentities($tpl);
  579. $msg = sprintf( __('WordPress supports a custom theme file for each registered post-type (content-type). Copy the text below into a file named <strong>%s</strong> and save it into your active theme.', CCTM::txtdomain)
  580. , 'single-'.$post_type.'.php'
  581. );
  582. $msg .= sprintf( __('You are currently using the %1$s theme. Save the file into the %2$s directory.',CCTM::txtdomain)
  583. , '<strong>'.$current_theme_name.'</strong>'
  584. , '<strong>'.$current_theme_path.'</strong>'
  585. );
  586. $data = get_option( self::db_key, array() );
  587. $def = array();
  588. if ( isset($data[$post_type]['custom_fields']) )
  589. {
  590. $def = $data[$post_type]['custom_fields'];
  591. }
  592. //print_r($def); exit;
  593. $custom_fields_str = '';
  594. foreach ( $def as $d )
  595. {
  596. $custom_fields_str .= sprintf("\t\t<strong>%s:</strong> <?php print_custom_field('%s'); ?><br />\n", $d['label'], $d['name']);
  597. }
  598. // Populate placeholders
  599. $hash['post_type'] = $post_type;
  600. $hash['custom_fields'] = $custom_fields_str;
  601. $sample_code = StandardizedCustomFields::parse($tpl, $hash);
  602. include('pages/sample_template.php');
  603. }
  604. /*------------------------------------------------------------------------------
  605. Manager Page -- called by page_main_controller()
  606. List all post types (default page)
  607. ------------------------------------------------------------------------------*/
  608. private static function _page_show_all_post_types($msg='')
  609. {
  610. $data = get_option( self::db_key, array() );
  611. $customized_post_types = array_keys($data);
  612. $displayable_types = array_merge(self::$built_in_post_types , $customized_post_types);
  613. $displayable_types = array_unique($displayable_types);
  614. $row_data = '';
  615. foreach ( $displayable_types as $post_type )
  616. {
  617. if ( isset($data[$post_type]['is_active']) && !empty($data[$post_type]['is_active']) )
  618. {
  619. $class = 'active';
  620. $is_active = true;
  621. }
  622. else
  623. {
  624. $class = 'inactive';
  625. $is_active = false;
  626. }
  627. // Built-in post types use a canned description.
  628. if ( in_array($post_type, self::$built_in_post_types) )
  629. {
  630. $description = __('Built-in post type');
  631. }
  632. // Whereas users define the description for custom post types
  633. else
  634. {
  635. $description = self::_get_value($data[$post_type],'description');
  636. }
  637. ob_start();
  638. include('single_content_type_tr.php');
  639. $row_data .= ob_get_contents();
  640. ob_end_clean();
  641. }
  642. include('pages/default.php');
  643. }
  644. /*------------------------------------------------------------------------------
  645. Populate form definition with data that defines a post-type. This data comes
  646. either from the database, or from the $_POST array. The $pt_data
  647. (i.e. post-type data) should contain only information about
  648. a single post_type; do not pass this function the entire contents of the
  649. get_option.
  650. This whole function is necessary because the form generator definition needs
  651. to know where to find values for its fields -- the $def is an empty template,
  652. so we need to populate with values by splicing the $def together with the
  653. $pt_data. Some of this complication is due to the fact that we need to update
  654. the field names to acommodate array, e.g.
  655. <input type="text" name="some[2][name]" />
  656. INPUT: $def (mixed) form definition
  657. $pt_data (mixed) data describing a single post type
  658. OUTPUT: $def updated with values
  659. ------------------------------------------------------------------------------*/
  660. private static function _populate_form_def_from_data($def, $pt_data)
  661. {
  662. foreach ($def as $node_id => $tmp)
  663. {
  664. if ( $node_id == 'supports_title' )
  665. {
  666. if ( !empty($pt_data['supports']) && in_array('title', $pt_data['supports']) )
  667. {
  668. $def[$node_id]['value'] = 'title';
  669. }
  670. else
  671. {
  672. $def[$node_id]['value'] = '';
  673. }
  674. }
  675. elseif ( $node_id == 'supports_editor' )
  676. {
  677. if ( !empty($pt_data['supports']) && in_array('editor', $pt_data['supports']) )
  678. {
  679. $def[$node_id]['value'] = 'editor';
  680. }
  681. else
  682. {
  683. $def[$node_id]['value'] = '';
  684. }
  685. }
  686. elseif ( $node_id == 'supports_author' )
  687. {
  688. if ( !empty($pt_data['supports']) && in_array('author', $pt_data['supports']) )
  689. {
  690. $def[$node_id]['value'] = 'author';
  691. }
  692. else
  693. {
  694. $def[$node_id]['value'] = '';
  695. }
  696. }
  697. elseif ( $node_id == 'supports_excerpt' )
  698. {
  699. if ( !empty($pt_data['supports']) && in_array('excerpt', $pt_data['supports']) )
  700. {
  701. $def[$node_id]['value'] = 'excerpt';
  702. }
  703. else
  704. {
  705. $def[$node_id]['value'] = '';
  706. }
  707. }
  708. elseif ( $node_id == 'supports_thumbnail' )
  709. {
  710. if ( !empty($pt_data['supports']) && in_array('thumbnail', $pt_data['supports']) )
  711. {
  712. $def[$node_id]['value'] = 'thumbnail';
  713. }
  714. else
  715. {
  716. $def[$node_id]['value'] = '';
  717. }
  718. }
  719. elseif ( $node_id == 'supports_trackbacks' )
  720. {
  721. if ( !empty($pt_data['supports']) && in_array('trackbacks', $pt_data['supports']) )
  722. {
  723. $def[$node_id]['value'] = 'trackbacks';
  724. }
  725. else
  726. {
  727. $def[$node_id]['value'] = '';
  728. }
  729. }
  730. elseif ( $node_id == 'supports_custom-fields' )
  731. {
  732. if ( !empty($pt_data['supports']) && in_array('custom-fields', $pt_data['supports']) )
  733. {
  734. $def[$node_id]['value'] = 'custom-fields';
  735. }
  736. else
  737. {
  738. $def[$node_id]['value'] = '';
  739. }
  740. }
  741. elseif ( $node_id == 'supports_comments' )
  742. {
  743. if ( !empty($pt_data['supports']) && in_array('comments', $pt_data['supports']) )
  744. {
  745. $def[$node_id]['value'] = 'comments';
  746. }
  747. else
  748. {
  749. $def[$node_id]['value'] = '';
  750. }
  751. }
  752. elseif ( $node_id == 'supports_revisions' )
  753. {
  754. if ( !empty($pt_data['supports']) && in_array('revisions', $pt_data['supports']) )
  755. {
  756. $def[$node_id]['value'] = 'revisions';
  757. }
  758. else
  759. {
  760. $def[$node_id]['value'] = '';
  761. }
  762. }
  763. elseif ( $node_id == 'supports_page-attributes' )
  764. {
  765. if ( !empty($pt_data['supports']) && in_array('page-attributes', $pt_data['supports']) )
  766. {
  767. $def[$node_id]['value'] = 'page-attributes';
  768. }
  769. else
  770. {
  771. $def[$node_id]['value'] = '';
  772. }
  773. }
  774. elseif ( $node_id == 'rewrite_slug' )
  775. {
  776. if ( !empty($pt_data['rewrite']['slug']) )
  777. {
  778. $def[$node_id]['value'] = $pt_data['rewrite']['slug'];
  779. }
  780. else
  781. {
  782. $def[$node_id]['value'] = '';
  783. }
  784. }
  785. elseif ( $node_id == 'rewrite_with_front' )
  786. {
  787. if ( !empty($pt_data['rewrite']['with_front']) )
  788. {
  789. $def[$node_id]['value'] = $pt_data['rewrite']['with_front'];
  790. }
  791. else
  792. {
  793. $def[$node_id]['value'] = '';
  794. }
  795. }
  796. else
  797. {
  798. $field_name = $def[$node_id]['name'];
  799. $def[$node_id]['value'] = self::_get_value($pt_data,$field_name);
  800. }
  801. }
  802. return $def;
  803. }
  804. /*------------------------------------------------------------------------------
  805. SYNOPSIS: Ensure that $post_type is a valid post_type name.
  806. INPUT:
  807. $post_type (str) name of the post type
  808. OUTPUT: null if there are no errors, otherwise return a string describing an error.
  809. ------------------------------------------------------------------------------*/
  810. private static function _post_type_name_has_errors($post_type)
  811. {
  812. $errors = null;
  813. $taxonomy_names_array = get_taxonomies('','names');
  814. if ( empty($post_type) )
  815. {
  816. return __('Name is required.', CCTM::txtdomain);
  817. }
  818. foreach ( self::$reserved_prefixes as $rp )
  819. {
  820. if ( preg_match('/^'.preg_quote($rp).'.*/', $post_type) )
  821. {
  822. return sprintf( __('The post type name cannot begin with %s because that is a reserved prefix.', CCTM::txtdomain)
  823. , $rp);
  824. }
  825. }
  826. // Is reserved name?
  827. if ( in_array($post_type, self::$reserved_post_types) )
  828. {
  829. $msg = __('Please choose another name.', CCTM::txtdomain );
  830. $msg .= ' ';
  831. $msg .= sprintf( __('%s is a reserved name.', CCTM::txtdomain )
  832. , '<strong>'.$post_type.'</strong>' );
  833. return $msg;
  834. }
  835. // Make sure the post-type name does not conflict with any registered taxonomies
  836. elseif ( in_array( $post_type, $taxonomy_names_array) )
  837. {
  838. $msg = __('Please choose another name.', CCTM::txtdomain );
  839. $msg .= ' ';
  840. $msg .= sprintf( __('%s is already in use as a registered taxonomy name.', CCTM::txtdomain)
  841. , $post_type );
  842. }
  843. // If this is a new post_type or if the $post_type name has been changed,
  844. // ensure that it is not going to overwrite an existing post type name.
  845. else
  846. {
  847. $data = get_option( self::db_key, array() );
  848. if ( in_array( $post_type, array_keys($data) ) )
  849. {
  850. return __('That name is already in use.');
  851. }
  852. }
  853. return; // no errors
  854. }
  855. /*------------------------------------------------------------------------------
  856. Every form element when creating a new post type must be filtered here.
  857. INPUT: unsanitized $_POST data.
  858. OUTPUT: filtered data. Only white-listed values are passed thru to output.
  859. ------------------------------------------------------------------------------*/
  860. private static function _sanitize_post_type_def($raw)
  861. {
  862. $sanitized = array();
  863. // This will be empty if none of the "supports" items are checked.
  864. if (!empty($raw['supports']) )
  865. {
  866. $sanitized['supports'] = $raw['supports'];
  867. }
  868. unset($raw['supports']); // we manually set this later
  869. // Temporary thing...
  870. unset($sanitized['rewrite_slug']);
  871. unset($sanitized['rewrite_with_front']);
  872. // We grab everything, then override specific $keys as needed.
  873. foreach ($raw as $key => $value )
  874. {
  875. if ( !preg_match('/^_.*/', $key) )
  876. {
  877. $sanitized[$key] = self::_get_value($raw, $key);
  878. }
  879. }
  880. // Specific overrides below:
  881. // post_type is the only required field
  882. $sanitized['post_type'] = self::_get_value($raw,'post_type');
  883. $sanitized['post_type'] = strtolower($sanitized['post_type']);
  884. $sanitized['post_type'] = preg_replace('/[^a-z|_]/', '_', $sanitized['post_type']);
  885. $sanitized['post_type'] = substr($sanitized['post_type'], 0, 20);
  886. // Our form passes integers and strings, but WP req's literal booleans,
  887. // so we do some type-casting here to ensure literal booleans.
  888. $sanitized['show_ui'] = (bool) self::_get_value($raw,'show_ui');
  889. $sanitized['public'] = (bool) self::_get_value($raw,'public');
  890. $sanitized['show_in_nav_menus'] = (bool) self::_get_value($raw,'show_in_nav_menus');
  891. $sanitized['can_export'] = (bool) self::_get_value($raw,'can_export');
  892. $sanitized['use_default_menu_icon'] = (bool) self::_get_value($raw,'use_default_menu_icon');
  893. $sanitized['hierarchical'] = (bool) self::_get_value($raw,'hierarchical');
  894. // *facepalm*... Special handling req'd here for menu_position because 0
  895. // is handled differently than a literal null.
  896. if ( (int) self::_get_value($raw,'menu_position') )
  897. {
  898. $sanitized['menu_position'] = (int) self::_get_value($raw,'menu_position',null);
  899. }
  900. else
  901. {
  902. $sanitized['menu_position'] = null;
  903. }
  904. // menu_icon... the user will lose any custom Menu Icon URL if they save with this checked!
  905. // TODO: let this value persist.
  906. if( $sanitized['use_default_menu_icon'] )
  907. {
  908. unset($sanitized['menu_icon']); // === null;
  909. }
  910. if (empty($sanitized['query_var']))
  911. {
  912. $sanitized['query_var'] = false;
  913. }
  914. // Rewrites. TODO: make this work like the built-in post-type permalinks
  915. switch ($sanitized['permalink_action'])
  916. {
  917. case '/%postname%/':
  918. $sanitized['rewrite'] = true;
  919. break;
  920. case 'Custom':
  921. $sanitized['rewrite']['slug'] = $raw['rewrite_slug'];
  922. $sanitized['rewrite']['with_front'] = (bool) $raw['rewrite_with_front'];
  923. break;
  924. case 'Off':
  925. default:
  926. $sanitized['rewrite'] = false;
  927. }
  928. return $sanitized;
  929. }
  930. /*------------------------------------------------------------------------------
  931. INPUT: $def (mixed) associative array describing a single post-type.
  932. OUTPUT: none; this saves a serialized data structure (arrays of arrays) to the db
  933. ------------------------------------------------------------------------------*/
  934. private static function _save_post_type_settings($def)
  935. {
  936. $key = $def['post_type'];
  937. $all_post_types = get_option( self::db_key, array() );
  938. // Update existing settings if this post-type has already been added
  939. if ( isset($all_post_types[$key]) )
  940. {
  941. $all_post_types[$key] = array_merge($all_post_types[$key], $def);
  942. }
  943. // OR, create a new node in the data structure for our new post-type
  944. else
  945. {
  946. $all_post_types[$key] = $def;
  947. }
  948. update_option( self::db_key, $all_post_types );
  949. }
  950. /*------------------------------------------------------------------------------
  951. This is sorta a reflexive form definition: it defines the form required to
  952. define a form. Note that names imply arrays, e.g. name="custom_fields[3][label]".
  953. This is intentional: since all custom field definitions are stored as a serialized
  954. array in the wp_options table, we have to treat all defs as a kind of recordset
  955. (i.e. an array of similar hashes).
  956. [+def_i+] gets used by Javascript for on-the-fly adding of form fields (where
  957. def_i is a Javascript variable indicating the definition number (or i for integer).
  958. ------------------------------------------------------------------------------*/
  959. private static function _set_custom_field_def_template()
  960. {
  961. $def['label']['name'] = 'custom_fields[[+def_i+]][label]';
  962. $def['label']['label'] = __('Label', CCTM::txtdomain);
  963. $def['label']['value'] = '';
  964. $def['label']['extra'] = '';
  965. $def['label']['description'] = '';
  966. $def['label']['type'] = 'text';
  967. $def['label']['sort_param'] = 1;
  968. $def['name']['name'] = 'custom_fields[[+def_i+]][name]';
  969. $def['name']['label'] = __('Name', CCTM::txtdomain);
  970. $def['name']['value'] = '';
  971. $def['name']['extra'] = '';
  972. $def['name']['description'] = __('The name identifies the option_name in the wp_postmeta database table. You will use this name in your template functions to identify this custom field.', CCTM::txtdomain);
  973. $def['name']['type'] = 'text';
  974. $def['name']['sort_param'] = 2;
  975. $def['description']['name'] = 'custom_fields[[+def_i+]][description]';
  976. $def['description']['label'] = __('Description',CCTM::txtdomain);
  977. $def['description']['value'] = '';
  978. $def['description']['extra'] = '';
  979. $def['description']['description'] = '';
  980. $def['description']['type'] = 'textarea';
  981. $def['description']['sort_param'] = 3;
  982. $def['type']['name'] = 'custom_fields[[+def_i+]][type]';
  983. $def['type']['label'] = __('Input Type', CCTM::txtdomain);
  984. $def['type']['value'] = 'text';
  985. $def['type']['extra'] = ' onchange="javascript:addRemoveDropdown(this.parentNode.id,this.value, [+def_i+])"';
  986. $def['type']['description'] = '';
  987. $def['type']['type'] = 'dropdown';
  988. $def['type']['options'] = array('checkbox','dropdown','media','relation','text','textarea','wysiwyg');
  989. $def['type']['sort_param'] = 4;
  990. $def['sort_param']['name'] = 'custom_fields[[+def_i+]][sort_param]';
  991. $def['sort_param']['label'] = __('Sort Order',CCTM::txtdomain);
  992. $def['sort_param']['value'] = '';
  993. $def['sort_param']['extra'] = ' size="2" maxlength="4"';
  994. $def['sort_param']['description'] = __('This controls where this field will appear on the page. Fields with smaller numbers will appear higher on the page.',CCTM::txtdomain);
  995. $def['sort_param']['type'] = 'text';
  996. $def['sort_param']['sort_param'] = 5;
  997. self::$custom_field_def_template = $def;
  998. }
  999. /*------------------------------------------------------------------------------
  1000. Used when creating or editing Post Types
  1001. ------------------------------------------------------------------------------*/
  1002. private static function _set_post_type_form_definition()
  1003. {
  1004. $def = array();
  1005. $def['post_type']['name'] = 'post_type';
  1006. $def['post_type']['label'] = __('Name', CCTM::txtdomain). ' *';
  1007. $def['post_type']['value'] = '';
  1008. $def['post_type']['extra'] = '';
  1009. $def['post_type']['description'] = __('Unique singular name to identify this post type in the database, e.g. "movie","book". This may show up in your URLs, e.g. ?movie=star-wars. This will also make a new theme file available, starting with prefix named "single-", e.g. <strong>single-movie.php</strong>. The name should be lowercase with only letters and underscores. This name cannot be changed!', CCTM::txtdomain);
  1010. $def['post_type']['type'] = 'text';
  1011. $def['post_type']['sort_param'] = 1;
  1012. $def['singular_label']['name'] = 'singular_label';
  1013. $def['singular_label']['label'] = __('Singular Label', CCTM::txtdomain);
  1014. $def['singular_label']['value'] = '';
  1015. $def['singular_label']['extra'] = '';
  1016. $def['singular_label']['description'] = __('Human readable single instance of this content type, e.g. "Post"', CCTM::txtdomain);
  1017. $def['singular_label']['type'] = 'text';
  1018. $def['singular_label']['sort_param'] = 2;
  1019. $def['label']['name'] = 'label';
  1020. $def['label']['label'] = __('Menu Label (Plural)', CCTM::txtdomain);
  1021. $def['label']['value'] = '';
  1022. $def['label']['extra'] = '';
  1023. $def['label']['description'] = __('Plural name used in the admin menu, e.g. "Posts"', CCTM::txtdomain);
  1024. $def['label']['type'] = 'text';
  1025. $def['label']['sort_param'] = 3;
  1026. $def['description']['name'] = 'description';
  1027. $def['description']['label'] = __('Description', CCTM::txtdomain);
  1028. $def['description']['value'] = '';
  1029. $def['description']['extra'] = '';
  1030. $def['description']['description'] = '';
  1031. $def['description']['type'] = 'textarea';
  1032. $def['description']['sort_param'] = 4;
  1033. $def['show_ui']['name'] = 'show_ui';
  1034. $def['show_ui']['label'] = __('Show Admin User Interface', CCTM::txtdomain);
  1035. $def['show_ui']['value'] = '1';
  1036. $def['show_ui']['extra'] = '';
  1037. $def['show_ui']['description'] = __('Should this post type be visible on the back-end?', CCTM::txtdomain);
  1038. $def['show_ui']['type'] = 'checkbox';
  1039. $def['show_ui']['sort_param'] = 5;
  1040. $def['capability_type']['name'] = 'capability_type';
  1041. $def['capability_type']['label'] = __('Capability Type', CCTM::txtdomain);
  1042. $def['capability_type']['value'] = 'post';
  1043. $def['capability_type']['extra'] = '';
  1044. $def['capability_type']['description'] = __('The post type to use for checking read, edit, and delete capabilities. Default: "post"', CCTM::txtdomain);
  1045. $def['capability_type']['type'] = 'text';
  1046. $def['capability_type']['sort_param'] = 6;
  1047. $def['public']['name'] = 'public';
  1048. $def['public']['label'] = __('Public', CCTM::txtdomain);
  1049. $def['public']['value'] = '1';
  1050. $def['public']['extra'] = '';
  1051. $def['public']['description'] = __('Should these posts be visible on the front-end?', CCTM::txtdomain);
  1052. $def['public']['type'] = 'checkbox';
  1053. $def['public']['sort_param'] = 7;
  1054. $def['hierarchical']['name'] = 'hierarchical';
  1055. $def['hierarchical']['label'] = __('Hierarchical', CCTM::txtdomain);
  1056. $def['hierarchical']['value'] = '';
  1057. $def['hierarchical']['extra'] = '';
  1058. $def['hierarchical']['description'] = __('Allows parent to be specified (Page Attributes should be checked)', CCTM::txtdomain);
  1059. $def['hierarchical']['type'] = 'checkbox';
  1060. $def['hierarchical']['sort_param'] = 8;
  1061. $def['supports_title']['name'] = 'supports[]';
  1062. $def['supports_title']['id'] = 'supports_title';
  1063. $def['supports_title']['label'] = __('Title', CCTM::txtdomain);
  1064. $def['supports_title']['value'] = 'title';
  1065. $def['supports_title']['checked_value'] = 'title';
  1066. $def['supports_title']['extra'] = '';
  1067. $def['supports_title']['description'] = __('Post Title', CCTM::txtdomain);
  1068. $def['supports_title']['type'] = 'checkbox';
  1069. $def['supports_title']['sort_param'] = 20;
  1070. $def['supports_editor']['name'] = 'supports[]';
  1071. $def['supports_editor']['id'] = 'supports_editor';
  1072. $def['supports_editor']['label'] = __('Content', CCTM::txtdomain);
  1073. $def['supports_editor']['value'] = 'editor';
  1074. $def['supports_editor']['checked_value'] = 'editor';
  1075. $def['supports_editor']['extra'] = '';
  1076. $def['supports_editor']['description'] = __('Main content block.', CCTM::txtdomain);
  1077. $def['supports_editor']['type'] = 'checkbox';
  1078. $def['supports_editor']['sort_param'] = 21;
  1079. $def['supports_author']['name'] = 'supports[]';
  1080. $def['supports_author']['id'] = 'supports_author';
  1081. $def['supports_author']['label'] = __('Author', CCTM::txtdomain);
  1082. $def['supports_author']['value'] = '';
  1083. $def['supports_author']['checked_value'] = 'author';
  1084. $def['supports_author']['extra'] = '';
  1085. $def['supports_author']['description'] = __('Track the author.', CCTM::txtdomain);
  1086. $def['supports_author']['type'] = 'checkbox';
  1087. $def['supports_author']['sort_param'] = 22;
  1088. $def['supports_thumbnail']['name'] = 'supports[]';
  1089. $def['supports_thumbnail']['id'] = 'supports_thumbnail';
  1090. $def['supports_thumbnail']['label'] = __('Thumbnail', CCTM::txtdomain);
  1091. $def['supports_thumbnail']['value'] = '';
  1092. $def['supports_thumbnail']['checked_value' ] = 'thumbnail';
  1093. $def['supports_thumbnail']['extra'] = '';
  1094. $def['supports_thumbnail']['description'] = __('Featured image (the activetheme must also support post-thumbnails)', CCTM::txtdomain);
  1095. $def['supports_thumbnail']['type'] = 'checkbox';
  1096. $def['supports_thumbnail']['sort_param'] = 23;
  1097. $def['supports_excerpt']['name'] = 'supports[]';
  1098. $def['supports_excerpt']['id'] = 'supports_excerpt';
  1099. $def['supports_excerpt']['label'] = __('Excerpt', CCTM::txtdomain);
  1100. $def['supports_excerpt']['value'] = '';
  1101. $def['supports_excerpt']['checked_value'] = 'excerpt';
  1102. $def['supports_excerpt']['extra'] = '';
  1103. $def['supports_excerpt']['description'] = __('Small summary field.', CCTM::txtdomain);
  1104. $def['supports_excerpt']['type'] = 'checkbox';
  1105. $def['supports_excerpt']['sort_param'] = 24;
  1106. $def['supports_trackbacks']['name'] = 'supports[]';
  1107. $def['supports_trackbacks']['id'] = 'supports_trackbacks';
  1108. $def['supports_trackbacks']['label'] = __('Trackbacks', CCTM::txtdomain);
  1109. $def['supports_trackbacks']['value'] = '';
  1110. $def['supports_trackbacks']['checked_value'] = 'trackbacks';
  1111. $def['supports_trackbacks']['extra'] = '';
  1112. $def['supports_trackbacks']['description'] = '';
  1113. $def['supports_trackbacks']['type'] = 'checkbox';
  1114. $def['supports_trackbacks']['sort_param'] = 25;
  1115. $def['supports_custom-fields']['name'] = 'supports[]';
  1116. $def['supports_custom-fields']['id'] = 'supports_custom-fields';
  1117. $def['supports_custom-fields']['label'] = __('Supports Custom Fields', CCTM::txtdomain);
  1118. $def['supports_custom-fields']['value'] = '';
  1119. $def['supports_custom-fields']['checked_value'] = 'custom-fields';
  1120. $def['supports_custom-fields']['extra'] = '';
  1121. $def['supports_custom-fields']['description'] = '';
  1122. $def['supports_custom-fields']['type'] = 'checkbox';
  1123. $def['supports_custom-fields']['sort_param'] = 26;
  1124. $def['supports_comments']['name'] = 'supports[]';
  1125. $def['supports_comments']['id'] = 'supports_comments';
  1126. $def['supports_comments']['label'] = __('Enable Comments', CCTM::txtdomain);
  1127. $def['supports_comments']['value'] = '';
  1128. $def['supports_comments']['checked_value'] = 'comments';
  1129. $def['supports_comments']['extra'] = '';
  1130. $def['supports_comments']['description'] = '';
  1131. $def['supports_comments']['type'] = 'checkbox';
  1132. $def['supports_comments']['sort_param'] = 27;
  1133. $def['supports_revisions']['name'] = 'supports[]';
  1134. $def['supports_revisions']['id'] = 'supports_revisions';
  1135. $def['supports_revisions']['label'] = __('Store Revisions', CCTM::txtdomain);
  1136. $def['supports_revisions']['value'] = '';
  1137. $def['supports_revisions']['checked_value'] = 'revisions';
  1138. $def['supports_revisions']['extra'] = '';
  1139. $def['supports_revisions']['description'] = '';
  1140. $def['supports_revisions']['type'] = 'checkbox';
  1141. $def['supports_revisions']['sort_param'] = 28;
  1142. $def['supports_page-attributes']['name'] = 'supports[]';
  1143. $def['supports_page-attributes']['id'] = 'supports_page-attributes';
  1144. $def['supports_page-attributes']['label'] = __('Enable Page Attributes', CCTM::txtdomain);
  1145. $def['supports_page-attributes']['value'] = '';
  1146. $def['supports_page-attributes']['checked_value'] = 'page-attributes';
  1147. $def['supports_page-attributes']['extra'] = '';
  1148. $def['supports_page-attributes']['description'] = __('(template and menu order; hierarchical must be checked)', CCTM::txtdomain);
  1149. $def['supports_page-attributes']['type'] = 'checkbox';
  1150. $def['supports_page-attributes']['sort_param'] = 29;
  1151. $def['menu_position']['name'] = 'menu_position';
  1152. $def['menu_position']['label'] = __('Menu Position', CCTM::txtdomain);
  1153. $def['menu_position']['value'] = '';
  1154. $def['menu_position']['extra'] = '';
  1155. $def['menu_position']['description'] =
  1156. sprintf('%1$s
  1157. <ul style="margin-left:40px;">
  1158. <li><strong>5</strong> - %2$s</li>
  1159. <li><strong>10</strong> - %3$s</li>
  1160. <li><strong>20</strong> -

Large files files are truncated, but you can click here to view the full file