/app/class-ms-factory.php

  1. <?php 
  2. /** 
  3. * Factory class for all Models. 
  4. * 
  5. * @since 1.0.0 
  6. * 
  7. * @package Membership2 
  8. */ 
  9. class MS_Factory { 
  10.  
  11. /** 
  12. * Holds a list of all singleton objects 
  13. * 
  14. * @since 1.0.0 
  15. * 
  16. * @var array 
  17. */ 
  18. static private $Singleton = array(); 
  19.  
  20. /** 
  21. * Used to cache the original blog-ID when using network-wide protection 
  22. * 
  23. * @since 1.0.0 
  24. * 
  25. * @var array 
  26. */ 
  27. static private $Prev_Blog_Id = array(); 
  28.  
  29. /** 
  30. * This is only used for Unit-Testing to reset all cached singleton 
  31. * instances before running a new test. 
  32. * 
  33. * @since 1.0.0 
  34. */ 
  35. static public function _reset() { 
  36. self::$Singleton = array(); 
  37. wp_cache_flush(); 
  38.  
  39. /** 
  40. * Create an MS Object. 
  41. * 
  42. * @since 1.0.0 
  43. * 
  44. * @param string $class The class to create object from. 
  45. * @return object The created object. 
  46. */ 
  47. public static function create( $class, $init_arg = null ) { 
  48. $singletons = array( 
  49. 'MS_Model_Pages',  
  50. 'MS_Model_Settings',  
  51. 'MS_Model_Addon',  
  52. 'MS_Model_Rule',  
  53. 'MS_Model_Simulate',  
  54. ); 
  55.  
  56. $class = trim( $class ); 
  57.  
  58. if ( in_array( $class, $singletons ) ) { 
  59. _doing_it_wrong( 
  60. 'MS_Factory::create()',  
  61. 'This class is a singleton and should be fetched via MS_Factory::load() -> ' . $class,  
  62. '1.0.4.5' 
  63. ); 
  64.  
  65. if ( class_exists( $class ) ) { 
  66. if ( null === $init_arg ) { 
  67. $obj = new $class(); 
  68. } else { 
  69. $obj = new $class( $init_arg ); 
  70. } else { 
  71. throw new Exception( 'Class ' . $class . ' does not exist.' ); 
  72.  
  73. /** 
  74. * Assign a new unique-ID to the object right after loading it. 
  75. * 
  76. * Purpose: 
  77. * This helps us to spot duplicates of the same object. 
  78. * We can also identify objects that were not created by MS_Factory. 
  79. */ 
  80. $obj->_factory_id = uniqid( 'object-' ); 
  81.  
  82. self::prepare_obj( $obj ); 
  83.  
  84. return apply_filters( 
  85. 'ms_factory_create_'. $class,  
  86. $obj 
  87. ); 
  88.  
  89. /** 
  90. * Load a MS Object. 
  91. * 
  92. * @since 1.0.0 
  93. * 
  94. * @param string $class The class to load object from. 
  95. * @param int $model_id Retrieve model object using ID. 
  96. * @return object The retrieved model. 
  97. */ 
  98. public static function load( $class, $model_id = 0, $context = null ) { 
  99. $model = null; 
  100. $class = trim( $class ); 
  101. $model_id = intval( $model_id ); 
  102.  
  103. $key = strtolower( $class . '-' . $model_id ); 
  104. if ( null !== $context ) { 
  105. $key .= '-' . $context; 
  106.  
  107. if ( class_exists( $class ) && ! isset( self::$Singleton[$key] ) ) { 
  108. /** 
  109. * We create a new object here so we can test via instanceof if 
  110. * the object has a certain parent class. 
  111. * 
  112. * The created object might be replaced by the load_from_... 
  113. * function. 
  114. * 
  115. * Tip: The __constructor() functions of these objects should not 
  116. * exist or contain very lightweight code, never attach any 
  117. * filters/hooks, etc. as the object can be dumped a few lines later. 
  118. */ 
  119. $model = new $class( $model_id ); 
  120. $model->before_load(); 
  121.  
  122. if ( $model instanceof MS_Model_Option ) { 
  123. $model = self::load_from_wp_option( $model ); 
  124. } elseif ( $model instanceof MS_Model_CustomPostType ) { 
  125. $model = self::load_from_wp_custom_post_type( $model, $model_id ); 
  126. } elseif ( $model instanceof MS_Model_Member ) { 
  127. $model = self::load_from_wp_user( $model, $model_id ); 
  128. } elseif ( $model instanceof MS_Model_Transient ) { 
  129. $model = self::load_from_wp_transient( $model, $model_id ); 
  130.  
  131. /** 
  132. * Assign a new unique-ID to the object right after loading it. 
  133. * 
  134. * Purpose: 
  135. * This helps us to spot duplicates of the same object. 
  136. * We can also identify objects that were not created by MS_Factory. 
  137. */ 
  138. $model->_factory_id = uniqid( $key . '-' ); 
  139.  
  140. $model->after_load(); 
  141.  
  142. // Store the new object in our singleton collection. 
  143. self::set_singleton( $model, $key, $model_id ); 
  144.  
  145. self::prepare_obj( self::$Singleton[$key] ); 
  146.  
  147. if ( ! isset( self::$Singleton[$key] ) ) { 
  148. self::$Singleton[$key] = null; 
  149.  
  150. return self::$Singleton[$key]; 
  151.  
  152. /** 
  153. * Allows us to manually set/replace a cached singleton object. 
  154. * This function was introduced to store the simulation subscription as 
  155. * a singleton with subscription ID -1 
  156. * 
  157. * @since 1.0.0 
  158. * @param string $key 
  159. * @param any $obj 
  160. */ 
  161. static public function set_singleton( $obj, $key = null, $model_id = null ) { 
  162. $class = get_class( $obj ); 
  163.  
  164. if ( null === $model_id ) { 
  165. $model_id = intval( $obj->id ); 
  166.  
  167. if ( null === $key ) { 
  168. $key = strtolower( $class . '-' . $model_id ); 
  169.  
  170. // This flag is used by MS_Model::store_singleton() 
  171. if ( property_exists( $obj, '_in_cache' ) ) { 
  172. $obj->_in_cache = true; 
  173.  
  174. $obj = apply_filters( 
  175. 'ms_factory_set-' . strtolower( $class ),  
  176. $obj,  
  177. $model_id 
  178. ); 
  179.  
  180. $obj = apply_filters( 
  181. 'ms_factory_set',  
  182. $obj,  
  183. $class,  
  184. $model_id 
  185. ); 
  186.  
  187. self::$Singleton[ $key ] = $obj; 
  188.  
  189. /** 
  190. * Clears the factory cache. 
  191. * 
  192. * @since 1.0.0 
  193. */ 
  194. static public function clear() { 
  195. wp_cache_flush(); 
  196.  
  197. /** 
  198. * Initialize the object after it was created or loaded. 
  199. * 
  200. * @since 1.0.0 
  201. * @param MS_Hook &$obj Any Membership2 object to initialize. 
  202. */ 
  203. static private function prepare_obj( &$obj ) { 
  204. static $Init_Obj = array(); 
  205. static $Init_Class = array(); 
  206.  
  207. // This case only happens during plugin-updates but needs to be handled. 
  208. if ( is_a( $obj, '__PHP_Incomplete_Class' ) ) { 
  209. return false; 
  210.  
  211. // Prepare each single object that was created. 
  212. if ( method_exists( $obj, 'prepare_obj' ) ) { 
  213. if ( ! isset( $Init_Obj[$obj->_factory_id] ) ) { 
  214. $Init_Obj[$obj->_factory_id] = true; 
  215. $obj->prepare_obj(); 
  216.  
  217. // Prepare the first object of each class-type (i.e. "prepare-once"). 
  218. if ( method_exists( $obj, 'prepare_class' ) ) { 
  219. $class = get_class( $obj ); 
  220.  
  221. if ( ! isset( $Init_Class[$class] ) ) { 
  222. $Init_Class[$class] = true; 
  223. $obj->prepare_class(); 
  224.  
  225. /** 
  226. * Load MS_Model_Option object. 
  227. * 
  228. * MS_Model_Option objects are singletons. 
  229. * To support network-wide protection we use our convenience function 
  230. * self::get_option(). 
  231. * 
  232. * @since 1.0.0 
  233. * 
  234. * @param MS_Model_option $model The empty model instance. 
  235. * @return MS_Model_Option The retrieved object. 
  236. */ 
  237. protected static function load_from_wp_option( $model ) { 
  238. $class = get_class( $model ); 
  239.  
  240. $option_key = $model->option_key(); 
  241. $cache = wp_cache_get( $option_key, 'MS_Model_Option' ); 
  242.  
  243. if ( $cache ) { 
  244. $model = $cache; 
  245. } else { 
  246. $settings = self::get_option( $option_key ); 
  247. self::populate_model( $model, $settings ); 
  248.  
  249. return apply_filters( 
  250. 'ms_factory_load_from_wp_option',  
  251. $model,  
  252. $class 
  253. ); 
  254.  
  255. /** 
  256. * Load MS_Model_Transient object. 
  257. * 
  258. * MS_Transient objects are singletons. 
  259. * To support network-wide protection we use our convenience function 
  260. * self::get_transient(). 
  261. * 
  262. * @since 1.0.0 
  263. * 
  264. * @param MS_Model_Transient $model The empty model instance. 
  265. * @return MS_Model_Transient The retrieved object. 
  266. */ 
  267. public static function load_from_wp_transient( $model ) { 
  268. $option_key = $model->option_key(); 
  269. $cache = wp_cache_get( $option_key, 'MS_Model_Transient' ); 
  270.  
  271. if ( $cache ) { 
  272. $model = $cache; 
  273. } else { 
  274. $settings = self::get_transient( $option_key ); 
  275. self::populate_model( $model, $settings ); 
  276.  
  277. return apply_filters( 
  278. 'ms_factory_load_from_wp_transient',  
  279. $model,  
  280. $option_key 
  281. ); 
  282.  
  283. /** 
  284. * Load MS_Model_CustomPostType Objects. 
  285. * 
  286. * Load from post and postmeta. 
  287. * For network-wide protection we get the data from first blog 
  288. * 
  289. * @since 1.0.0 
  290. * 
  291. * @param MS_Model_CustomPostType $model The empty model instance. 
  292. * @param int $model_id The model id to retrieve. 
  293. * 
  294. * @return MS_Model_CustomPostType The retrieved object. 
  295. */ 
  296. protected static function load_from_wp_custom_post_type( $model, $model_id = 0 ) { 
  297. $class = get_class( $model ); 
  298.  
  299. if ( ! empty( $model_id ) ) { 
  300. $cache = wp_cache_get( $model_id, $class ); 
  301.  
  302. if ( $cache ) { 
  303. $model = $cache; 
  304. } else { 
  305. self::select_blog(); 
  306. $post = get_post( $model_id ); 
  307.  
  308. if ( ! empty( $post ) && $model->get_post_type() === $post->post_type ) { 
  309. $post_meta = get_post_meta( $model_id ); 
  310. $post_meta['id'] = array( $post->ID ); 
  311. $post_meta['description'] = array( $post->post_content ); 
  312. $post_meta['user_id'] = array( $post->post_author ); 
  313. self::populate_model( $model, $post_meta, true ); 
  314.  
  315. /** 
  316. * Allow child classes of the CustomPostType model to load 
  317. * custom values from the posts/postmeta table 
  318. * 
  319. * @since 1.0.1.0 
  320. */ 
  321. $model->load_meta_data( $post_meta ); 
  322. $model->load_post_data( $post ); 
  323. } else { 
  324. $model->id = 0; 
  325. self::revert_blog(); 
  326.  
  327. return apply_filters( 
  328. 'ms_factory_load_from_custom_post_type',  
  329. $model,  
  330. $class,  
  331. $model_id 
  332. ); 
  333.  
  334. /** 
  335. * Load MS_Model_Member Object. 
  336. * 
  337. * Load from user and user meta. 
  338. * This data is always network-wide. 
  339. * 
  340. * @since 1.0.0 
  341. * 
  342. * @param MS_Model_Member $model The empty member instance. 
  343. * @param int $user_id The user/member ID. 
  344. * 
  345. * @return MS_Model_Member The retrieved object. 
  346. */ 
  347. protected static function load_from_wp_user( $model, $user_id, $name = null ) { 
  348. $class = get_class( $model ); 
  349. $cache = wp_cache_get( $user_id, $class ); 
  350.  
  351. if ( $cache ) { 
  352. $model = $cache; 
  353. } else { 
  354. $wp_user = new WP_User( $user_id, $name ); 
  355.  
  356. if ( ! empty( $wp_user->ID ) ) { 
  357. $member_details = get_user_meta( $user_id ); 
  358.  
  359. $model->id = $wp_user->ID; 
  360. $model->username = $wp_user->user_login; 
  361. $model->email = $wp_user->user_email; 
  362. $model->name = $wp_user->display_name; 
  363. $model->first_name = $wp_user->first_name; 
  364. $model->last_name = $wp_user->last_name; 
  365. $model->wp_user = $wp_user; 
  366.  
  367. if ( ! $model->name ) { 
  368. if ( $model->first_name ) { 
  369. $model->name = $model->first_name . ' ' . $model->last_name; 
  370. } else { 
  371. $model->name = $wp_user->user_login; 
  372. $model->name = ucwords( strtolower( $model->name ) ); 
  373. $model->name = trim( $model->name ); 
  374.  
  375. /** 
  376. * Manually customize the display name of the user via a filter. 
  377. * 
  378. * @since 1.0.1.2 
  379. * @param string $name The default display name used by M2. 
  380. * @param WP_User $wp_user The user object used to populate the name. 
  381. */ 
  382. $model->name = apply_filters( 
  383. 'ms_model_user_set_name',  
  384. $model->name,  
  385. $wp_user 
  386. ); 
  387.  
  388. // Remove automatic populated values from metadata, if present. 
  389. unset( $member_details['ms_username'] ); 
  390. unset( $member_details['ms_email'] ); 
  391. unset( $member_details['ms_name'] ); 
  392. unset( $member_details['ms_first_name'] ); 
  393. unset( $member_details['ms_last_name'] ); 
  394.  
  395. self::populate_model( $model, $member_details, 'ms_' ); 
  396.  
  397. // Load membership_relationships 
  398. $model->subscriptions = MS_Model_Relationship::get_subscriptions( 
  399. array( 'user_id' => $model->id ) 
  400. ); 
  401.  
  402. return apply_filters( 
  403. 'ms_factory_load_from_wp_user',  
  404. $model,  
  405. $class,  
  406. $user_id 
  407. ); 
  408.  
  409. // 
  410. // ========================================================================= 
  411. // Public helper functions 
  412. // ========================================================================= 
  413. // 
  414.   
  415. /** 
  416. * Populate fields of the model 
  417. * 
  418. * @since 1.0.0 
  419. * 
  420. * @param MS_Model $model 
  421. * @param array $settings 
  422. * @param bool $postmeta 
  423. */ 
  424. static public function populate_model( &$model, $settings, $postmeta = false ) { 
  425. $fields = $model->get_object_vars(); 
  426. $class = get_class( $model ); 
  427. $vars = get_class_vars( $class ); 
  428. $saved_data = array(); 
  429.  
  430. $ignore = isset( $vars['ignore_fields'] ) ? $vars['ignore_fields'] : array(); 
  431. $ignore[] = 'instance'; // Don't deserialize the double-serialized model! 
  432. $ignore[] = 'actions'; 
  433. $ignore[] = 'filters'; 
  434. $ignore[] = 'ignore_fields'; 
  435.  
  436. foreach ( $fields as $field => $val ) { 
  437. if ( '_' === $field[0] || in_array( $field, $ignore ) ) { 
  438. continue; 
  439.  
  440. $value = null; 
  441.  
  442. if ( false === $postmeta ) { 
  443. if ( isset( $settings[ $field ] ) ) { 
  444. $value = $settings[ $field ]; 
  445. } elseif ( isset( $settings[ '_' . $field ] ) ) { 
  446. $value = $settings[ '_' . $field ]; 
  447. } elseif ( true === $postmeta ) { 
  448. if ( isset( $settings[ $field ][0] ) ) { 
  449. $value = $settings[ $field ][ 0 ]; 
  450. } elseif ( isset( $settings[ '_' . $field ][0] ) ) { 
  451. $value = $settings[ '_' . $field ][ 0 ]; 
  452. } elseif ( is_string( $postmeta ) ) { 
  453. if ( isset( $settings[ $postmeta . $field ][0] ) ) { 
  454. $value = $settings[ $postmeta . $field ][ 0 ]; 
  455. } elseif ( isset( $settings[ '_' . $postmeta . $field ][0] ) ) { 
  456. $value = $settings[ '_' . $postmeta . $field ][ 0 ]; 
  457.  
  458. if ( $value ) { 
  459. $value = maybe_unserialize( $value ); 
  460.  
  461. $saved_data[ $field ] = $value; 
  462. if ( null !== $value ) { 
  463. $model->set_field( $field, $value ); 
  464.  
  465. $model->_saved_data = $saved_data; 
  466.  
  467. /** 
  468. * Filter the serialized data collection before it is returned. 
  469. * 
  470. * Typically it is written to database right after this function call,  
  471. * so this hook allows us to modify data before it's written to the DB. 
  472. * 
  473. * @var object $model The completely populated object. 
  474. * @var string $class Class name of the object. 
  475. * @var array $settings The source data (serialized array). 
  476. * @var bool|string $postmeta The post-meta flag defines how the 
  477. * $settings array is formatted. 
  478. */ 
  479. $model = apply_filters( 
  480. 'ms_factory_populate',  
  481. $model,  
  482. $class,  
  483. $settings,  
  484. $postmeta 
  485. ); 
  486.  
  487. $model = apply_filters( 
  488. 'ms_factory_populate-' . strtolower( $class ),  
  489. $model,  
  490. $settings,  
  491. $postmeta 
  492. ); 
  493.  
  494. /** 
  495. * Converts an MS_Model into an array 
  496. * 
  497. * @since 1.0.0 
  498. * 
  499. * @param MS_Model $model 
  500. * @return array 
  501. */ 
  502. static public function serialize_model( &$model ) { 
  503. $data = array(); 
  504. $ignore = array(); 
  505. $class = get_class( $model ); 
  506.  
  507. if ( is_object( $model ) ) { 
  508. if ( method_exists( $model, '__sleep' ) ) { 
  509. $fields = array_flip( $model->__sleep() ); 
  510. } else { 
  511. $fields = $model->get_object_vars(); 
  512.  
  513. $vars = get_class_vars( get_class( $model ) ); 
  514.  
  515. $ignore = isset( $vars['ignore_fields'] ) ? $vars['ignore_fields'] : array(); 
  516. $ignore[] = 'instance'; // Don't double-serialize the model! 
  517. $ignore[] = 'actions'; 
  518. $ignore[] = 'filters'; 
  519. $ignore[] = 'ignore_fields'; 
  520. } else { 
  521. // Value does not need to be serialized. 
  522. return $model; 
  523.  
  524. foreach ( $fields as $field => $dummy ) { 
  525. if ( '_' === $field[0] || in_array( $field, $ignore ) ) { 
  526. continue; 
  527.  
  528. $data[ $field ] = $model->$field; 
  529.  
  530. /** 
  531. * Filter the serialized data collection before it is returned. 
  532. * 
  533. * Typically it is written to database right after this function call,  
  534. * so this hook allows us to modify data before it's written to the DB. 
  535. * 
  536. * @var array $data Serialized data array. 
  537. * @var string $class Class name of the source object. 
  538. * @var object $model The source object (unserialized) 
  539. */ 
  540. $data = apply_filters( 
  541. 'ms_factory_serialize',  
  542. $data,  
  543. $class,  
  544. $model 
  545. ); 
  546.  
  547. $data = apply_filters( 
  548. 'ms_factory_serialize-' . strtolower( $class ),  
  549. $data,  
  550. $model 
  551. ); 
  552.  
  553. ksort( $data ); 
  554. return $data; 
  555.  
  556. // 
  557. // ========================================================================= 
  558. // Wrappers and convenience functions 
  559. // ========================================================================= 
  560. // 
  561.   
  562. /** 
  563. * Wrapper to get an option value (regards network-wide protection mode) 
  564. * 
  565. * @since 1.0.0 
  566. * @param string $key Option Key 
  567. * @return mixed Option value 
  568. */ 
  569. static public function get_option( $key ) { 
  570. if ( MS_Plugin::is_network_wide() ) { 
  571. $settings = get_site_option( $key ); 
  572. } else { 
  573. $settings = get_option( $key ); 
  574.  
  575. return $settings; 
  576.  
  577. /** 
  578. * Wrapper to delete an option value (regards network-wide protection mode) 
  579. * 
  580. * @since 1.0.0 
  581. * @param string $key Option Key 
  582. */ 
  583. static public function delete_option( $key ) { 
  584. if ( MS_Plugin::is_network_wide() ) { 
  585. delete_site_option( $key ); 
  586. } else { 
  587. delete_option( $key ); 
  588.  
  589. /** 
  590. * Wrapper to update an option value (regards network-wide protection mode) 
  591. * 
  592. * @since 1.0.0 
  593. * @param string $key Option Key 
  594. * @param mixed $value New option value 
  595. */ 
  596. static public function update_option( $key, $value ) { 
  597. if ( MS_Plugin::is_network_wide() ) { 
  598. update_site_option( $key, $value ); 
  599. } else { 
  600. update_option( $key, $value ); 
  601.  
  602. /** 
  603. * Wrapper to get an transient value (regards network-wide protection mode) 
  604. * 
  605. * @since 1.0.0 
  606. * @param string $key Transient Key 
  607. * @return mixed Transient value 
  608. */ 
  609. static public function get_transient( $key ) { 
  610. if ( MS_Plugin::is_network_wide() ) { 
  611. $transient = get_site_transient( $key ); 
  612. } else { 
  613. $transient = get_transient( $key ); 
  614.  
  615. return $transient; 
  616.  
  617. /** 
  618. * Wrapper to delete an transient value (regards network-wide protection mode) 
  619. * 
  620. * @since 1.0.0 
  621. * @param string $key Transient Key 
  622. */ 
  623. static public function delete_transient( $key ) { 
  624. if ( MS_Plugin::is_network_wide() ) { 
  625. delete_site_transient( $key ); 
  626. } else { 
  627. delete_transient( $key ); 
  628.  
  629. /** 
  630. * Wrapper to update an transient value (regards network-wide protection mode) 
  631. * 
  632. * @since 1.0.0 
  633. * @param string $key Transient Key 
  634. * @param mixed $value New transient value 
  635. */ 
  636. static public function set_transient( $key, $value, $expiration ) { 
  637. if ( MS_Plugin::is_network_wide() ) { 
  638. set_site_transient( $key, $value, $expiration ); 
  639. } else { 
  640. set_transient( $key, $value, $expiration ); 
  641.  
  642. /** 
  643. * When network wide protection is enabled this will temporarily switch 
  644. * to the main blog to access or change data. 
  645. * 
  646. * Use revert_blog() when done!! 
  647. * This function is a performance-wise much better alternative to the 
  648. * built-in function switch_to_blog() because it does not run all the 
  649. * initialization logic (update user-roles, etc) when switching a blog. 
  650. * 
  651. * @since 1.0.0 
  652. */ 
  653. static public function select_blog( $site_id = null ) { 
  654. global $wpdb; 
  655.  
  656. if ( MS_Plugin::is_network_wide() ) { 
  657. if ( null === $site_id ) { 
  658. if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) { 
  659. $site_id = BLOG_ID_CURRENT_SITE; 
  660. } else { 
  661. $site_id = 1; 
  662. self::$Prev_Blog_Id[] = $GLOBALS['blog_id']; 
  663.  
  664. /**if ( $GLOBALS['blog_id'] != $site_id ) { 
  665. $GLOBALS['blog_id'] = $site_id; 
  666. $wpdb->set_blog_id( $GLOBALS['blog_id'] ); 
  667. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix(); 
  668. }*/ 
  669. switch_to_blog( $site_id ); 
  670.  
  671. /** 
  672. * Reverts back to the original blog during network wide protection. 
  673. * 
  674. * @since 1.0.0 
  675. */ 
  676. static public function revert_blog() { 
  677. global $wpdb; 
  678.  
  679. if ( MS_Plugin::is_network_wide() ) { 
  680. $site_id = array_pop( self::$Prev_Blog_Id ); 
  681.  
  682. /**if ( $site_id != $GLOBALS['blog_id'] ) { 
  683. $GLOBALS['blog_id'] = $site_id; 
  684. $wpdb->set_blog_id( $GLOBALS['blog_id'] ); 
  685. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix(); 
  686. }*/ 
  687.  
  688. restore_current_blog(); 
  689.  
  690. /** 
  691. * Returns the blog-id that was loaded by the user. This will return the 
  692. * original blog-id, even when switched to a different blog by calling 
  693. * self::select_blog() 
  694. * 
  695. * @since 1.0.0 
  696. * @return int The requested blog-ID. 
  697. */ 
  698. static public function current_blog_id() { 
  699. $blog_id = get_current_blog_id(); 
  700.  
  701. if ( count( self::$Prev_Blog_Id ) > 0 ) { 
  702. $blog_id = self::$Prev_Blog_Id[0]; 
  703.  
  704. return $blog_id; 
  705.  
.