[ Index ]

PHP Cross Reference of BBPress

title

Body

[close]

/src/includes/admin/classes/ -> class-bbp-converter-base.php (source)

   1  <?php
   2  
   3  /**
   4   * bbPress Converter Base Class
   5   *
   6   * Based on the hard work of Adam Ellis
   7   *
   8   * @package bbPress
   9   * @subpackage Administration
  10   */
  11  
  12  // Exit if accessed directly
  13  defined( 'ABSPATH' ) || exit;
  14  
  15  if ( ! class_exists( 'BBP_Converter_Base' ) ) :
  16  /**
  17   * Base class to be extended by specific individual importers
  18   *
  19   * @since 2.1.0 bbPress (r3813)
  20   */
  21  abstract class BBP_Converter_Base {
  22  
  23      /**
  24       * @var array() This is the field mapping array to process.
  25       */
  26      protected $field_map = array();
  27  
  28      /**
  29       * @var object This is the connection to the WordPress database.
  30       */
  31      protected $wpdb;
  32  
  33      /**
  34       * @var object This is the connection to the other platforms database.
  35       */
  36      protected $opdb;
  37  
  38      /**
  39       * @var int Maximum number of rows to convert at 1 time. Default 100.
  40       */
  41      protected $max_rows = 100;
  42  
  43      /**
  44       * @var array() Map of topic to forum.  It is for optimization.
  45       */
  46      protected $map_topicid_to_forumid = array();
  47  
  48      /**
  49       * @var array() Map of from old forum ids to new forum ids.  It is for optimization.
  50       */
  51      protected $map_forumid = array();
  52  
  53      /**
  54       * @var array() Map of from old topic ids to new topic ids.  It is for optimization.
  55       */
  56      protected $map_topicid = array();
  57  
  58      /**
  59       * @var array() Map of from old reply_to ids to new reply_to ids.  It is for optimization.
  60       */
  61      protected $map_reply_to = array();
  62  
  63      /**
  64       * @var array() Map of from old user ids to new user ids.  It is for optimization.
  65       */
  66      protected $map_userid = array();
  67  
  68      /**
  69       * @var str This is the charset for your wp database.
  70       */
  71      public $charset = '';
  72  
  73      /**
  74       * @var boolean Sync table available.
  75       */
  76      public $sync_table = false;
  77  
  78      /**
  79       * @var str Sync table name.
  80       */
  81      public $sync_table_name = '';
  82  
  83      /**
  84       * @var bool Whether users should be converted or not. Default false.
  85       */
  86      public $convert_users = false;
  87  
  88      /**
  89       * @var bool Whether to clean up any old converter data. Default false.
  90       */
  91      public $clean = false;
  92  
  93      /**
  94       * @var array Custom BBCode class properties in a key => value format
  95       */
  96      public $bbcode_parser_properties = array();
  97  
  98      /** Methods ***************************************************************/
  99  
 100      /**
 101       * This is the constructor and it connects to the platform databases.
 102       */
 103  	public function __construct() {
 104          $this->init();
 105          $this->setup_globals();
 106      }
 107  
 108      /**
 109       * Initialize the converter
 110       *
 111       * @since 2.1.0
 112       */
 113  	private function init() {
 114  
 115          /** BBCode Parse Properties *******************************************/
 116  
 117          // Setup smiley URL & path
 118          $this->bbcode_parser_properties = array(
 119              'smiley_url' => includes_url( 'images/smilies' ),
 120              'smiley_dir' => '/' . WPINC . '/images/smilies'
 121          );
 122  
 123          /** Sanitize Options **************************************************/
 124  
 125          $this->clean         = ! empty( $_POST['_bbp_converter_clean'] );
 126          $this->convert_users = (bool) get_option( '_bbp_converter_convert_users', false );
 127          $this->halt          = (bool) get_option( '_bbp_converter_halt',          0     );
 128          $this->max_rows      = (int)  get_option( '_bbp_converter_rows',          100   );
 129  
 130          /** Sanitize Connection ***********************************************/
 131  
 132          $db_user   = get_option( '_bbp_converter_db_user',   DB_USER     );
 133          $db_pass   = get_option( '_bbp_converter_db_pass',   DB_PASSWORD );
 134          $db_name   = get_option( '_bbp_converter_db_name',   DB_NAME     );
 135          $db_host   = get_option( '_bbp_converter_db_server', DB_HOST     );
 136          $db_port   = get_option( '_bbp_converter_db_port',   ''          );
 137          $db_prefix = get_option( '_bbp_converter_db_prefix', ''          );
 138  
 139          // Maybe add port to server
 140          if ( ! empty( $db_port ) && ! empty( $db_host ) && ! strstr( $db_host, ':' ) ) {
 141              $db_host = "{$db_host}:{$db_port}";
 142          }
 143  
 144          /** Get database connections ******************************************/
 145  
 146          // Setup WordPress Database
 147          $this->wpdb = bbp_db();
 148  
 149          // Setup old forum Database
 150          $this->opdb = new BBP_Converter_DB( $db_user, $db_pass, $db_name, $db_host );
 151  
 152          // Connection failed
 153          if ( ! $this->opdb->db_connect( false ) ) {
 154              $error = new WP_Error( 'bbp_converter_db_connection_failed', esc_html__( 'Database connection failed.', 'bbpress' ) );
 155              wp_send_json_error( $error );
 156          }
 157  
 158          // Maybe setup the database prefix
 159          $this->opdb->prefix = $db_prefix;
 160  
 161          /**
 162           * Don't wp_die() uncontrollably
 163           */
 164          $this->wpdb->show_errors( false );
 165          $this->opdb->show_errors( false );
 166  
 167          /**
 168           * Syncing
 169           */
 170          $this->sync_table_name = $this->wpdb->prefix . 'bbp_converter_translator';
 171          $this->sync_table      = $this->sync_table_name === $this->wpdb->get_var( "SHOW TABLES LIKE '{$this->sync_table_name}'" )
 172              ? true
 173              : false;
 174  
 175          /**
 176           * Character set
 177           */
 178          $this->charset = ! empty( $this->wpdb->charset )
 179              ? $this->wpdb->charset
 180              : 'UTF8';
 181  
 182          /**
 183           * Default mapping.
 184           */
 185  
 186          /** Forum Section *****************************************************/
 187  
 188          $this->field_map[] = array(
 189              'to_type'      => 'forum',
 190              'to_fieldname' => 'post_status',
 191              'default'      => 'publish'
 192          );
 193          $this->field_map[] = array(
 194              'to_type'      => 'forum',
 195              'to_fieldname' => 'comment_status',
 196              'default'      => 'closed'
 197          );
 198          $this->field_map[] = array(
 199              'to_type'      => 'forum',
 200              'to_fieldname' => 'ping_status',
 201              'default'      => 'closed'
 202          );
 203          $this->field_map[] = array(
 204              'to_type'      => 'forum',
 205              'to_fieldname' => 'post_type',
 206              'default'      => 'forum'
 207          );
 208  
 209          /** Topic Section *****************************************************/
 210  
 211          $this->field_map[] = array(
 212              'to_type'      => 'topic',
 213              'to_fieldname' => 'post_status',
 214              'default'      => 'publish'
 215          );
 216          $this->field_map[] = array(
 217              'to_type'      => 'topic',
 218              'to_fieldname' => 'comment_status',
 219              'default'      => 'closed'
 220          );
 221          $this->field_map[] = array(
 222              'to_type'      => 'topic',
 223              'to_fieldname' => 'ping_status',
 224              'default'      => 'closed'
 225          );
 226          $this->field_map[] = array(
 227              'to_type'      => 'topic',
 228              'to_fieldname' => 'post_type',
 229              'default'      => 'topic'
 230          );
 231  
 232          /** Post Section ******************************************************/
 233  
 234          $this->field_map[] = array(
 235              'to_type'      => 'reply',
 236              'to_fieldname' => 'post_status',
 237              'default'      => 'publish'
 238          );
 239          $this->field_map[] = array(
 240              'to_type'      => 'reply',
 241              'to_fieldname' => 'comment_status',
 242              'default'      => 'closed'
 243          );
 244          $this->field_map[] = array(
 245              'to_type'      => 'reply',
 246              'to_fieldname' => 'ping_status',
 247              'default'      => 'closed'
 248          );
 249          $this->field_map[] = array(
 250              'to_type'      => 'reply',
 251              'to_fieldname' => 'post_type',
 252              'default'      => 'reply'
 253          );
 254  
 255          /** User Section ******************************************************/
 256  
 257          $this->field_map[] = array(
 258              'to_type'      => 'user',
 259              'to_fieldname' => 'role',
 260              'default'      => get_option( 'default_role' )
 261          );
 262      }
 263  
 264      /**
 265       * Setup global values
 266       */
 267  	public function setup_globals() {}
 268  
 269      /**
 270       * Convert Forums
 271       */
 272  	public function convert_forums( $start = 1 ) {
 273          return $this->convert_table( 'forum', $start );
 274      }
 275  
 276      /**
 277       * Convert Topics / Threads
 278       */
 279  	public function convert_topics( $start = 1 ) {
 280          return $this->convert_table( 'topic', $start );
 281      }
 282  
 283      /**
 284       * Convert Posts
 285       */
 286  	public function convert_replies( $start = 1 ) {
 287          return $this->convert_table( 'reply', $start );
 288      }
 289  
 290      /**
 291       * Convert Users
 292       */
 293  	public function convert_users( $start = 1 ) {
 294          return $this->convert_table( 'user', $start );
 295      }
 296  
 297      /**
 298       * Convert Topic Tags
 299       */
 300  	public function convert_tags( $start = 1 ) {
 301          return $this->convert_table( 'tags', $start );
 302      }
 303  
 304      /**
 305       * Convert Forum Subscriptions
 306       */
 307  	public function convert_forum_subscriptions( $start = 1 ) {
 308          return $this->convert_table( 'forum_subscriptions', $start );
 309      }
 310  
 311      /**
 312       * Convert Topic Subscriptions
 313       */
 314  	public function convert_topic_subscriptions( $start = 1 ) {
 315          return $this->convert_table( 'topic_subscriptions', $start );
 316      }
 317  
 318      /**
 319       * Convert Favorites
 320       */
 321  	public function convert_favorites( $start = 1 ) {
 322          return $this->convert_table( 'favorites', $start );
 323      }
 324  
 325      /**
 326       * Convert Table
 327       *
 328       * @param string to type
 329       * @param int Start row
 330       */
 331  	public function convert_table( $to_type, $start ) {
 332  
 333          // Set some defaults
 334          $has_insert     = false;
 335          $from_tablename = '';
 336          $field_list     = $from_tables = $tablefield_array = array();
 337  
 338          // Toggle Table Name based on $to_type (destination)
 339          switch ( $to_type ) {
 340              case 'user' :
 341                  $tablename = $this->wpdb->users;
 342                  break;
 343  
 344              case 'tags' :
 345                  $tablename = '';
 346                  break;
 347  
 348              case 'forum_subscriptions' :
 349                  $tablename = $this->wpdb->postmeta;
 350                  break;
 351  
 352              case 'topic_subscriptions' :
 353                  $tablename = $this->wpdb->postmeta;
 354                  break;
 355  
 356              case 'favorites' :
 357                  $tablename = $this->wpdb->postmeta;
 358                  break;
 359  
 360              default :
 361                  $tablename = $this->wpdb->posts;
 362          }
 363  
 364          // Get the fields from the destination table
 365          if ( ! empty( $tablename ) ) {
 366              $tablefield_array = $this->get_fields( $tablename );
 367          }
 368  
 369          /** Step 1 ************************************************************/
 370  
 371          // Loop through the field maps, and look for to_type matches
 372          foreach ( $this->field_map as $item ) {
 373  
 374              // Yay a match, and we have a from table, too
 375              if ( ( $item['to_type'] === $to_type ) && ! empty( $item['from_tablename'] ) ) {
 376  
 377                  // $from_tablename was set from a previous loop iteration
 378                  if ( ! empty( $from_tablename ) ) {
 379  
 380                      // Doing some joining
 381                      if ( ! in_array( $item['from_tablename'], $from_tables, true ) && in_array( $item['join_tablename'], $from_tables, true ) ) {
 382                          $from_tablename .= ' ' . $item['join_type'] . ' JOIN ' . $this->opdb->prefix . $item['from_tablename'] . ' AS ' . $item['from_tablename'] . ' ' . $item['join_expression'];
 383                      }
 384  
 385                  // $from_tablename needs to be set
 386                  } else {
 387                      $from_tablename = $item['from_tablename'] . ' AS ' . $item['from_tablename'];
 388                  }
 389  
 390                  // Specific FROM expression data used
 391                  if ( ! empty( $item['from_expression'] ) ) {
 392  
 393                      // No 'WHERE' in expression
 394                      if ( stripos( $from_tablename, "WHERE" ) === false ) {
 395                          $from_tablename .= ' ' . $item['from_expression'];
 396  
 397                      // 'WHERE' in expression, so replace with 'AND'
 398                      } else {
 399                          $from_tablename .= ' ' . str_replace( "WHERE", "AND", $item['from_expression'] );
 400                      }
 401                  }
 402  
 403                  // Add tablename and fieldname to arrays, formatted for querying
 404                  $from_tables[] = $item['from_tablename'];
 405                  $field_list[]  = 'convert(' . $item['from_tablename'] . '.' . $item['from_fieldname'] . ' USING "' . $this->charset . '") AS ' . $item['from_fieldname'];
 406              }
 407          }
 408  
 409          /** Step 2 ************************************************************/
 410  
 411          // We have a $from_tablename, so we want to get some data to convert
 412          if ( ! empty( $from_tablename ) ) {
 413  
 414              // Update rows
 415              $this->count_rows_by_table( "{$this->opdb->prefix}{$from_tablename}" );
 416  
 417              // Get some data from the old forums
 418              $field_list  = array_unique( $field_list );
 419              $fields      = implode( ',', $field_list );
 420              $forum_query = "SELECT {$fields} FROM {$this->opdb->prefix}{$from_tablename} LIMIT {$start}, {$this->max_rows}";
 421  
 422              // Set this query as the last one ran
 423              $this->update_query( $forum_query );
 424  
 425              // Get results as an array
 426              $forum_array = $this->opdb->get_results( $forum_query, ARRAY_A );
 427  
 428              // Query returned some results
 429              if ( ! empty( $forum_array ) ) {
 430  
 431                  // Loop through results
 432                  foreach ( (array) $forum_array as $forum ) {
 433  
 434                      // Reset some defaults
 435                      $insert_post = $insert_postmeta = $insert_data = array();
 436  
 437                      // Loop through field map, again...
 438                      foreach ( $this->field_map as $row ) {
 439  
 440                          // Types match and to_fieldname is present. This means
 441                          // we have some work to do here.
 442                          if ( ( $row['to_type'] === $to_type ) && isset( $row['to_fieldname'] ) ) {
 443  
 444                              // This row has a destination that matches one of the
 445                              // columns in this table.
 446                              if ( in_array( $row['to_fieldname'], $tablefield_array, true ) ) {
 447  
 448                                  // Allows us to set default fields.
 449                                  if ( isset( $row['default'] ) ) {
 450                                      $insert_post[ $row['to_fieldname'] ] = $row['default'];
 451  
 452                                  // Translates a field from the old forum.
 453                                  } elseif ( isset( $row['callback_method'] ) ) {
 454                                      if ( ( 'callback_userid' === $row['callback_method'] ) && ( false === $this->convert_users ) ) {
 455                                          $insert_post[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
 456                                      } else {
 457                                          $insert_post[ $row['to_fieldname'] ] = call_user_func_array( array( $this, $row['callback_method'] ), array( $forum[ $row['from_fieldname'] ], $forum ) );
 458                                      }
 459  
 460                                  // Maps the field from the old forum.
 461                                  } else {
 462                                      $insert_post[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
 463                                  }
 464  
 465                              // Destination field is not empty, so we might need
 466                              // to do some extra work or set a default.
 467                              } elseif ( ! empty( $row['to_fieldname'] ) ) {
 468  
 469                                  // Allows us to set default fields.
 470                                  if ( isset( $row['default'] ) ) {
 471                                      $insert_postmeta[ $row['to_fieldname'] ] = $row['default'];
 472  
 473                                  // Translates a field from the old forum.
 474                                  } elseif ( isset( $row['callback_method'] ) ) {
 475                                      if ( ( $row['callback_method'] === 'callback_userid' ) && ( false === $this->convert_users ) ) {
 476                                          $insert_postmeta[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
 477                                      } else {
 478                                          $insert_postmeta[ $row['to_fieldname'] ] = call_user_func_array( array( $this, $row['callback_method'] ), array( $forum[ $row['from_fieldname'] ], $forum ) );
 479                                      }
 480  
 481                                  // Maps the field from the old forum.
 482                                  } else {
 483                                      $insert_postmeta[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
 484                                  }
 485                              }
 486                          }
 487                      }
 488  
 489                      /** Step 3 ************************************************/
 490  
 491                      // Something to insert into the destination field
 492                      if ( count( $insert_post ) > 0 || ( $to_type == 'tags' && count( $insert_postmeta ) > 0 ) ) {
 493  
 494                          switch ( $to_type ) {
 495  
 496                              /** New user **************************************/
 497  
 498                              case 'user' :
 499                                  if ( username_exists( $insert_post['user_login'] ) ) {
 500                                      $insert_post['user_login'] = "imported_{$insert_post['user_login']}";
 501                                  }
 502  
 503                                  if ( email_exists( $insert_post['user_email'] ) ) {
 504                                      $insert_post['user_email'] = "imported_{$insert_post['user_email']}";
 505                                  }
 506  
 507                                  if ( empty( $insert_post['user_pass'] ) ) {
 508                                      $insert_post['user_pass'] = '';
 509                                  }
 510  
 511                                  // Internally re-calls _exists() checks above.
 512                                  // Also checks for existing nicename.
 513                                  $post_id = wp_insert_user( $insert_post );
 514  
 515                                  if ( is_numeric( $post_id ) ) {
 516                                      foreach ( $insert_postmeta as $key => $value ) {
 517                                          add_user_meta( $post_id, $key, $value, true );
 518  
 519                                          if ( '_id' == substr( $key, -3 ) && ( true === $this->sync_table ) ) {
 520                                              $this->wpdb->insert( $this->sync_table_name, array(
 521                                                  'value_type' => 'user',
 522                                                  'value_id'   => $post_id,
 523                                                  'meta_key'   => $key,
 524                                                  'meta_value' => $value
 525                                              ) );
 526                                          }
 527                                      }
 528                                  }
 529                                  break;
 530  
 531                              /** New Topic-Tag *********************************/
 532  
 533                              case 'tags' :
 534                                  $post_id = wp_set_object_terms( $insert_postmeta['objectid'], $insert_postmeta['name'], 'topic-tag', true );
 535                                  $term = get_term_by( 'name', $insert_postmeta['name'], 'topic-tag');
 536                                  if ( false !== $term ) {
 537                                      wp_update_term( $term->term_id, 'topic-tag', array(
 538                                          'description' => $insert_postmeta['description'],
 539                                          'slug'        => $insert_postmeta['slug']
 540                                      ) );
 541                                  }
 542                                  break;
 543  
 544                              /** Forum Subscriptions ***************************/
 545  
 546                              case 'forum_subscriptions' :
 547                                  $user_id = $insert_post['user_id'];
 548                                  $items   = wp_list_pluck( $insert_postmeta, '_bbp_forum_subscriptions' );
 549                                  if ( is_numeric( $user_id ) && ! empty( $items ) ) {
 550                                      foreach ( $items as $value ) {
 551  
 552                                          // Maybe string with commas
 553                                          $value = is_string( $value )
 554                                              ? explode( ',', $value )
 555                                              : (array) $value;
 556  
 557                                          // Add user ID to forums subscribed users
 558                                          foreach ( $value as $fav ) {
 559                                              bbp_add_user_subscription( $user_id, $this->callback_forumid( $fav ) );
 560                                          }
 561                                      }
 562                                  }
 563                                  break;
 564  
 565                              /** Subscriptions *********************************/
 566  
 567                              case 'topic_subscriptions' :
 568                                  $user_id = $insert_post['user_id'];
 569                                  $items   = wp_list_pluck( $insert_postmeta, '_bbp_subscriptions' );
 570                                  if ( is_numeric( $user_id ) && ! empty( $items ) ) {
 571                                      foreach ( $items as $value ) {
 572  
 573                                          // Maybe string with commas
 574                                          $value = is_string( $value )
 575                                              ? explode( ',', $value )
 576                                              : (array) $value;
 577  
 578                                          // Add user ID to topics subscribed users
 579                                          foreach ( $value as $fav ) {
 580                                              bbp_add_user_subscription( $user_id, $this->callback_topicid( $fav ) );
 581                                          }
 582                                      }
 583                                  }
 584                                  break;
 585  
 586                              /** Favorites *************************************/
 587  
 588                              case 'favorites' :
 589                                  $user_id = $insert_post['user_id'];
 590                                  $items   = wp_list_pluck( $insert_postmeta, '_bbp_favorites' );
 591                                  if ( is_numeric( $user_id ) && ! empty( $items ) ) {
 592                                      foreach ( $items as $value ) {
 593  
 594                                          // Maybe string with commas
 595                                          $value = is_string( $value )
 596                                              ? explode( ',', $value )
 597                                              : (array) $value;
 598  
 599                                          // Add user ID to topics favorited users
 600                                          foreach ( $value as $fav ) {
 601                                              bbp_add_user_favorite( $user_id, $this->callback_topicid( $fav ) );
 602                                          }
 603                                      }
 604                                  }
 605                                  break;
 606  
 607                              /** Forum, Topic, Reply ***************************/
 608  
 609                              default :
 610                                  $post_id = wp_insert_post( $insert_post, true );
 611  
 612                                  if ( is_numeric( $post_id ) ) {
 613                                      foreach ( $insert_postmeta as $key => $value ) {
 614                                          add_post_meta( $post_id, $key, $value, true );
 615  
 616                                          /**
 617                                           * If we are using the sync_table add
 618                                           * the meta '_id' keys to the table
 619                                           *
 620                                           * Forums:  _bbp_old_forum_id         // The old forum ID
 621                                           *          _bbp_old_forum_parent_id  // The old forum parent ID
 622                                           *
 623                                           * Topics:  _bbp_forum_id             // The new forum ID
 624                                           *          _bbp_old_topic_id         // The old topic ID
 625                                           *          _bbp_old_closed_status_id // The old topic open/closed status
 626                                           *          _bbp_old_sticky_status_id // The old topic sticky status
 627                                           *
 628                                           * Replies: _bbp_forum_id             // The new forum ID
 629                                           *          _bbp_topic_id             // The new topic ID
 630                                           *          _bbp_old_reply_id         // The old reply ID
 631                                           *          _bbp_old_reply_to_id      // The old reply to ID
 632                                           */
 633                                          if ( '_id' === substr( $key, -3 ) && ( true === $this->sync_table ) ) {
 634                                              $this->wpdb->insert( $this->sync_table_name, array(
 635                                                  'value_type' => 'post',
 636                                                  'value_id'   => $post_id,
 637                                                  'meta_key'   => $key,
 638                                                  'meta_value' => $value
 639                                              ) );
 640                                          }
 641  
 642                                          /**
 643                                           * Replies need to save their old reply_to ID for
 644                                           * hierarchical replies association. Later we update
 645                                           * the _bbp_reply_to value with the new bbPress
 646                                           * value using convert_reply_to_parents()
 647                                           */
 648                                          if ( ( 'reply' === $to_type ) && ( '_bbp_old_reply_to_id' === $key ) ) {
 649                                              add_post_meta( $post_id, '_bbp_reply_to', $value );
 650                                          }
 651                                      }
 652                                  }
 653                                  break;
 654                          }
 655                          $has_insert = true;
 656                      }
 657                  }
 658              }
 659          }
 660  
 661          return ! $has_insert;
 662      }
 663  
 664      /**
 665       * This method converts old forum hierarchy to new bbPress hierarchy.
 666       */
 667  	public function convert_forum_parents( $start = 1 ) {
 668          $has_update = false;
 669          $query      = ! empty( $this->sync_table )
 670              ? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}",           '_bbp_old_forum_parent_id' )
 671              : $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}", '_bbp_old_forum_parent_id' );
 672  
 673          foreach ( $this->count_rows_by_results( $query ) as $row ) {
 674              $parent_id = $this->callback_forumid( $row->meta_value );
 675              $this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} SET post_parent = %d WHERE ID = %d LIMIT 1", $parent_id, $row->value_id ) );
 676              $has_update = true;
 677          }
 678  
 679          return ! $has_update;
 680      }
 681  
 682      /**
 683       * This method converts old topic stickies to new bbPress stickies.
 684       *
 685       * @since 2.5.0 bbPress (r5170)
 686       */
 687  	public function convert_topic_stickies( $start = 1 ) {
 688          $has_update = false;
 689          $query      = ! empty( $this->sync_table )
 690              ? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}",           '_bbp_old_sticky_status_id', 'sticky' )
 691              : $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}", '_bbp_old_sticky_status_id', 'sticky' );
 692  
 693          foreach ( $this->count_rows_by_results( $query ) as $row ) {
 694              bbp_stick_topic( $row->value_id );
 695              $has_update = true;
 696          }
 697  
 698          return ! $has_update;
 699      }
 700  
 701      /**
 702       * This method converts old topic super stickies to new bbPress super stickies.
 703       *
 704       * @since 2.5.0 bbPress (r5170)
 705       */
 706  	public function convert_topic_super_stickies( $start = 1 ) {
 707          $has_update = false;
 708          $query      = ! empty( $this->sync_table )
 709              ? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}",           '_bbp_old_sticky_status_id', 'super-sticky' )
 710              : $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}", '_bbp_old_sticky_status_id', 'super-sticky' );
 711  
 712          foreach ( $this->count_rows_by_results( $query ) as $row ) {
 713              $super = true;
 714              bbp_stick_topic( $row->value_id, $super );
 715              $has_update = true;
 716          }
 717  
 718          return ! $has_update;
 719      }
 720  
 721      /**
 722       * This method converts old closed topics to bbPress closed topics.
 723       *
 724       * @since 2.6.0 bbPress (r5425)
 725       */
 726  	public function convert_topic_closed_topics( $start = 1 ) {
 727          $has_update = false;
 728          $query      = ! empty( $this->sync_table )
 729              ? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}",           '_bbp_old_closed_status_id', 'closed' )
 730              : $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}", '_bbp_old_closed_status_id', 'closed' );
 731  
 732          foreach ( $this->count_rows_by_results( $query ) as $row ) {
 733              bbp_close_topic( $row->value_id );
 734              $has_update = true;
 735          }
 736  
 737          return ! $has_update;
 738      }
 739  
 740      /**
 741       * This method converts old reply_to post id to new bbPress reply_to post id.
 742       *
 743       * @since 2.4.0 bbPress (r5093)
 744       */
 745  	public function convert_reply_to_parents( $start = 1 ) {
 746          $has_update = false;
 747          $query      = ! empty( $this->sync_table )
 748              ? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}",           '_bbp_old_reply_to_id' )
 749              : $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}", '_bbp_old_reply_to_id' );
 750  
 751          foreach ( $this->count_rows_by_results( $query ) as $row ) {
 752              $reply_to = $this->callback_reply_to( $row->meta_value );
 753              $this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->postmeta} SET meta_value = %s WHERE meta_key = %s AND post_id = %d LIMIT 1", $reply_to, '_bbp_reply_to', $row->value_id ) );
 754              $has_update = true;
 755          }
 756  
 757          return ! $has_update;
 758      }
 759  
 760      /**
 761       * This method converts anonymous topics.
 762       *
 763       * @since 2.6.0 bbPress (r5538)
 764       */
 765  	public function convert_anonymous_topic_authors( $start = 1 ) {
 766  
 767          $has_update = false;
 768  
 769          if ( ! empty( $this->sync_table ) ) {
 770              $query = $this->wpdb->prepare( "SELECT sync_table1.value_id AS topic_id, sync_table1.meta_value AS topic_is_anonymous, sync_table2.meta_value AS topic_author
 771                  FROM {$this->sync_table_name} AS sync_table1
 772                  INNER JOIN {$this->sync_table_name} AS sync_table2
 773                  ON ( sync_table1.value_id = sync_table2.value_id )
 774                  WHERE sync_table1.meta_value = %s
 775                  AND sync_table2.meta_key = %s
 776                  LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_topic_author_name_id' );
 777          } else {
 778              $query = $this->wpdb->prepare( "SELECT wp_postmeta1.post_id AS topic_id, wp_postmeta1.meta_value AS topic_is_anonymous, wp_postmeta2.meta_value AS topic_author
 779                  FROM {$this->wpdb->postmeta} AS wp_postmeta1
 780                  INNER JOIN {$this->wpdb->postmeta} AS wp_postmeta2
 781                  ON ( wp_postmeta1.post_id = wp_postmeta2.post_id )
 782                  WHERE wp_postmeta1.meta_value = %s
 783                  AND wp_postmeta2.meta_key = %s
 784                  LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_topic_author_name_id' );
 785          }
 786  
 787          foreach ( $this->count_rows_by_results( $query ) as $row ) {
 788              $anonymous_topic_author_id = 0;
 789              $this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} SET post_author = %d WHERE ID = %d LIMIT 1", $anonymous_topic_author_id, $row->topic_id ) );
 790  
 791              add_post_meta( $row->topic_id, '_bbp_anonymous_name', $row->topic_author );
 792  
 793              $has_update = true;
 794          }
 795  
 796          return ! $has_update;
 797      }
 798  
 799      /**
 800       * This method converts anonymous replies.
 801       *
 802       * @since 2.6.0 bbPress (r5538)
 803       */
 804  	public function convert_anonymous_reply_authors( $start = 1 ) {
 805  
 806          $has_update = false;
 807  
 808          if ( ! empty( $this->sync_table ) ) {
 809              $query = $this->wpdb->prepare( "SELECT sync_table1.value_id AS reply_id, sync_table1.meta_value AS reply_is_anonymous, sync_table2.meta_value AS reply_author
 810                  FROM {$this->sync_table_name} AS sync_table1
 811                  INNER JOIN {$this->sync_table_name} AS sync_table2
 812                  ON ( sync_table1.value_id = sync_table2.value_id )
 813                  WHERE sync_table1.meta_value = %s
 814                  AND sync_table2.meta_key = %s
 815                  LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_reply_author_name_id' );
 816          } else {
 817              $query = $this->wpdb->prepare( "SELECT wp_postmeta1.post_id AS reply_id, wp_postmeta1.meta_value AS reply_is_anonymous, wp_postmeta2.meta_value AS reply_author
 818                  FROM {$this->wpdb->postmeta} AS wp_postmeta1
 819                  INNER JOIN {$this->wpdb->postmeta} AS wp_postmeta2
 820                  ON ( wp_postmeta1.post_id = wp_postmeta2.post_id )
 821                  WHERE wp_postmeta1.meta_value = %s
 822                  AND wp_postmeta2.meta_key = %s
 823                  LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_reply_author_name_id' );
 824          }
 825  
 826          foreach ( $this->count_rows_by_results( $query ) as $row ) {
 827              $anonymous_reply_author_id = 0;
 828              $this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} SET post_author = %d WHERE ID = %d LIMIT 1", $anonymous_reply_author_id, $row->reply_id ) );
 829  
 830              add_post_meta( $row->reply_id, '_bbp_anonymous_name', $row->reply_author );
 831  
 832              $has_update = true;
 833          }
 834  
 835          return ! $has_update;
 836      }
 837  
 838      /**
 839       * This method deletes data from the wp database.
 840       *
 841       * @since 2.6.0 bbPress (r6456)
 842       */
 843  	public function clean() {
 844  
 845          // Defaults
 846          $has_delete = false;
 847  
 848          /** Delete topics/forums/posts ****************************************/
 849  
 850          $esc_like = $this->wpdb->esc_like( '_bbp_' ) . '%';
 851          $query    = ! empty( $this->sync_table )
 852              ? $this->wpdb->prepare( "SELECT value_id FROM {$this->sync_table_name} INNER JOIN {$this->wpdb->posts} ON(value_id = ID) WHERE meta_key LIKE %s AND value_type = %s GROUP BY value_id ORDER BY value_id DESC LIMIT {$this->max_rows}", $esc_like, 'post' )
 853              : $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key LIKE %s GROUP BY post_id ORDER BY post_id DESC LIMIT {$this->max_rows}", $esc_like );
 854  
 855          $posts = $this->get_results( $query, ARRAY_A );
 856  
 857          if ( isset( $posts[0] ) && ! empty( $posts[0]['value_id'] ) ) {
 858              foreach ( (array) $posts as $value ) {
 859                  $deleted = wp_delete_post( $value['value_id'], true );
 860  
 861                  // Only flag if not empty or error
 862                  if ( ( false === $has_delete ) && ! empty( $deleted ) && ! is_wp_error( $deleted ) ) {
 863                      $has_delete = true;
 864                  }
 865              }
 866          }
 867  
 868          /** Delete users ******************************************************/
 869  
 870          $query = ! empty( $this->sync_table )
 871              ? $this->wpdb->prepare( "SELECT value_id FROM {$this->sync_table_name} INNER JOIN {$this->wpdb->users} ON(value_id = ID) WHERE meta_key = %s AND value_type = %s LIMIT {$this->max_rows}", '_bbp_old_user_id', 'user' )
 872              : $this->wpdb->prepare( "SELECT user_id AS value_id FROM {$this->wpdb->usermeta} WHERE meta_key = %s LIMIT {$this->max_rows}", '_bbp_old_user_id' );
 873  
 874          $users = $this->get_results( $query, ARRAY_A );
 875  
 876          if ( ! empty( $users ) ) {
 877              foreach ( $users as $value ) {
 878                  $deleted = wp_delete_user( $value['value_id'] );
 879  
 880                  // Only flag if not empty or error
 881                  if ( ( false === $has_delete ) && ! empty( $deleted ) && ! is_wp_error( $deleted ) ) {
 882                      $has_delete = true;
 883                  }
 884              }
 885          }
 886  
 887          unset( $posts );
 888          unset( $users );
 889  
 890          return ! $has_delete;
 891      }
 892  
 893      /**
 894       * This method deletes passwords from the wp database.
 895       *
 896       * @param int Start row
 897       */
 898  	public function clean_passwords( $start = 1 ) {
 899          $has_delete = false;
 900          $query      = $this->wpdb->prepare( "SELECT user_id, meta_value FROM {$this->wpdb->usermeta} WHERE meta_key = %s LIMIT {$start}, {$this->max_rows}", '_bbp_password' );
 901          $converted  = $this->get_results( $query, ARRAY_A );
 902  
 903          if ( ! empty( $converted ) ) {
 904              foreach ( $converted as $value ) {
 905                  if ( is_serialized( $value['meta_value'] ) ) {
 906                      $this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->users} SET user_pass = '' WHERE ID = %d", $value['user_id'] ) );
 907                  } else {
 908                      $this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->users} SET user_pass = %s WHERE ID = %d", $value['meta_value'], $value['user_id'] ) );
 909                      $this->query( $this->wpdb->prepare( "DELETE FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND user_id = %d", '_bbp_password', $value['user_id'] ) );
 910                  }
 911              }
 912              $has_delete = true;
 913          }
 914  
 915          return ! $has_delete;
 916      }
 917  
 918      /**
 919       * This method implements the authentication for the different forums.
 920       *
 921       * @param string Un-encoded password.
 922       */
 923      abstract protected function authenticate_pass( $password, $hash );
 924  
 925      /**
 926       * Info
 927       */
 928      abstract protected function info();
 929  
 930      /**
 931       * This method grabs appropriate fields from the table specified
 932       *
 933       * @param string The table name to grab fields from
 934       */
 935  	private function get_fields( $tablename = '' ) {
 936          $retval      = array();
 937          $field_array = $this->get_results( "DESCRIBE {$tablename}", ARRAY_A );
 938  
 939          // Bail if no fields
 940          if ( empty( $field_array ) ) {
 941              return $retval;
 942          }
 943  
 944          // Add fields to array
 945          foreach ( $field_array as $field ) {
 946              if ( ! empty( $field['Field'] ) ) {
 947                  $retval[] = $field['Field'];
 948              }
 949          }
 950  
 951          // Add social fields for users table
 952          if ( $tablename === $this->wpdb->users ) {
 953              $retval[] = 'role';
 954              $retval[] = 'yim';
 955              $retval[] = 'aim';
 956              $retval[] = 'jabber';
 957          }
 958  
 959          return $retval;
 960      }
 961  
 962      /** Database Wrappers *****************************************************/
 963  
 964      /**
 965       * Update the last query option and return results
 966       *
 967       * @param string $query
 968       * @param string $output
 969       */
 970  	private function get_row( $query = '' ) {
 971          $this->update_query( $query );
 972  
 973          return $this->wpdb->get_row( $query );
 974      }
 975  
 976      /**
 977       * Update the last query option and return results
 978       *
 979       * @param string $query
 980       * @param string $output
 981       */
 982  	private function get_results( $query = '', $output = OBJECT ) {
 983          $this->update_query( $query );
 984  
 985          return (array) $this->wpdb->get_results( $query, $output );
 986      }
 987  
 988      /**
 989       * Update the last query option and do a general query
 990       *
 991       * @param string $query
 992       */
 993  	private function query( $query = '' ) {
 994          $this->update_query( $query );
 995  
 996          return $this->wpdb->query( $query );
 997      }
 998  
 999      /**
1000       * Update the last query ran
1001       *
1002       * @since 2.6.0 bbPress (r6637)
1003       *
1004       * @param string $query The literal MySQL query
1005       * @return bool
1006       */
1007  	private function update_query( $query = '' ) {
1008          return update_option( '_bbp_converter_query', $query );
1009      }
1010  
1011      /**
1012       * Update the number of rows in the current step
1013       *
1014       * @since 2.6.0 bbPress (r6637)
1015       *
1016       * @param string $query The literal MySQL query
1017       * @return bool
1018       */
1019  	private function count_rows_by_results( $query = '' ) {
1020          $results = $this->get_results( $query );
1021  
1022          update_option( '_bbp_converter_rows_in_step', count( $results ) );
1023  
1024          return $results;
1025      }
1026  
1027      /**
1028       * Update the number of rows in the current step
1029       *
1030       * @since 2.6.0 bbPress (r6637)
1031       *
1032       * @param string $table_name The literal MySQL query
1033       * @return bool
1034       */
1035  	private function count_rows_by_table( $table_name = '' ) {
1036          $count = (int) $this->opdb->get_var( "SELECT COUNT(*) FROM {$table_name}" );
1037  
1038          return update_option( '_bbp_converter_rows_in_step', $count );
1039      }
1040  
1041      /** Callbacks *************************************************************/
1042  
1043      /**
1044       * Run password through wp_hash_password()
1045       *
1046       * @param string $username
1047       * @param string $password
1048       */
1049  	public function callback_pass( $username, $password ) {
1050          $user = $this->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->users} WHERE user_login = %s AND user_pass = '' LIMIT 1", $username ) );
1051          if ( ! empty( $user ) ) {
1052              $usermeta = $this->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND user_id = %d LIMIT 1", '_bbp_password', $user->ID ) );
1053  
1054              if ( ! empty( $usermeta ) ) {
1055                  if ( $this->authenticate_pass( $password, $usermeta->meta_value ) ) {
1056                      $this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->users} SET user_pass = %s WHERE ID = %d", wp_hash_password( $password ), $user->ID ) );
1057                      $this->query( $this->wpdb->prepare( "DELETE FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND user_id = %d", '_bbp_password', $user->ID ) );
1058  
1059                      // Clean the cache for this user since their password was
1060                      // upgraded from the old platform to the new.
1061                      clean_user_cache( $user->ID );
1062                  }
1063              }
1064          }
1065      }
1066  
1067      /**
1068       * A mini cache system to reduce database calls to forum ID's
1069       *
1070       * @param string $field
1071       * @return string
1072       */
1073  	private function callback_forumid( $field ) {
1074          if ( ! isset( $this->map_forumid[ $field ] ) ) {
1075              $row = ! empty( $this->sync_table )
1076                  ? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_forum_id', $field ) )
1077                  : $this->get_row( $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_forum_id', $field ) );
1078  
1079              $this->map_forumid[ $field ] = ! is_null( $row )
1080                  ? $row->value_id
1081                  : 0;
1082          }
1083  
1084          return $this->map_forumid[ $field ];
1085      }
1086  
1087      /**
1088       * A mini cache system to reduce database calls to topic ID's
1089       *
1090       * @param string $field
1091       * @return string
1092       */
1093  	private function callback_topicid( $field ) {
1094          if ( ! isset( $this->map_topicid[ $field ] ) ) {
1095              $row = ! empty( $this->sync_table )
1096                  ? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_topic_id', $field ) )
1097                  : $this->get_row( $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_topic_id', $field ) );
1098  
1099              $this->map_topicid[ $field ] = ! is_null( $row )
1100                  ? $row->value_id
1101                  : 0;
1102          }
1103  
1104          return $this->map_topicid[ $field ];
1105      }
1106  
1107      /**
1108       * A mini cache system to reduce database calls to reply_to post id.
1109       *
1110       * @since 2.4.0 bbPress (r5093)
1111       *
1112       * @param string $field
1113       * @return string
1114       */
1115  	private function callback_reply_to( $field ) {
1116          if ( ! isset( $this->map_reply_to[ $field ] ) ) {
1117              $row = ! empty( $this->sync_table )
1118                  ? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_reply_id', $field ) )
1119                  : $this->get_row( $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_reply_id', $field ) );
1120  
1121              $this->map_reply_to[ $field ] = ! is_null( $row )
1122                  ? $row->value_id
1123                  : 0;
1124          }
1125  
1126          return $this->map_reply_to[ $field ];
1127      }
1128  
1129      /**
1130       * A mini cache system to reduce database calls to user ID's
1131       *
1132       * @param string $field
1133       * @return string
1134       */
1135  	private function callback_userid( $field ) {
1136          if ( ! isset( $this->map_userid[ $field ] ) ) {
1137              $row = ! empty( $this->sync_table )
1138                  ? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_user_id', $field ) )
1139                  : $this->get_row( $this->wpdb->prepare( "SELECT user_id AS value_id FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_user_id', $field ) );
1140  
1141              if ( ! is_null( $row ) ) {
1142                  $this->map_userid[ $field ] = $row->value_id;
1143              } else {
1144                  $this->map_userid[ $field ] = ( true === $this->convert_users )
1145                      ? 0
1146                      : $field;
1147              }
1148          }
1149  
1150          return $this->map_userid[ $field ];
1151      }
1152  
1153      /**
1154       * Check if the topic or reply author is anonymous
1155       *
1156       * @since 2.6.0 bbPress (r5544)
1157       *
1158       * @param  string $field
1159       * @return string
1160       */
1161  	private function callback_check_anonymous( $field ) {
1162          $field = ( $this->callback_userid( $field ) == 0 )
1163              ? 'true'
1164              : 'false';
1165  
1166          return $field;
1167      }
1168  
1169      /**
1170       * A mini cache system to reduce database calls map topics ID's to forum ID's
1171       *
1172       * @param string $field
1173       * @return string
1174       */
1175  	private function callback_topicid_to_forumid( $field ) {
1176          $topicid = $this->callback_topicid( $field );
1177          if ( empty( $topicid ) ) {
1178              $this->map_topicid_to_forumid[ $topicid ] = 0;
1179          } elseif ( ! isset( $this->map_topicid_to_forumid[ $topicid ] ) ) {
1180              $row = $this->get_row( $this->wpdb->prepare( "SELECT post_parent FROM {$this->wpdb->posts} WHERE ID = %d LIMIT 1", $topicid ) );
1181  
1182              $this->map_topicid_to_forumid[ $topicid ] = ! is_null( $row )
1183                  ? $row->post_parent
1184                  : 0;
1185          }
1186  
1187          return $this->map_topicid_to_forumid[ $topicid ];
1188      }
1189  
1190  	protected function callback_slug( $field ) {
1191          return sanitize_title( $field );
1192      }
1193  
1194  	protected function callback_negative( $field ) {
1195          return ( $field < 0 )
1196              ? 0
1197              : $field;
1198      }
1199  
1200  	protected function callback_html( $field ) {
1201          require_once bbp_admin()->admin_dir . 'parser.php';
1202  
1203          // Setup the BBCode parser
1204          $bbcode = BBCode::getInstance();
1205  
1206          // Pass BBCode properties to the parser
1207          foreach ( $this->bbcode_parser_properties as $prop => $value ) {
1208              $bbcode->{$prop} = $value;
1209          }
1210  
1211          return html_entity_decode( $bbcode->Parse( $field ) );
1212      }
1213  
1214  	protected function callback_null( $field ) {
1215          return is_null( $field )
1216              ? ''
1217              : $field;
1218      }
1219  
1220  	protected function callback_datetime( $field ) {
1221          return is_numeric( $field )
1222              ? date( 'Y-m-d H:i:s', $field )
1223              : date( 'Y-m-d H:i:s', strtotime( $field ) );
1224      }
1225  }
1226  endif;


Generated: Thu Sep 19 01:01:28 2019 Cross-referenced by PHPXref 0.7.1