PageRenderTime 59ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/wordpress/wp-content/plugins/custom-content-type-manager/includes/CCTM.php

http://ownerpress.googlecode.com/
PHP | 1875 lines | 1117 code | 227 blank | 531 comment | 187 complexity | b0e73917690e62458f7fb3e62d090865 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-1.0, GPL-2.0, GPL-3.0, LGPL-2.1

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. Post Thumbnails support is post-type specific:
  9. http://markjaquith.wordpress.com/2009/12/23/new-in-wordpress-2-9-post-thumbnail-images/
  10. ------------------------------------------------------------------------------*/
  11. class CCTM {
  12. // Name of this plugin
  13. const name = 'Custom Content Type Manager';
  14. // Required versions (referenced in the CCTMtest class).
  15. const wp_req_ver = '3.0.1';
  16. const php_req_ver = '5.2.6';
  17. const mysql_req_ver = '4.1.2';
  18. // Used to uniquely identify an option_name in the wp_options table
  19. // ALL data describing the post types and their custom fields lives there.
  20. // DELETE FROM `wp_options` WHERE option_name='custom_content_types_mgr_data';
  21. // would clean out everything this plugin knows.
  22. const db_key = 'custom_content_types_mgr_data';
  23. // Used to uniquely identify this plugin's menu page in the WP manager
  24. const admin_menu_slug = 'cctm';
  25. // These parameters identify where in the $_GET array we can find the values
  26. // and how URLs are constructed, e.g. some-admin-page.php?a=123&pt=xyz
  27. const action_param = 'a';
  28. const post_type_param = 'pt';
  29. const FormElement_classname_prefix = 'CCTM_';
  30. // Data object stored in the wp_options table representing all primary data
  31. // for post_types and custom fields
  32. public static $data = array();
  33. // integer iterator used to uniquely identify groups of field definitions for
  34. // CSS and $_POST variables
  35. public static $def_i = 0;
  36. // Where are the icons for custom images stored?
  37. // TODO: let the users select their own dir in their own directory
  38. public static $custom_field_icons_dir;
  39. // Built-in post-types that can have custom fields, but cannot be deleted.
  40. public static $built_in_post_types = array('post', 'page');
  41. // Names that are off-limits for custom post types b/c they're already used by WP
  42. public static $reserved_post_types = array('post', 'page', 'attachment', 'revision'
  43. , 'nav_menu', 'nav_menu_item');
  44. // Custom field names are not allowed to use the same names as any column in wp_posts
  45. public static $reserved_field_names = array('ID', 'post_author', 'post_date', 'post_date_gmt',
  46. 'post_content', 'post_title', 'post_excerpt', 'post_status', 'comment_status', 'ping_status',
  47. 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt',
  48. 'post_content_filtered', 'post_parent', 'guid', 'menu_order', 'post_type', 'post_mime_type',
  49. 'comment_count');
  50. // Future-proofing: post-type names cannot begin with 'wp_'
  51. // See: http://codex.wordpress.org/Custom_Post_Types
  52. // FUTURE: List any other reserved prefixes here (if any)
  53. public static $reserved_prefixes = array('wp_');
  54. public static $Errors; // used to store WP_Error object (FUTURE TODO)
  55. /*------------------------------------------------------------------------------
  56. This var stores the big definition for the forms that allow users to define
  57. custom post-types. The form is generated in a way so that when it is posted, it
  58. can be easily passed to WP's register_post_type() function.
  59. We populate the value via the setter function, _set_post_type_form_definition(),
  60. but we do not have a getter. Since we are lazy, and PHP doesn't require
  61. getters/setters, we would have forgone the setter function if possible, but we
  62. had to use a setter simply to avoid the PHP syntax errors that would have
  63. errupted had we tried something like this:
  64. public $myvar = array( 'val' => __('somevalue') );
  65. That fails because we can't use the __() function nakedly when declaring a class
  66. variable. :(
  67. ------------------------------------------------------------------------------*/
  68. public static $post_type_form_definition = array();
  69. /*------------------------------------------------------------------------------
  70. This array defines the form used for all new custom field definitions.
  71. The variable is populated via a setter: _set_custom_field_def_template() for
  72. the same reason as the $post_type_form_definition var above (see above).
  73. See the _page_manage_custom_fields() function for when and how these forms
  74. are used and handled.
  75. ------------------------------------------------------------------------------*/
  76. public static $custom_field_def_template = array();
  77. //! Private Functions
  78. //------------------------------------------------------------------------------
  79. /**
  80. * Geared to be backwards compatible with CCTM versions prior to 0.8.8 where
  81. * custom field defs were stored in numbered arrays instead of keyed off of their
  82. * unique names.
  83. *
  84. * @param mixed $data: full data structure
  85. * @param string $post_type: the name of this post_type
  86. * @param string $field_name: the name of the field whose data you want
  87. * @return array associative array representing a field definition for $field_name
  88. */
  89. private static function _get_field_data($data, $post_type, $field_name) {
  90. if ( empty($data) || empty($data[$post_type]) || empty($data[$post_type]['custom_fields']))
  91. {
  92. return array();
  93. }
  94. foreach ( $data[$post_type]['custom_fields'] as $tmp => $def )
  95. {
  96. if ( $def['name'] == $field_name )
  97. {
  98. return $def;
  99. }
  100. }
  101. return array(); // gave up
  102. }
  103. /*------------------------------------------------------------------------------
  104. Generate HTML portion of our manage custom fields form. This is in distinction
  105. to the JS portion of the form, which uses a slightly different format.
  106. self::$def_i is used to track the definition #. All 5 output fields will use
  107. the same $def_i number to identify their place in the $_POST array.
  108. INPUT: $custom_field_defs (mixed) an array of hashes, each hash describing
  109. a custom field.
  110. Array
  111. (
  112. [1] => Array
  113. (
  114. [label] => Rating
  115. [name] => rating
  116. [description] => MPAA rating
  117. [type] => dropdown
  118. [options] => Array
  119. (
  120. [0] => G
  121. [1] => PG
  122. [2] => PG-13
  123. )
  124. [sort_param] =>
  125. )
  126. )
  127. OUTPUT: An HTML form, length depends on the # of field defs.
  128. * @return unknown
  129. */
  130. private static function _get_field_type_icons() {
  131. $icons = array();
  132. if ($handle = opendir(CCTM_PATH.'/images/custom-fields/')) {
  133. while (false !== ($file = readdir($handle))) {
  134. if ( !preg_match('/^\./', $file) && preg_match('/\.png$/i', $file) ) {
  135. $icons[] = $file;
  136. }
  137. }
  138. closedir($handle);
  139. }
  140. $output = '';
  141. $tpl = CCTM_PATH.'/tpls/settings/icon.tpl';
  142. if ( file_exists($tpl) ) {
  143. $tpl = file_get_contents($tpl);
  144. }
  145. foreach ( $icons as $img ) {
  146. $output .= FormGenerator::parse($tpl, array('title'=> $img, 'src'=> CCTM_URL.'/images/icons/default/'.$img) );
  147. }
  148. return $output;
  149. }
  150. //------------------------------------------------------------------------------
  151. /**
  152. *
  153. *
  154. * @return unknown
  155. */
  156. private static function _get_post_type_icons() {
  157. $icons = array();
  158. if ($handle = opendir(CCTM_PATH.'/images/icons/default')) {
  159. while (false !== ($file = readdir($handle))) {
  160. if ( !preg_match('/^\./', $file) ) {
  161. $icons[] = $file;
  162. }
  163. }
  164. closedir($handle);
  165. }
  166. $output = '';
  167. $tpl = CCTM_PATH.'/tpls/settings/icon.tpl';
  168. if ( file_exists($tpl) ) {
  169. $tpl = file_get_contents($tpl);
  170. }
  171. foreach ( $icons as $img ) {
  172. $output .= FormGenerator::parse($tpl, array('title'=> $img, 'src'=> CCTM_URL.'/images/icons/default/'.$img) );
  173. }
  174. return $output;
  175. }
  176. /*------------------------------------------------------------------------------
  177. Designed to safely retrieve scalar elements out of a hash. Don't use this
  178. if you have a more deeply nested object (e.g. an array of arrays).
  179. INPUT:
  180. $hash : an associative array, e.g. array('animal' => 'Cat');
  181. $key : the key to search for in that array, e.g. 'animal'
  182. $default (optional) : value to return if the value is not set. Default=''
  183. OUTPUT: either safely escaped value from the hash or the default value
  184. ------------------------------------------------------------------------------*/
  185. /**
  186. *
  187. *
  188. * @param unknown $hash
  189. * @param unknown $key
  190. * @param unknown $default (optional)
  191. * @return unknown
  192. */
  193. private static function _get_value($hash, $key, $default='') {
  194. if ( !isset($hash[$key]) ) {
  195. return $default;
  196. }
  197. else {
  198. if ( is_array($hash[$key]) ) {
  199. return $hash[$key];
  200. }
  201. // Warning: stripslashes was added to avoid some weird behavior
  202. else {
  203. return esc_html(stripslashes($hash[$key]));
  204. }
  205. }
  206. }
  207. //------------------------------------------------------------------------------
  208. /**
  209. SYNOPSIS: checks the custom content data array to see if $post_type exists.
  210. The $data array is structured something like this:
  211. $data = array(
  212. 'movie' => array('name'=>'movie', ... ),
  213. 'book' => array('name'=>'book', ... ),
  214. ...
  215. );
  216. So we can just check the keys of the main array to see if the post type exists.
  217. Built-in post types 'page' and 'post' are considered valid (i.e. existing) by
  218. default, even if they haven't been explicitly defined for use by this plugin
  219. so long as the 2nd argument, $search_built_ins, is not overridden to false.
  220. *
  221. *
  222. * @param string $post_type the lowercase database slug identifying a post type.
  223. * @param boolean $search_built_ins (optional) whether or not to search inside the
  224. $built_in_post_types array.
  225. * @return boolean indicating whether this is a valid post-type
  226. */
  227. private static function _is_existing_post_type($post_type, $search_built_ins=true) {
  228. // If there is no existing data, check against the built-ins
  229. if ( empty(self::$data) && $search_built_ins ) {
  230. return in_array($post_type, self::$built_in_post_types);
  231. }
  232. // If there's no existing $data and we omit the built-ins...
  233. elseif ( empty(self::$data) && !$search_built_ins ) {
  234. return false;
  235. }
  236. // Check to see if we've stored this $post_type before
  237. elseif ( array_key_exists($post_type, self::$data) ) {
  238. return true;
  239. }
  240. // Check the built-ins
  241. elseif ( $search_built_ins && in_array($post_type, self::$built_in_post_types) ) {
  242. return true;
  243. }
  244. else {
  245. return false;
  246. }
  247. }
  248. //! Links
  249. //------------------------------------------------------------------------------
  250. /**
  251. *
  252. *
  253. * @param string $post_type
  254. * @return unknown
  255. */
  256. private static function _link_activate($post_type) {
  257. return sprintf(
  258. '<a href="?page=%s&%s=6&%s=%s" title="%s">%s</a>'
  259. , self::admin_menu_slug
  260. , self::action_param
  261. , self::post_type_param
  262. , $post_type
  263. , __('Activate this content type', CCTM_TXTDOMAIN)
  264. , __('Activate', CCTM_TXTDOMAIN)
  265. );
  266. }
  267. //------------------------------------------------------------------------------
  268. /**
  269. * $tpl = sprintf(
  270. * '<li><a href="?page=%s&%s=9&%s=%s&type=[+field_type+]" title="[+title+]">
  271. * <img src="[+icon_src+]" class="cctm-field-icon" id="cctm-field-icon-[+field_type+]"/>
  272. * <br/>[+label+]</a>
  273. * </li>'
  274. *
  275. * @param string $post_type
  276. * @return unknown
  277. */
  278. private static function _link_create_custom_field($post_type) {
  279. $output = '<ul id="cctm-field-type-selector">';
  280. $tpl = sprintf(
  281. '<li><a href="?page=%s&%s=9&%s=%s&type=[+field_type+]" title="[+title+]">
  282. <img src="[+icon_src+]" class="cctm-field-icon" id="cctm-field-icon-[+field_type+]"/>
  283. </a>
  284. <!-- a href="?page=%s&%s=9&%s=%s&type=[+field_type+]" class="button" title="[+title+]">[+label+]</a-->
  285. </li>'
  286. , self::admin_menu_slug
  287. , self::action_param
  288. , self::post_type_param
  289. , $post_type
  290. , self::admin_menu_slug
  291. , self::action_param
  292. , self::post_type_param
  293. , $post_type
  294. );
  295. foreach ( self::$custom_field_def_template['type']['options'] as $field_type ) {
  296. $hash = array();
  297. $hash['icon_src'] = self::get_custom_icons_src_dir() . $field_type.'.png';
  298. // Use the default image if necessary
  299. if (!@fclose(@fopen($hash['icon_src'], 'r'))) {
  300. $hash['icon_src'] = self::get_custom_icons_src_dir() . 'default.png';
  301. }
  302. $hash['field_type'] = $field_type;
  303. $hash['label'] = ucfirst($field_type);
  304. $hash['title'] = sprintf( __('Create a %s custom field', CCTM_TXTDOMAIN), $field_type );
  305. $output .= FormGenerator::parse($tpl, $hash);
  306. }
  307. return $output . '</ul>';
  308. }
  309. //------------------------------------------------------------------------------
  310. /**
  311. *
  312. *
  313. * @param string $post_type
  314. * @return unknown
  315. */
  316. private static function _link_deactivate($post_type) {
  317. return sprintf(
  318. '<a href="?page=%s&%s=7&%s=%s" title="%s">%s</a>'
  319. , self::admin_menu_slug
  320. , self::action_param
  321. , self::post_type_param
  322. , $post_type
  323. , __('Deactivate this content type', CCTM_TXTDOMAIN)
  324. , __('Deactivate', CCTM_TXTDOMAIN)
  325. );
  326. }
  327. //------------------------------------------------------------------------------
  328. /**
  329. *
  330. *
  331. * @param string $post_type
  332. * @return unknown
  333. */
  334. private static function _link_delete($post_type) {
  335. return sprintf(
  336. '<a href="?page=%s&%s=3&%s=%s" title="%s">%s</a>'
  337. , self::admin_menu_slug
  338. , self::action_param
  339. , self::post_type_param
  340. , $post_type
  341. , __('Delete this content type', CCTM_TXTDOMAIN)
  342. , __('Delete', CCTM_TXTDOMAIN)
  343. );
  344. }
  345. //------------------------------------------------------------------------------
  346. /**
  347. * Delete all custom fields for the given post_type
  348. *
  349. * @param string $post_type
  350. * @return string
  351. */
  352. private static function _link_reset_all_custom_fields($post_type) {
  353. return sprintf(
  354. '<a href="?page=%s&%s=12&%s=%s" title="%s" class="button">%s</a>'
  355. , self::admin_menu_slug
  356. , self::action_param
  357. , self::post_type_param
  358. , $post_type
  359. , __('Delete all custom field definitions for this post type', CCTM_TXTDOMAIN)
  360. , __('Reset Custom Fields', CCTM_TXTDOMAIN)
  361. );
  362. }
  363. ///------------------------------------------------------------------------------
  364. /**
  365. *
  366. *
  367. * @param string $post_type a post_type known to CCTM (not necessarily currently registered)
  368. * @return string HTML link for managing the custom fields
  369. */
  370. private static function _link_manage_custom_fields($post_type) {
  371. return sprintf(
  372. '<a href="?page=%s&%s=4&%s=%s" title="%s">%s</a>'
  373. , self::admin_menu_slug
  374. , self::action_param
  375. , self::post_type_param
  376. , $post_type
  377. , __('Manage Custom Fields for this content type', CCTM_TXTDOMAIN)
  378. , __('Manage Custom Fields', CCTM_TXTDOMAIN)
  379. );
  380. }
  381. //------------------------------------------------------------------------------
  382. /**
  383. *
  384. *
  385. * @param string $post_type a post_type known to CCTM (not necessarily currently registered)
  386. * @return string HTML link to edit a post_type
  387. */
  388. private static function _link_edit($post_type) {
  389. return sprintf(
  390. '<a href="?page=%s&%s=2&%s=%s" title="%s">%s</a>'
  391. , self::admin_menu_slug
  392. , self::action_param
  393. , self::post_type_param
  394. , $post_type
  395. , __('Edit this content type', CCTM_TXTDOMAIN )
  396. , __('Edit', CCTM_TXTDOMAIN)
  397. );
  398. }
  399. //------------------------------------------------------------------------------
  400. /**
  401. *
  402. *
  403. * @param string $post_type
  404. * @return unknown
  405. */
  406. private static function _link_view_sample_templates($post_type) {
  407. return sprintf('<a href="?page=%s&%s=8&%s=%s" title="%s">%s</a>'
  408. , self::admin_menu_slug
  409. , self::action_param
  410. , self::post_type_param
  411. , $post_type
  412. , __('View Sample Templates for this content type', CCTM_TXTDOMAIN )
  413. , __('View Sample Templates', CCTM_TXTDOMAIN)
  414. );
  415. }
  416. //! Pages
  417. //------------------------------------------------------------------------------
  418. /**
  419. * Manager Page -- called by page_main_controller()
  420. * Activating a post type will cause it to show up in the WP menus and its custom
  421. * fields will be managed.
  422. * @param string $post_type
  423. */
  424. private static function _page_activate_post_type($post_type) {
  425. // Validate post type
  426. if (!self::_is_existing_post_type($post_type) ) {
  427. self::_page_display_error();
  428. return;
  429. }
  430. self::$data[$post_type]['is_active'] = 1;
  431. update_option( self::db_key, self::$data );
  432. $msg = '
  433. <div class="updated">
  434. <p>'
  435. . sprintf( __('The %s post_type has been activated.', CCTM_TXTDOMAIN), '<em>'.$post_type.'</em>')
  436. . '</p>
  437. </div>';
  438. self::set_flash($msg);
  439. // Often, PHP scripts use the header() function to refresh a page, but
  440. // WP has already claimed those, so we use a JavaScript refresh instead.
  441. // Refreshing the page ensures that active post types are added to menus.
  442. $msg = '
  443. <script type="text/javascript">
  444. window.location.replace("?page='.self::admin_menu_slug.'");
  445. </script>';
  446. print $msg;
  447. }
  448. //------------------------------------------------------------------------------
  449. /**
  450. Edit a custom field. This is a bit complicated, but it doesn't involve JS like
  451. the previous version did.
  452. *
  453. *
  454. * @param string $post_type
  455. * @param string $field_name
  456. */
  457. private static function _page_create_custom_field($post_type, $field_type) {
  458. if ( !self::_is_existing_post_type($post_type, true ) ) {
  459. self::_page_display_error();
  460. return;
  461. }
  462. // Page variables
  463. $heading = __('Create Field', CCTM_TXTDOMAIN);
  464. $action_name = 'custom_content_type_mgr_create_new_custom_field';
  465. $nonce_name = 'custom_content_type_mgr_create_new_custom_field_nonce';
  466. $success_msg = sprintf('<div class="updated"><p>%s</p></div>'
  467. , sprintf(__('A custom field for %s has been created.', CCTM_TXTDOMAIN)
  468. , '<em>'.$post_type.'</em>'));
  469. $field_data = array(); // Data object we will save
  470. self::include_form_element_class($field_type); // This will die on errors
  471. $field_type_name = self::FormElement_classname_prefix.$field_type;
  472. $FieldObj = new $field_type_name(); // Instantiate the field element
  473. // Save if submitted...
  474. if ( !empty($_POST) && check_admin_referer($action_name, $nonce_name) ) {
  475. // A little cleanup before we handoff to save_field_filter
  476. unset($_POST[ $nonce_name ]);
  477. unset($_POST['_wp_http_referer']);
  478. // Validate and sanitize any submitted data
  479. $field_data = $FieldObj->save_field_filter($_POST, $post_type);
  480. $field_data['type'] = $field_type; // same effect as adding a hidden field
  481. $FieldObj->props = $field_data; // This is how we repopulate data in the create forms
  482. // Any errors?
  483. if ( !empty($FieldObj->errors) ) {
  484. $msg = $FieldObj->format_errors();
  485. }
  486. // Save;
  487. else {
  488. $field_name = $field_data['name'];
  489. self::$data[$post_type]['custom_fields'][$field_name] = $field_data;
  490. update_option( self::db_key, self::$data );
  491. unset($_POST);
  492. self::set_flash($success_msg);
  493. self::_page_show_custom_fields($post_type);
  494. return;
  495. }
  496. }
  497. // this should change to get_edit_field_definition() if it's an edit.
  498. $fields = $FieldObj->get_create_field_definition();
  499. $submit_link = $tpl = sprintf(
  500. '?page=%s&%s=9&%s=%s&type=%s'
  501. , self::admin_menu_slug
  502. , self::action_param
  503. , self::post_type_param
  504. , $post_type
  505. , $field_type
  506. );
  507. $icon = $FieldObj->get_icon();
  508. include 'pages/custom_field.php';
  509. }
  510. //------------------------------------------------------------------------------
  511. /**
  512. * Edit a custom field. This is a bit complicated, but it doesn't involve JS like
  513. * the previous version did.
  514. *
  515. * @param string $post_type
  516. * @param string $field_name uniquely identifies this field inside this post_type
  517. */
  518. //! Working here...
  519. private static function _page_edit_custom_field($post_type, $field_name) {
  520. if ( !self::_is_existing_post_type($post_type, true ) ) {
  521. self::_page_display_error();
  522. return;
  523. }
  524. $field_data = array(); // Data object we will save
  525. // For compatibility with versions prior to 0.8.8, we iterate through
  526. if ( !empty(self::$data[$post_type]['custom_fields']) ) {
  527. foreach (self::$data[$post_type]['custom_fields'] as $k => $def )
  528. {
  529. $custom_fields_array[] = $def['name'];
  530. if ($def['name'] == $field_name) {
  531. $field_data = $def; // Data object we will save
  532. }
  533. }
  534. }
  535. if ( !in_array($field_name, $custom_fields_array) ) {
  536. $msg = '<p>'. __('Invalid custom field.', CCTM_TXTDOMAIN)
  537. . '</p>';
  538. $msg .= sprintf(
  539. '<a href="?page=%s&%s=4&%s=%s" title="%s" class="button">%s</a>'
  540. , self::admin_menu_slug
  541. , self::action_param
  542. , self::post_type_param
  543. , $post_type
  544. , __('Manage Custom Fields for this content type', CCTM_TXTDOMAIN)
  545. , __('Back', CCTM_TXTDOMAIN)
  546. );
  547. wp_die( $msg );
  548. }
  549. $field_type = $field_data['type'];
  550. // Page variables
  551. $heading = __('Create Field', CCTM_TXTDOMAIN);
  552. $action_name = 'custom_content_type_mgr_create_new_custom_field';
  553. $nonce_name = 'custom_content_type_mgr_create_new_custom_field_nonce';
  554. $success_msg = sprintf('<div class="updated"><p>%s</p></div>'
  555. , sprintf(__('The %s custom field has been edited.', CCTM_TXTDOMAIN)
  556. , '<em>'.$post_type.'</em>'));
  557. self::include_form_element_class($field_type); // This will die on errors
  558. $field_type_name = self::FormElement_classname_prefix.$field_type;
  559. $FieldObj = new $field_type_name(); // Instantiate the field element
  560. //
  561. $FieldObj->props = $field_data;
  562. // THIS is what keys us off to the fact that we're EDITING a field:
  563. // the logic in FormElement->save_field_filter() ensures we don't overwrite other fields.
  564. // This attribute is nuked by the time we get down to line 691 or so.
  565. $FieldObj->original_name = $field_name;
  566. // Save if submitted...
  567. if ( !empty($_POST) && check_admin_referer($action_name, $nonce_name) ) {
  568. // A little cleanup before we handoff to save_field_filter
  569. unset($_POST[ $nonce_name ]);
  570. unset($_POST['_wp_http_referer']);
  571. // Validate and sanitize any submitted data
  572. $field_data = $FieldObj->save_field_filter($_POST, $post_type);
  573. $field_data['type'] = $field_type; // same effect as adding a hidden field
  574. $FieldObj->props = $field_data;
  575. // Any errors?
  576. if ( !empty($FieldObj->errors) ) {
  577. $msg = $FieldObj->format_errors();
  578. }
  579. // Save;
  580. else {
  581. // Unset the old field if the name changed ($field_name is passed via $_GET)
  582. if ($field_name != $field_data['name']) {
  583. unset(self::$data[$post_type]['custom_fields'][$field_name]);
  584. }
  585. self::$data[$post_type]['custom_fields'][ $field_data['name'] ] = $field_data;
  586. update_option( self::db_key, self::$data );
  587. unset($_POST);
  588. self::set_flash($success_msg);
  589. self::_page_show_custom_fields($post_type);
  590. return;
  591. }
  592. }
  593. $fields = $FieldObj->get_edit_field_definition($field_data);
  594. $submit_link = $tpl = sprintf(
  595. '?page=%s&%s=9&%s=%s&type=%s'
  596. , self::admin_menu_slug
  597. , self::action_param
  598. , self::post_type_param
  599. , $post_type
  600. , $field_type
  601. );
  602. include 'pages/custom_field.php';
  603. }
  604. //------------------------------------------------------------------------------
  605. /**
  606. * Manager Page -- called by page_main_controller()
  607. * Create a new post type
  608. */
  609. private static function _page_create_new_post_type() {
  610. self::_set_post_type_form_definition();
  611. // Variables for our template
  612. $page_header = __('Create Custom Content Type', CCTM_TXTDOMAIN);
  613. $fields = '';
  614. $action_name = 'custom_content_type_mgr_create_new_content_type';
  615. $nonce_name = 'custom_content_type_mgr_create_new_content_type_nonce';
  616. $submit = __('Create New Content Type', CCTM_TXTDOMAIN);
  617. $msg = '';
  618. $def = self::$post_type_form_definition;
  619. // Save data if it was properly submitted
  620. if ( !empty($_POST) && check_admin_referer($action_name, $nonce_name) ) {
  621. $sanitized_vals = self::_sanitize_post_type_def($_POST);
  622. $error_msg = self::_post_type_name_has_errors($sanitized_vals, true);
  623. if ( empty($error_msg) ) {
  624. self::_save_post_type_settings($sanitized_vals);
  625. $msg = '
  626. <div class="updated">
  627. <p>'
  628. . sprintf( __('The content type %s has been created', CCTM_TXTDOMAIN), '<em>'.$sanitized_vals['post_type'].'</em>')
  629. . '</p>
  630. </div>';
  631. self::set_flash($msg);
  632. self::_page_show_all_post_types();
  633. return;
  634. }
  635. else {
  636. //! Error: see issue 17: http://code.google.com/p/wordpress-custom-content-type-manager/issues/detail?id=37
  637. // This won't work bc the location in the $_POST array does not match the location in the $def. This needs a _post_to_def() function.. mostly direct throughput, but we'd have to identify the array inputs and walk through them specifically.
  638. // This is for repopulating the form
  639. foreach ( $def as $node_id => &$d ) {
  640. $d['value'] = self::_get_value($sanitized_vals, $d['name']);
  641. }
  642. $msg = "<div class='error'>$error_msg</div>";
  643. }
  644. }
  645. //
  646. foreach ($def as $pt => &$d) {
  647. $d['raw_name'] = $pt;
  648. }
  649. $fields = FormGenerator::generate($def, 'css-friendly');
  650. $mgr_tpl_file = CCTM_PATH.'/tpls/settings/edit_post_type.tpl';
  651. if ( file_exists($mgr_tpl_file) ) {
  652. $tpl = file_get_contents($mgr_tpl_file);
  653. FormGenerator::$placeholders['icons'] = self::_get_post_type_icons();
  654. FormGenerator::$placeholders['CCTM_URL'] = CCTM_URL;
  655. $fields = FormGenerator::parse($tpl, FormGenerator::$placeholders);
  656. }
  657. include 'pages/basic_form.php';
  658. }
  659. /*------------------------------------------------------------------------------
  660. Manager Page -- called by page_main_controller()
  661. Deactivate a post type. This will remove custom post types from the WP menus;
  662. deactivation stops custom fields from being standardized in built-in and custom
  663. post types
  664. ------------------------------------------------------------------------------*/
  665. /**
  666. *
  667. *
  668. * @param string $post_type
  669. */
  670. private static function _page_deactivate_post_type($post_type) {
  671. // Validate post type
  672. if (!self::_is_existing_post_type($post_type) ) {
  673. self::_page_display_error();
  674. return;
  675. }
  676. // Variables for our template
  677. $style = '';
  678. $page_header = sprintf( __('Deactivate Content Type %s', CCTM_TXTDOMAIN), $post_type );
  679. $fields = '';
  680. $action_name = 'custom_content_type_mgr_deactivate_content_type';
  681. $nonce_name = 'custom_content_type_mgr_deactivate_content_type_nonce';
  682. $submit = __('Deactivate', CCTM_TXTDOMAIN);
  683. // If properly submitted, Proceed with deleting the post type
  684. if ( !empty($_POST) && check_admin_referer($action_name, $nonce_name) ) {
  685. // get current values from database
  686. self::$data[$post_type]['is_active'] = 0;
  687. update_option( self::db_key, self::$data );
  688. $msg = '<div class="updated"><p>'
  689. . sprintf( __('The %s content type has been deactivated.', CCTM_TXTDOMAIN), $post_type )
  690. . '</p></div>';
  691. self::set_flash($msg);
  692. // A JavaScript refresh ensures that inactive post types are removed from the menus.
  693. $msg = '
  694. <script type="text/javascript">
  695. window.location.replace("?page='.self::admin_menu_slug.'");
  696. </script>';
  697. print $msg;
  698. return;
  699. }
  700. $msg = '<div class="error">
  701. <img src="'.CCTM_URL.'/images/warning-icon.png" width="50" height="44" style="float:left; padding:10px;"/>
  702. <p>'
  703. . sprintf( __('You are about to deactivate the %s post type.', CCTM_TXTDOMAIN ), "<strong>$post_type</strong>")
  704. .'</p>';
  705. // If it's a custom post type, we include some additional info.
  706. if ( !in_array($post_type, self::$built_in_post_types) ) {
  707. $msg .= '<p>'
  708. . sprintf( __('Deactivation does not delete anything, but it does make %s posts 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), "<strong>$post_type</strong>", "<strong>$post_type</strong>" )
  709. .'</p>';
  710. }
  711. $post_cnt_obj = wp_count_posts($post_type);
  712. $msg .= '<p>'
  713. . sprintf( __('This would affect %1$s published %2$s posts.'
  714. , CCTM_TXTDOMAIN), '<strong>'.$post_cnt_obj->publish.'</strong>'
  715. , "<strong>$post_type</strong>")
  716. .'</p>';
  717. $msg .= '<p>'.__('Are you sure you want to do this?', CCTM_TXTDOMAIN).'
  718. <a href="http://code.google.com/p/wordpress-custom-content-type-manager/wiki/DeactivatePostType" title="deactivating a content type" target="_blank">
  719. <img src="'.CCTM_URL.'/images/question-mark.gif" width="16" height="16" />
  720. </a>
  721. </p>
  722. </div>';
  723. include 'pages/basic_form.php';
  724. }
  725. //------------------------------------------------------------------------------
  726. /**
  727. * called by page_main_controller()
  728. *
  729. * @param string $post_type
  730. * @param null
  731. */
  732. private static function _page_delete_custom_field($post_type, $field) {
  733. // We can't delete built-in post types
  734. if (!self::_is_existing_post_type($post_type, false ) ) {
  735. self::_page_display_error();
  736. return;
  737. }
  738. $custom_fields_array = array();
  739. #print_r($data[$post_type]['custom_fields']); exit;
  740. // For compatibility with versions prior to 0.8.8, we iterate through
  741. if ( !empty(self::$data[$post_type]['custom_fields']) ) {
  742. foreach (self::$data[$post_type]['custom_fields'] as $k => $def )
  743. {
  744. $custom_fields_array[] = $def['name'];
  745. }
  746. # $custom_fields_array = array_keys($data[$post_type]['custom_fields']);
  747. }
  748. if ( !in_array($field, $custom_fields_array) ) {
  749. $msg = '<p>'. __('Invalid custom field.', CCTM_TXTDOMAIN)
  750. . '</p>';
  751. $msg .= sprintf(
  752. '<a href="?page=%s&%s=4&%s=%s" title="%s" class="button">%s</a>'
  753. , self::admin_menu_slug
  754. , self::action_param
  755. , self::post_type_param
  756. , $post_type
  757. , __('Manage Custom Fields for this content type', CCTM_TXTDOMAIN)
  758. , __('Back', CCTM_TXTDOMAIN)
  759. );
  760. wp_die( $msg );
  761. }
  762. $nonce = self::_get_value($_GET, '_wpnonce');
  763. if (! wp_verify_nonce($nonce, 'cctm_delete_field') ) {
  764. die( __('Invalid request.', CCTM_TXTDOMAIN ) );
  765. }
  766. else {
  767. // Again, for compatibility with versions prior to 0.8.8, we do not assume that the
  768. // field names exist as keys inside of 'custom_fields' (there could be int keys)
  769. foreach (self::$data[$post_type]['custom_fields'] as $k => $def ) {
  770. if ($def['name'] == $field) {
  771. unset(self::$data[$post_type]['custom_fields'][$k]);
  772. }
  773. }
  774. update_option( self::db_key, self::$data );
  775. $msg = '<div class="updated"><p>'
  776. .sprintf( __('The %s custom field has been deleted', CCTM_TXTDOMAIN), "<em>$field</em>")
  777. . '</p></div>';
  778. self::set_flash($msg);
  779. unset($_POST);
  780. self::_page_show_custom_fields($post_type);
  781. return;
  782. }
  783. }
  784. //------------------------------------------------------------------------------
  785. /**
  786. * Manager Page -- called by page_main_controller()
  787. * This is only a valid page for custom post types.
  788. * @param string $post_type
  789. * @return null
  790. */
  791. private static function _page_delete_post_type($post_type) {
  792. // We can't delete built-in post types
  793. if (!self::_is_existing_post_type($post_type, false ) ) {
  794. self::_page_display_error();
  795. return;
  796. }
  797. // Variables for our template
  798. $style = '';
  799. $page_header = sprintf( __('Delete Content Type: %s', CCTM_TXTDOMAIN), $post_type );
  800. $fields = '';
  801. $action_name = 'custom_content_type_mgr_delete_content_type';
  802. $nonce_name = 'custom_content_type_mgr_delete_content_type_nonce';
  803. $submit = __('Delete', CCTM_TXTDOMAIN);
  804. // If properly submitted, Proceed with deleting the post type
  805. if ( !empty($_POST) && check_admin_referer($action_name, $nonce_name) ) {
  806. unset(self::$data[$post_type]); // <-- Delete this node of the data structure
  807. update_option( self::db_key, self::$data );
  808. $msg = '<div class="updated"><p>'
  809. .sprintf( __('The post type %s has been deleted', CCTM_TXTDOMAIN), "<em>$post_type</em>")
  810. . '</p></div>';
  811. self::set_flash($msg);
  812. self::_page_show_all_post_types();
  813. return;
  814. }
  815. $msg = '<div class="error">
  816. <img src="'.CCTM_URL.'/images/warning-icon.png" width="50" height="44" style="float:left; padding:10px;"/>
  817. <p>'
  818. . 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>" )
  819. .'</p>'
  820. . '<p>'.__('Are you sure you want to do this?', CCTM_TXTDOMAIN).'
  821. <a href="http://code.google.com/p/wordpress-custom-content-type-manager/wiki/DeletePostType" title="Deleting a content type" target="_blank">
  822. <img src="'.CCTM_URL.'/images/question-mark.gif" width="16" height="16" />
  823. </a>
  824. </p></div>';
  825. include 'pages/basic_form.php';
  826. }
  827. //------------------------------------------------------------------------------
  828. /**
  829. * Manager Page -- called by page_main_controller()
  830. * Returned on errors. Future: accept an argument identifying an error
  831. * @param string $msg_id identifies the error.
  832. */
  833. private static function _page_display_error($msg_id='invalid_post_type') {
  834. $msg = '';
  835. switch ($msg_id) {
  836. case 'invalid_field_name':
  837. $msg = '<p>'. __('Invalid field name.', CCTM_TXTDOMAIN)
  838. . '</p><a class="button" href="?page='
  839. .self::admin_menu_slug.'">'. __('Back', CCTM_TXTDOMAIN). '</a>';
  840. break;
  841. default:
  842. $msg = '<p>'. __('Invalid post type.', CCTM_TXTDOMAIN)
  843. . '</p><a class="button" href="?page='
  844. .self::admin_menu_slug.'">'. __('Back', CCTM_TXTDOMAIN). '</a>';
  845. }
  846. wp_die( $msg );
  847. }
  848. //------------------------------------------------------------------------------
  849. /**
  850. * Manager Page -- called by page_main_controller()
  851. * Edit an existing post type. Changing the unique post-type identifier (i.e. name)
  852. * is not allowed.
  853. * @param string $post_type
  854. */
  855. private static function _page_edit_post_type($post_type) {
  856. // We can't edit built-in post types
  857. if (!self::_is_existing_post_type($post_type, false ) ) {
  858. self::_page_display_error();
  859. return;
  860. }
  861. self::_set_post_type_form_definition($post_type);
  862. // Variables for our template (TODO: register this instead of this cheap inline trick)
  863. $style = '';
  864. $page_header = __('Edit Content Type: ') . $post_type;
  865. $fields = '';
  866. $action_name = 'custom_content_type_mgr_edit_content_type';
  867. $nonce_name = 'custom_content_type_mgr_edit_content_type_nonce';
  868. $submit = __('Save', CCTM_TXTDOMAIN);
  869. $msg = ''; // Any validation errors
  870. $def = self::$post_type_form_definition;
  871. $def['post_type']['type'] = 'readonly';
  872. $def['post_type']['description'] = __('The name of the post-type cannot be changed. The name 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>.', CCTM_TXTDOMAIN);
  873. // Save data if it was properly submitted
  874. if ( !empty($_POST) && check_admin_referer($action_name, $nonce_name) ) {
  875. $sanitized_vals = self::_sanitize_post_type_def($_POST);
  876. //print_r($sanitized_vals); exit;
  877. $error_msg = self::_post_type_name_has_errors($sanitized_vals);
  878. if ( empty($error_msg) ) {
  879. self::_save_post_type_settings($sanitized_vals);
  880. $msg .= '<div class="updated"><p>'
  881. . sprintf( __('Settings for %s have been updated.', CCTM_TXTDOMAIN )
  882. , '<em>'.$sanitized_vals['post_type'].'</em>')
  883. .'</p></div>';
  884. self::set_flash($msg);
  885. $msg = '
  886. <script type="text/javascript">
  887. window.location.replace("?page='.self::admin_menu_slug.'");
  888. </script>';
  889. print $msg;
  890. return;
  891. }
  892. else {
  893. // This is for repopulating the form
  894. $def = self::_populate_form_def_from_data($def, $sanitized_vals);
  895. $msg = "<div class='error'>$error_msg</div>";
  896. }
  897. }
  898. //
  899. foreach ($def as $pt => &$d) {
  900. $d['raw_name'] = $pt;
  901. }
  902. // Populate the form $def with values from the database
  903. $def = self::_populate_form_def_from_data($def, self::$data[$post_type]);
  904. $fields = FormGenerator::generate($def, 'css-friendly');
  905. $mgr_tpl_file = CCTM_PATH.'/tpls/settings/edit_post_type.tpl';
  906. if ( file_exists($mgr_tpl_file) ) {
  907. $tpl = file_get_contents($mgr_tpl_file);
  908. FormGenerator::$placeholders['icons'] = self::_get_post_type_icons();
  909. FormGenerator::$placeholders['CCTM_URL'] = CCTM_URL;
  910. // print_r(FormGenerator::$placeholders);
  911. $fields = FormGenerator::parse($tpl, FormGenerator::$placeholders);
  912. }
  913. include 'pages/basic_form.php';
  914. }
  915. //------------------------------------------------------------------------------
  916. /**
  917. Manager Page -- called by page_main_controller()
  918. Deletes all custom field definitions for a given post_type.
  919. * @param string $post_type
  920. */
  921. private static function _page_reset_all_custom_fields($post_type) {
  922. // We can't delete built-in post types
  923. if (!self::_is_existing_post_type($post_type, true ) ) {
  924. self::_page_display_error();
  925. return;
  926. }
  927. // Variables for our template
  928. $style = '';
  929. $page_header = sprintf( __('Reset custom field definitions for post type %s', CCTM_TXTDOMAIN), $post_type );
  930. $fields = '';
  931. $action_name = 'custom_content_type_mgr_delete_all_custom_fields';
  932. $nonce_name = 'custom_content_type_mgr_delete_all_custom_fields';
  933. $submit = __('Reset', CCTM_TXTDOMAIN);
  934. // If properly submitted, Proceed with deleting the post type
  935. if ( !empty($_POST) && check_admin_referer($action_name, $nonce_name) ) {
  936. unset(self::$data[$post_type]['custom_fields']); // <-- Delete this node of the data structure
  937. update_option( self::db_key, self::$data );
  938. $msg = '<div class="updated"><p>'
  939. .sprintf( __('All custom field definitions for the %s post type have been deleted', CCTM_TXTDOMAIN), "<em>$post_type</em>")
  940. . '</p></div>';
  941. self::set_flash($msg);
  942. self::_page_show_custom_fields($post_type, true);
  943. return;
  944. }
  945. $msg = '<div class="error">
  946. <img src="'.CCTM_URL.'/images/warning-icon.png" width="50" height="44" style="float:left; padding:10px;"/>
  947. <p>'
  948. . sprintf( __('You are about to delete all custom field definitions for the %s post type. This will not delete any data from the wp_postmeta table, but it will make any custom fields invisible to WordPress users on the front and back end.', CCTM_TXTDOMAIN), "<em>$post_type</em>" )
  949. .'</p>'
  950. . '<p>'.__('Are you sure you want to do this?', CCTM_TXTDOMAIN).'</p></div>';
  951. // The URL nec. to take the "Cancel" button back to this page.
  952. $cancel_target_url = '?page='.self::admin_menu_slug . '&'.self::action_param .'=4&'.self::post_type_param.'='.$post_type;
  953. include 'pages/basic_form.php';
  954. }
  955. //------------------------------------------------------------------------------
  956. /**
  957. * Manager Page -- called by page_main_controller()
  958. * List all post types (default page)
  959. */
  960. private static function _page_show_all_post_types() {
  961. $msg = self::get_flash();
  962. $customized_post_types = array();
  963. $displayable_types = array();
  964. $displayable_types = array();
  965. if ( !empty(self::$data) ) {
  966. $customized_post_types = array_keys(self::$data);
  967. }
  968. $displayable_types = array_merge(self::$built_in_post_types , $customized_post_types);
  969. $displayable_types = array_unique($displayable_types);
  970. $row_data = '';
  971. $tpl = file_get_contents(CCTM_PATH.'/tpls/settings/post_type_tr.tpl');
  972. foreach ( $displayable_types as $post_type ) {
  973. $hash = array(); // populated for the tpl
  974. $hash['post_type'] = $post_type;
  975. // Get our links
  976. $deactivate = self::_link_deactivate($post_type);
  977. $edit_link = self::_link_edit($post_type);
  978. $manage_custom_fields = self::_link_manage_custom_fields($post_type);
  979. $view_templates = self::_link_view_sample_templates($post_type);
  980. $hash['edit_manage_view_links'] = $edit_link . ' | '. $manage_custom_fields . ' | ' . $view_templates;
  981. if ( isset(self::$data[$post_type]['is_active']) && !empty(self::$data[$post_type]['is_active']) ) {
  982. $hash['class'] = 'active';
  983. $hash['activate_deactivate_delete_links'] = '<span class="deactivate">'.$deactivate.'</span>';
  984. $is_active = true;
  985. }
  986. else {
  987. $hash['class'] = 'inactive';
  988. $hash['activate_deactivate_delete_links'] = '<span class="activate">'
  989. . self::_link_activate($post_type) . ' | </span>'
  990. . '<span class="delete">'. self::_link_delete($post_type).'</span>';
  991. $is_active = false;
  992. }
  993. // Built-in post types use a canned description and override a few other behaviors
  994. if ( in_array($post_type, self::$built_in_post_types) ) {
  995. $hash['description'] = __('Built-in post type.', CCTM_TXTDOMAIN);
  996. $hash['edit_manage_view_links'] = $manage_custom_fields . ' | ' . $view_templates;
  997. if (!$is_active) {
  998. $hash['activate_deactivate_delete_links'] = '<span class="activate">'
  999. . self::_link_activate($post_type) . '</span>';
  1000. }
  1001. }
  1002. // Whereas users define the description for custom post types
  1003. else {
  1004. $hash['description'] = self::_get_value(self::$data[$post_type], 'description');
  1005. }
  1006. // Images
  1007. $hash['icon'] = '';
  1008. switch ($post_type) {
  1009. case 'post':
  1010. $hash['icon'] = '<img src="'. CCTM_URL . '/images/icons/default/post.png' . '" width="15" height="15"/>';
  1011. break;
  1012. case 'page':
  1013. $hash['icon'] = '<img src="'. CCTM_URL . '/images/icons/default/page.png' . '" width="14" height="16"/>';
  1014. break;
  1015. default:
  1016. //print_r($data[$post_type]); exit;
  1017. if ( !empty(self::$data[$post_type]['menu_icon']) && !self::$data[$post_type]['use_default_menu_icon'] ) {
  1018. $hash['icon'] = '<img src="'. self::$data[$post_type]['menu_icon'] . '" />';
  1019. }
  1020. break;
  1021. }
  1022. $row_data .= FormGenerator::parse($tpl, $hash);
  1023. }
  1024. include 'pages/default.php';
  1025. }
  1026. //------------------------------------------------------------------------------
  1027. /**
  1028. * Manager Page -- called by page_main_controller()
  1029. * Show what a single page for this custom post-type might look like. This is
  1030. * me throwing a bone to template editors and creators.
  1031. *
  1032. * I'm using a tpl and my parse() function because I have to print out sample PHP
  1033. * code and it's too much of a pain in the ass to include PHP without it executing.
  1034. *
  1035. * @param string $post_type
  1036. */
  1037. private static function _page_sample_template($post_type) {
  1038. // Validate post type
  1039. if (!self::_is_existing_post_type($post_type) ) {
  1040. self::_page_display_error();
  1041. return;
  1042. }
  1043. $current_theme_name = get_current_theme();
  1044. $current_theme_path = get_stylesheet_directory();
  1045. $hash = array();
  1046. $tpl = file_get_contents( CCTM_PATH.'/tpls/samples/single_post.tpl');
  1047. $tpl = htmlentities($tpl);
  1048. $single_page_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)
  1049. , 'single-'.$post_type.'.php'
  1050. );
  1051. $single_page_msg .= sprintf( __('You are currently using the %1$s theme. Save the file into the %2$s directory.', CCTM_TXTDOMAIN)
  1052. , '<strong>'.$current_theme_name.'</strong>'
  1053. , '<strong>'.$current_theme_path.'</strong>'
  1054. );
  1055. $def = array();
  1056. if ( isset(self::$data[$post_type]['custom_fields']) ) {
  1057. $def = self::$data[$post_type]['custom_fields'];
  1058. }
  1059. //print_r($data[$post_type]); exit;
  1060. // built-in content types don't verbosely display what they display
  1061. /* Array
  1062. (
  1063. [product] => Array
  1064. (
  1065. [supports] => Array
  1066. (
  1067. [0] => title
  1068. [1] => editor
  1069. [2] => author
  1070. [3] => thumbnail
  1071. [4] => excerpt
  1072. [5] => trackbacks
  1073. [6] => custom-fields
  1074. )
  1075. */
  1076. // print_r($data); exit;
  1077. // Check the TYPE of custom field to handle image and relation custom fields.
  1078. // title, author, thumbnail, excerpt
  1079. $custom_fields_str = '';
  1080. $builtin_fields_str = '';
  1081. $comments_str = '';
  1082. // Built-in Fields
  1083. if ( is_array(self::$data[$post_type]['supports']) ) {
  1084. if ( in_array('title', self::$data[$post_type]['supports']) ) {
  1085. $builtin_fields_str .= "\n\t<h1><?php the_title(); ?></h1>\n";
  1086. }
  1087. if ( in_array('editor', self::$data[$post_type]['supports']) ) {
  1088. $builtin_fields_str .= "\n\t\t<?php the_content(); ?>\n";
  1089. }
  1090. if ( in_array('author', self::$data[$post_type]['supports']) ) {
  1091. $builtin_fields_str .= "\n\t\t<?php the_author(); ?>\n";
  1092. }
  1093. if ( in_array('thumbnail', self::$data[$post_type]['supports']) ) {
  1094. $builtin_fields_str .= "\n\t\t<?php the_post_thumbnail(); ?>\n";
  1095. }
  1096. if ( in_array('excerpt', self::$data[$post_type]['supports']) ) {
  1097. $builtin_fields_str .= "\n\t\t<?php the_excerpt(); ?>\n";
  1098. }
  1099. if ( in_array('comments', self::$data[$post_type]['supports']) ) {
  1100. $comments_str .= "\n\t\t<?php comments_template(); ?>\n";
  1101. }
  1102. }
  1103. // Custom fields
  1104. foreach ( $def as $d ) {
  1105. switch ($d['type']) {
  1106. case 'media':
  1107. $custom_fields_str .= "\t\t<?php /* http://codex.wordpress.org/Function_Reference/wp_get_attachment_image */ ?>\n";
  1108. $custom_fields_str .= sprintf("\t\t<strong>%s:</strong> <?php print wp_get_attachment_image( get_custom_field('%s'), 'full'); ?><br />\n", $d['label'], $d['name']);
  1109. case 'text':
  1110. default:
  1111. $custom_fields_str .= sprintf("\t\t<strong>%s:</strong> <?php print_custom_field('%s'); ?><br />\n", $d['label'], $d['name']);
  1112. }
  1113. }
  1114. // Populate placeholders
  1115. $hash['post_type'] = $post_type;
  1116. $hash['built_in_fields'] = $builtin_fields_str;
  1117. $hash['custom_fields'] = $custom_fields_str;
  1118. $hash['comments'] = $comments_str;
  1119. $single_page_sample_code = StandardizedCustomFields::parse($tpl, $hash);
  1120. // Manager Page Sample CSS
  1121. $manager_page_css_msg = '';
  1122. $manager_page_sample_css = '';
  1123. $manager_page_css_msg .= sprintf( __('You can customize the forms in the manager by adding the following CSS declarations to your in your theme\'s %s file.', CCTM_TXTDOMAIN)
  1124. , '<strong>editor-style.css</strong>' );
  1125. $manager_page_css_msg .= sprintf( __('You can override the style definitions in %s', CCTM_TXTDOMAIN)
  1126. , '<strong>'.CCTM_PATH.'/css/posts.css</strong>');
  1127. // or in your theme's editor-style.css file.
  1128. // FormGenerator::element_wrapper_id_prefix
  1129. foreach ( $def as $d ) {
  1130. $manager_page_sample_css .= sprintf("/* The div that wraps the %s field */\n#%s%s {\n\n}\n\n/* Style the input for the %s field */\n#%s%s {\n\n}\n\n"
  1131. , $d['name']
  1132. , FormGenerator::element_wrapper_id_prefix
  1133. , $d['name']
  1134. , $d['name']
  1135. , StandardizedCustomFields::field_name_prefix
  1136. , $d['name']
  1137. );
  1138. }
  1139. // Manager Page HTML examples;
  1140. // post-new.php?post_type=%s
  1141. $manager_page_html_msg = '';
  1142. $manager_page_sample_html = '';
  1143. /*
  1144. <div class="formgenerator_element_wrapper" id="custom_field_id_sample_img">
  1145. <span class="formgenerator_label formgenerator_media_label" id="formgenerator_label_custom_content_sample_img">Sample Image (sample_img)</span>
  1146. <input type="hidden" id="custom_content_sample_img" name="custom_content_sample_img" />
  1147. </div>
  1148. A <div> wraps each custom field. Its class is "formgenerator_element_wrapper" and its id is the field name prefixed by "custom_field_id_"
  1149. Labels for each field are wrapped with their own <span>. Each <span> uses 2 classes: a general one for all generated labels, and another specific to the field type (text, checkbox, etc).
  1150. */
  1151. $manager_page_html_msg .= __('You can create custom manager templates for the users who will be creating new content.', CCTM_TXTDOMAIN) . ' ';
  1152. $manager_page_html_msg .= sprintf( __('Create a file named %s in the %s directory.', CCTM_TXTDOMAIN)
  1153. , '<strong>'.$post_type.'.tpl</strong>'
  1154. , '<strong>'.CCTM_PATH.'/tpls/manager/</strong>'
  1155. );
  1156. foreach ( $def as $d ) {
  1157. unset($d['default_value']); // this should not be publicly available.
  1158. $manager_page_sample_html .= sprintf( "<!-- Sample HTML for %s field-->\n", $d['name']);
  1159. $manager_page_sample_html .= "<!-- [+".$d['name']."+] will generate field in its entirety -->\n";
  1160. $manager_page_sample_html .= "<!-- Individual placeholders follow: -->\n";
  1161. foreach ($d as $k => $v) {
  1162. $manager_page_sample_html .= '[+'.$d['name'].'.'.$k.'+]'. "\n";
  1163. }
  1164. $manager_page_sample_html .= "\n";
  1165. //! FUTURE: TODO: Give more complete examples.
  1166. /*
  1167. switch ( $d['type'] )
  1168. {
  1169. case 'checkbox':
  1170. $output_this_field .= self::_get_checkbox_element($field_def);
  1171. break;
  1172. case 'dropdown':
  1173. $output_this_field .= self::_get_dropdown_element($field_def);
  1174. break;
  1175. case 'media':
  1176. $output_this_field .= self::_get_media_element($field_def);
  1177. break;
  1178. case 'readonly':
  1179. $output_this_field .= self::_get_readonly_element($field_def);
  1180. break;
  1181. case 'relation':
  1182. $output_this_field .= self::_get_relation_element($field_def);
  1183. break;
  1184. case 'textarea':
  1185. $output_this_field .= self::_get_textarea_element($field_def);
  1186. break;
  1187. case 'wysiwyg':
  1188. $output_this_field .= self::_get_wysiwyg_element($field_def);
  1189. break;
  1190. case 'text':
  1191. default:
  1192. $output_this_field .= self::_get_text_element($field_def);
  1193. break;
  1194. }
  1195. */
  1196. }
  1197. if ( empty($def) ) {
  1198. $manager_page_sample_css = sprintf( '/* %s %s */'
  1199. , __('There are no custom fields defined this post type.', CCTM_TXTDOMAIN)
  1200. , "($post_type)"
  1201. );
  1202. $manager_page_sample_html = sprintf( '<!-- %s %s -->'
  1203. , __('There are no custom fields defined this post type.', CCTM_TXTDOMAIN)
  1204. , "($post_type)"
  1205. );
  1206. }
  1207. include 'pages/sample_template.php';
  1208. }
  1209. //------------------------------------------------------------------------------
  1210. /**
  1211. * Manager Page -- called by page_main_controller()
  1212. * Manage custom fields for any post type, built-in or custom.
  1213. * @param string $post_type
  1214. * @param boolen $reset true only if we've just reset all custom fields
  1215. */
  1216. private static function _page_show_custom_fields($post_type, $reset=false) {
  1217. // Validate post type
  1218. if (!self::_is_existing_post_type($post_type) ) {
  1219. self::_page_display_error();

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