/nextgen-facebook.php

  1. <?php 
  2. /** 
  3. * Plugin Name: NextGEN Facebook (NGFB) 
  4. * Plugin Slug: nextgen-facebook 
  5. * Text Domain: nextgen-facebook 
  6. * Domain Path: /languages 
  7. * Plugin URI: https://surniaulula.com/extend/plugins/nextgen-facebook/ 
  8. * Assets URI: https://surniaulula.github.io/nextgen-facebook/assets/ 
  9. * Author: JS Morisset 
  10. * Author URI: https://surniaulula.com/ 
  11. * License: GPLv3 
  12. * License URI: https://www.gnu.org/licenses/gpl.txt 
  13. * Description: Complete meta tags for the best looking shares on Facebook, Google, Pinterest, Twitter, etc - no matter how your webpage is shared! 
  14. * Requires At Least: 3.7 
  15. * Tested Up To: 4.7.4 
  16. * Version: 8.43.0 
  17. * 
  18. * Version Numbering: {major}.{minor}.{bugfix}[-{stage}.{level}] 
  19. * 
  20. * {major} Major structural code changes / re-writes or incompatible API changes. 
  21. * {minor} New functionality was added or improved in a backwards-compatible manner. 
  22. * {bugfix} Backwards-compatible bug fixes or small improvements. 
  23. * {stage}.{level} Pre-production release: dev < a (alpha) < b (beta) < rc (release candidate). 
  24. * 
  25. * Copyright 2012-2017 Jean-Sebastien Morisset (https://surniaulula.com/) 
  26. */ 
  27.  
  28. if ( ! defined( 'ABSPATH' ) ) { 
  29. die( 'These aren\'t the droids you\'re looking for...' ); 
  30.  
  31. if ( ! class_exists( 'Ngfb' ) ) { 
  32.  
  33. class Ngfb { 
  34. /** 
  35. * Class Object Variables 
  36. */ 
  37. public $p; // Ngfb 
  38. public $admin; // NgfbAdmin (admin menus and page loader) 
  39. public $cache; // SucomCache (object and file caching) 
  40. public $check; // NgfbCheck 
  41. public $debug; // SucomDebug or SucomNoDebug 
  42. public $head; // NgfbHead 
  43. public $loader; // NgfbLoader 
  44. public $media; // NgfbMedia (images, videos, etc.) 
  45. public $msgs; // NgfbMessages (admin tooltip messages) 
  46. public $notice; // SucomNotice or SucomNoNotice 
  47. public $og; // NgfbOpenGraph 
  48. public $opt; // NgfbOptions 
  49. public $page; // NgfbPage (page title, desc, etc.) 
  50. public $reg; // NgfbRegister 
  51. public $script; // NgfbScript (admin jquery tooltips) 
  52. public $sharing; // NgfbSharing (wp_head and wp_footer js and buttons) 
  53. public $style; // NgfbStyle (admin styles) 
  54. public $tc; // NgfbTwitterCard 
  55. public $util; // NgfbUtil (extends SucomUtil) 
  56. public $webpage; // deprecated on 2017/03/31 (retain for backwards compatibility) 
  57. public $weibo; // NgfbWeibo 
  58.  
  59. /** 
  60. * Reference Variables (config, options, modules, etc.) 
  61. */ 
  62. public $m = array(); // plugin modules 
  63. public $m_ext = array(); // plugin extension modules 
  64. public $cf = array(); // config array defined in construct method 
  65. public $avail = array(); // assoc array for other plugin checks 
  66. public $options = array(); // individual blog/site options 
  67. public $site_options = array(); // multisite options 
  68. public $sc = array(); // shortcodes 
  69.  
  70. private static $instance; 
  71.  
  72. /** 
  73. * Ngfb Constructor 
  74. */ 
  75. public function __construct() { 
  76.  
  77. require_once dirname( __FILE__ ).'/lib/config.php'; 
  78. $this->cf = NgfbConfig::get_config( false, false ); // unfiltered - $cf['*'] array is not available yet 
  79. NgfbConfig::set_constants( __FILE__ ); 
  80. NgfbConfig::require_libs( __FILE__ ); // includes the register.php class library 
  81. $this->reg = new NgfbRegister( $this ); // activate, deactivate, uninstall hooks 
  82.  
  83. add_action( 'init', array( &$this, 'set_config' ), -10 ); // runs at init -10 (before widgets_init) 
  84. add_action( 'widgets_init', array( &$this, 'init_widgets' ), 10 ); // runs at init 1 
  85. add_action( 'init', array( &$this, 'set_options' ), NGFB_INIT_PRIORITY - 3 ); // runs at init 11 by default 
  86. add_action( 'init', array( &$this, 'set_objects' ), NGFB_INIT_PRIORITY - 2 ); // runs at init 12 by default 
  87. add_action( 'init', array( &$this, 'init_shortcodes' ), NGFB_INIT_PRIORITY - 1 ); // runs at init 13 by default 
  88. add_action( 'init', array( &$this, 'init_plugin' ), NGFB_INIT_PRIORITY ); // runs at init 14 by default 
  89.  
  90. if ( is_admin() ) { 
  91. add_action( 'ngfb_init_textdomain', // action is run after the debug property is defined 
  92. array( __CLASS__, 'init_textdomain' ), -10, 1 ); // hooks override_textdomain_mofile if debug enabled 
  93.  
  94. public static function &get_instance() { 
  95. if ( ! isset( self::$instance ) ) { 
  96. self::$instance = new self; 
  97. return self::$instance; 
  98.  
  99. // runs at init priority -10 
  100. // called by activate_plugin() as well 
  101. public function set_config( $activate = false ) { 
  102. $this->cf = NgfbConfig::get_config( false, true ); // apply filters and define the $cf['*'] array 
  103.  
  104. // runs at init 1 
  105. public function init_widgets() { 
  106. $opts = get_option( NGFB_OPTIONS_NAME ); 
  107. if ( ! empty( $opts['plugin_widgets'] ) ) { 
  108. foreach ( $this->cf['plugin'] as $ext => $info ) { 
  109. if ( isset( $info['lib']['widget'] ) && is_array( $info['lib']['widget'] ) ) { 
  110. foreach ( $info['lib']['widget'] as $id => $name ) { 
  111. $classname = apply_filters( $ext.'_load_lib', false, 'widget/'.$id ); 
  112. if ( $classname !== false && class_exists( $classname ) ) { 
  113. register_widget( $classname ); // name of a class that extends WP_Widget 
  114.  
  115. // runs at init priority 11 by default 
  116. // called by activate_plugin() as well 
  117. public function set_options( $activate = false ) { 
  118.  
  119. if ( $activate && defined( 'NGFB_RESET_ON_ACTIVATE' ) && NGFB_RESET_ON_ACTIVATE ) { 
  120. error_log( 'NGFB_RESET_ON_ACTIVATE constant is true - reloading default settings for plugin activation' ); 
  121. delete_option( NGFB_OPTIONS_NAME ); 
  122.  
  123. $this->options = get_option( NGFB_OPTIONS_NAME ); 
  124.  
  125. // look for alternate options name 
  126. if ( ! is_array( $this->options ) ) { 
  127. if ( defined( 'NGFB_OPTIONS_NAME_ALT' ) && NGFB_OPTIONS_NAME_ALT ) { 
  128. $this->options = get_option( NGFB_OPTIONS_NAME_ALT ); 
  129. if ( is_array( $this->options ) ) { 
  130. update_option( NGFB_OPTIONS_NAME, $this->options ); // auto-creates with autoload = yes 
  131. delete_option( NGFB_OPTIONS_NAME_ALT ); 
  132.  
  133. // check_options() saves the settings 
  134. if ( ! is_array( $this->options ) ) { 
  135. if ( isset( $this->cf['opt']['defaults'] ) ) { // just in case 
  136. $this->options = $this->cf['opt']['defaults']; 
  137. } else { 
  138. $this->options = array(); 
  139. // reload from filtered defaults when all classes loaded 
  140. $this->options['options_reload_defaults'] = true; 
  141.  
  142. if ( is_multisite() ) { 
  143.  
  144. $this->site_options = get_site_option( NGFB_SITE_OPTIONS_NAME ); 
  145.  
  146. // look for alternate site options name 
  147. if ( ! is_array( $this->site_options ) ) { 
  148. if ( defined( 'NGFB_SITE_OPTIONS_NAME_ALT' ) && NGFB_SITE_OPTIONS_NAME_ALT ) { 
  149. $this->site_options = get_site_option( NGFB_SITE_OPTIONS_NAME_ALT ); 
  150. if ( is_array( $this->site_options ) ) { 
  151. update_site_option( NGFB_SITE_OPTIONS_NAME, $this->site_options ); 
  152. delete_site_option( NGFB_SITE_OPTIONS_NAME_ALT ); 
  153.  
  154. // check_options() saves the settings 
  155. if ( ! is_array( $this->site_options ) ) { 
  156. if ( isset( $this->cf['opt']['site_defaults'] ) ) { // just in case 
  157. $this->site_options = $this->cf['opt']['site_defaults']; 
  158. } else { 
  159. $this->site_options = array(); 
  160. // reload from filtered defaults when all classes loaded 
  161. $this->site_options['options_reload_defaults'] = true; 
  162.  
  163. // if multisite options are found, check for overwrite of site specific options 
  164. if ( is_array( $this->options ) && is_array( $this->site_options ) ) { 
  165. $blog_id = get_current_blog_id(); // since wp 3.1 
  166. $defined_constants = get_defined_constants( true ); // $categorize = true 
  167. foreach ( $this->site_options as $key => $val ) { 
  168. if ( strpos( $key, ':use' ) !== false ) { 
  169. continue; 
  170. if ( isset( $this->site_options[$key.':use'] ) ) { 
  171. switch ( $this->site_options[$key.':use'] ) { 
  172. case'force': 
  173. $this->options[$key.':is'] = 'disabled'; 
  174. $this->options[$key] = $this->site_options[$key]; 
  175. break; 
  176. case 'empty': // blank string, null, false, or 0 
  177. if ( empty( $this->options[$key] ) ) { 
  178. $this->options[$key] = $this->site_options[$key]; 
  179. break; 
  180. $constant_name = 'NGFB_ID_'.$blog_id.'_OPT_'.strtoupper( $key ); 
  181. if ( isset( $defined_constants['user'][$constant_name] ) ) { 
  182. $this->options[$key] = $defined_constants['user'][$constant_name]; 
  183.  
  184. // runs at init priority 12 by default 
  185. // called by activate_plugin() as well 
  186. public function set_objects( $activate = false ) { 
  187.  
  188. $network = is_multisite() ? true : false; 
  189.  
  190. $this->check = new NgfbCheck( $this ); 
  191. $this->avail = $this->check->get_avail(); // uses $this->options in checks 
  192.  
  193. // configure the debug class 
  194. $html_debug = ! empty( $this->options['plugin_debug'] ) ||  
  195. ( defined( 'NGFB_HTML_DEBUG' ) && NGFB_HTML_DEBUG ) ? true : false; 
  196. $wp_debug = defined( 'NGFB_WP_DEBUG' ) && NGFB_WP_DEBUG ? true : false; 
  197.  
  198. if ( ( $html_debug || $wp_debug ) && // only load debug class if debug options are enabled 
  199. ( $classname = NgfbConfig::load_lib( false, 'com/debug', 'SucomDebug' ) ) ) { 
  200. $this->debug = new $classname( $this, array( 'html' => $html_debug, 'wp' => $wp_debug ) ); 
  201. if ( $this->debug->enabled ) { 
  202. global $wp_version; 
  203. $this->debug->log( 'debug enabled on '.date( 'c' ) ); 
  204. $this->debug->log( 'hostname '.php_uname( 'n' ) ); 
  205. $this->debug->log( 'WP version '.$wp_version ); 
  206. $this->debug->log( 'PHP version '.phpversion() ); 
  207. $this->debug->log( $this->check->get_ext_list() ); 
  208. } else { 
  209. $this->debug = new SucomNoDebug(); // make sure debug property is always available 
  210.  
  211. do_action( 'ngfb_init_textdomain', $this->debug->enabled ); 
  212.  
  213. if ( is_admin() && // only load notice class in the admin interface 
  214. ( $classname = NgfbConfig::load_lib( false, 'com/notice', 'SucomNotice' ) ) ) { 
  215. $this->notice = new $classname( $this ); 
  216. } else { 
  217. $this->notice = new SucomNoNotice(); // make sure the notice property is always available 
  218.  
  219. $this->util = new NgfbUtil( $this ); // extends SucomUtil 
  220. $this->opt = new NgfbOptions( $this ); 
  221. $this->cache = new SucomCache( $this ); // object and file caching 
  222. $this->style = new NgfbStyle( $this ); // admin styles 
  223. $this->script = new NgfbScript( $this ); // admin jquery tooltips 
  224. $this->page = new NgfbPage( $this ); // page title, desc, etc. 
  225. $this->webpage =& $this->page; // deprecated on 2017/03/31 (retain for backwards compatibility) 
  226. $this->media = new NgfbMedia( $this ); // images, videos, etc. 
  227. $this->filters = new NgfbFilters( $this ); // integration filters 
  228. $this->head = new NgfbHead( $this ); 
  229.  
  230. // meta tags and json-ld markup 
  231. $this->og = new NgfbOpenGraph( $this ); // open graph 
  232. $this->weibo = new NgfbWeibo( $this ); // weibo 
  233. $this->tc = new NgfbTwitterCard( $this ); // twitter 
  234. $this->schema = new NgfbSchema( $this ); // schema 
  235.  
  236. if ( is_admin() ) { 
  237. $this->msgs = new NgfbMessages( $this ); // admin tooltip messages 
  238. $this->admin = new NgfbAdmin( $this ); // admin menus and page loader 
  239.  
  240. if ( $this->avail['p_ext']['ssb'] ) { 
  241. $this->sharing = new NgfbSharing( $this ); // wp_head and wp_footer js and buttons 
  242.  
  243. $this->loader = new NgfbLoader( $this ); // module loader 
  244.  
  245. if ( $this->debug->enabled ) { 
  246. $this->debug->mark( 'init objects action' ); // begin timer 
  247. do_action( 'ngfb_init_objects', $activate ); 
  248.  
  249. if ( $this->debug->enabled ) { 
  250. $this->debug->mark( 'init objects action' ); // end timer 
  251.  
  252. /** 
  253. * set_options() may have loaded the static defaults for new or missing options. 
  254. * After all objects have been loaded, and all filter / action hooks registered,  
  255. * check to see if the options need to be reloaded from the filtered defaults. 
  256. */ 
  257. if ( isset( $this->options['options_reload_defaults'] ) &&  
  258. $this->options['options_reload_defaults'] === true ) { 
  259. $this->options = $this->opt->get_defaults(); // check_options() saves the settings 
  260. $this->options = $this->opt->check_options( NGFB_OPTIONS_NAME,  
  261. $this->options, $network, $activate ); 
  262.  
  263. if ( $network ) { 
  264. if ( isset( $this->options['options_reload_defaults'] ) &&  
  265. $this->options['options_reload_defaults'] === true ) { 
  266. $this->options = $this->opt->get_site_defaults(); // check_options() saves the settings 
  267. $this->site_options = $this->opt->check_options( NGFB_SITE_OPTIONS_NAME,  
  268. $this->site_options, $network, $activate ); 
  269.  
  270. /** 
  271. * Issue reminder notices and disable some caching when the plugin's debug mode is enabled. 
  272. */ 
  273. if ( $this->debug->enabled ) { 
  274. if ( $this->debug->is_enabled( 'wp' ) ) { 
  275. $this->debug->log( 'WP debug log mode is active' ); 
  276. $this->notice->warn( __( 'WP debug log mode is active — debug messages are being sent to the WordPress debug log.',  
  277. 'nextgen-facebook' ) ); 
  278. } elseif ( $this->debug->is_enabled( 'html' ) ) { 
  279. $this->debug->log( 'HTML debug mode is active' ); 
  280. $this->notice->warn( __( 'HTML debug mode is active — debug messages are being added to webpages as hidden HTML comments.',  
  281. 'nextgen-facebook' ) ); 
  282. $this->util->add_plugin_filters( $this, array(  
  283. 'cache_expire_head_array' => '__return_zero',  
  284. 'cache_expire_setup_html' => '__return_zero',  
  285. 'cache_expire_sharing_buttons' => '__return_zero',  
  286. ) ); 
  287.  
  288. // runs at init priority 13 by default 
  289. public function init_shortcodes() { 
  290. if ( ! empty( $this->options['plugin_shortcodes'] ) ) { 
  291. foreach ( $this->cf['plugin'] as $ext => $info ) { 
  292. if ( isset( $info['lib']['shortcode'] ) && is_array( $info['lib']['shortcode'] ) ) { 
  293. foreach ( $info['lib']['shortcode'] as $id => $name ) { 
  294. $classname = apply_filters( $ext.'_load_lib', false, 'shortcode/'.$id ); 
  295. if ( $classname !== false && class_exists( $classname ) ) { 
  296. $this->sc[$id] = new $classname( $this ); 
  297.  
  298. // runs at init priority 14 by default 
  299. public function init_plugin() { 
  300.  
  301. if ( $this->debug->enabled ) { 
  302. $this->debug->mark( 'plugin initialization' ); // begin timer 
  303.  
  304. if ( $this->debug->enabled ) { 
  305. foreach ( array( 'wp_head', 'wp_footer', 'admin_head', 'admin_footer' ) as $action ) { 
  306. foreach ( array( -9000, 9000 ) as $prio ) { 
  307. add_action( $action, create_function( '',  
  308. 'echo "<!-- ngfb '.$action.' action hook priority '.$prio.' mark -->\n";' ), $prio ); 
  309. add_action( $action, array( &$this, 'show_debug' ), $prio + 1 ); 
  310. foreach ( array( 'wp_footer', 'admin_footer' ) as $action ) { 
  311. foreach ( array( 9900 ) as $prio ) { 
  312. add_action( $action, array( &$this, 'show_config' ), $prio ); 
  313.  
  314. if ( $this->debug->enabled ) { 
  315. $this->debug->log( 'running init_plugin action' ); 
  316.  
  317. do_action( 'ngfb_init_plugin' ); 
  318.  
  319. if ( $this->debug->enabled ) { 
  320. $this->debug->mark( 'plugin initialization' ); // end timer 
  321.  
  322. // runs at ngfb_init_textdomain priority -10 
  323. public static function init_textdomain( $debug_enabled ) { 
  324. if ( $debug_enabled ) { 
  325. add_filter( 'load_textdomain_mofile',  
  326. array( self::get_instance(), 'override_textdomain_mofile' ), 10, 3 ); 
  327. load_plugin_textdomain( 'nextgen-facebook', false, 'nextgen-facebook/languages/' ); 
  328.  
  329. // only runs when debug is enabled 
  330. public function override_textdomain_mofile( $wp_mofile, $domain ) { 
  331. if ( strpos( $domain, 'nextgen-facebook' ) === 0 ) { // optimize 
  332. foreach ( $this->cf['plugin'] as $ext => $info ) { 
  333. if ( $info['slug'] === $domain ) { 
  334. $constant_name = strtoupper( $ext ).'_PLUGINDIR'; 
  335. if ( defined( $constant_name ) && $plugin_dir = constant( $constant_name ) ) { 
  336. $plugin_mofile = $plugin_dir.'languages/'.basename( $wp_mofile ); 
  337. if ( $plugin_mofile !== $wp_mofile && is_readable( $plugin_mofile ) ) { 
  338. global $l10n; 
  339. unset( $l10n[$domain] ); // prevent merging 
  340. return $plugin_mofile; 
  341. break; // stop here 
  342. return $wp_mofile; 
  343.  
  344. // only runs when debug is enabled 
  345. public function show_debug() {  
  346. $this->debug->show_html( null, 'debug log' ); 
  347.  
  348. // only runs when debug is enabled 
  349. public function show_config() {  
  350.  
  351. if ( ! $this->debug->enabled ) { // just in case 
  352. return; 
  353.  
  354. // show constants 
  355. $defined_constants = get_defined_constants( true ); 
  356. $defined_constants['user']['NGFB_NONCE'] = '********'; 
  357.  
  358. if ( is_multisite() ) { 
  359. $this->debug->show_html( SucomUtil::preg_grep_keys( '/^(MULTISITE|^SUBDOMAIN_INSTALL|.*_SITE)$/',  
  360. $defined_constants['user'] ), 'multisite constants' ); 
  361.  
  362. $this->debug->show_html( SucomUtil::preg_grep_keys( '/^NGFB_/', $defined_constants['user'] ), 'ngfb constants' ); 
  363.  
  364. // show active plugins 
  365. $this->debug->show_html( print_r( SucomUtil::active_plugins(), true ), 'active plugins' ); 
  366.  
  367. // show available modules 
  368. $this->debug->show_html( print_r( $this->avail, true ), 'available features' ); 
  369.  
  370. // show all plugin options 
  371. $opts = $this->options; 
  372. foreach ( $opts as $key => $val ) { 
  373. switch ( $key ) { 
  374. case ( strpos( $key, '_js_' ) !== false ? true : false ): 
  375. case ( strpos( $key, '_css_' ) !== false ? true : false ): 
  376. case ( preg_match( '/(_css|_js|_html)$/', $key ) ? true : false ): 
  377. case ( preg_match( '/_(key|secret|tid|token)$/', $key ) ? true : false ): 
  378. $opts[$key] = '[removed]'; 
  379. break; 
  380. $this->debug->show_html( $opts, 'ngfb settings' ); 
  381.  
  382. global $ngfb; 
  383. $ngfb =& Ngfb::get_instance(); 
  384.  
  385. ?> 
.