diff --git a/CRM/Ogp/Form/Settings.php b/CRM/Ogp/Form/Settings.php new file mode 100644 index 0000000000000000000000000000000000000000..75e46370d620abbd11095c269038383791ae8b95 --- /dev/null +++ b/CRM/Ogp/Form/Settings.php @@ -0,0 +1,78 @@ +<?php + +use CRM_Ogp_ExtensionUtil as E; + +/** + * Form controller class + * + * @see https://wiki.civicrm.org/confluence/display/CRMDOC/QuickForm+Reference + */ +class CRM_Ogp_Form_Settings extends CRM_Core_Form { + public function buildQuickForm() { + + // add form elements + $this->add( + 'select', // field type + 'favorite_color', // field name + 'Favorite Color', // field label + $this->getColorOptions(), // list of options + TRUE // is required + ); + $this->addButtons(array( + array( + 'type' => 'submit', + 'name' => E::ts('Submit'), + 'isDefault' => TRUE, + ), + )); + + // export form elements + $this->assign('elementNames', $this->getRenderableElementNames()); + parent::buildQuickForm(); + } + + public function postProcess() { + $values = $this->exportValues(); + $options = $this->getColorOptions(); + CRM_Core_Session::setStatus(E::ts('You picked color "%1"', array( + 1 => $options[$values['favorite_color']], + ))); + parent::postProcess(); + } + + public function getColorOptions() { + $options = array( + '' => E::ts('- select -'), + '#f00' => E::ts('Red'), + '#0f0' => E::ts('Green'), + '#00f' => E::ts('Blue'), + '#f0f' => E::ts('Purple'), + ); + foreach (array('1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e') as $f) { + $options["#{$f}{$f}{$f}"] = E::ts('Grey (%1)', array(1 => $f)); + } + return $options; + } + + /** + * Get the fields/elements defined in this form. + * + * @return array (string) + */ + public function getRenderableElementNames() { + // The _elements list includes some items which should not be + // auto-rendered in the loop -- such as "qfKey" and "buttons". These + // items don't have labels. We'll identify renderable by filtering on + // the 'label'. + $elementNames = array(); + foreach ($this->_elements as $element) { + /** @var HTML_QuickForm_Element $element */ + $label = $element->getLabel(); + if (!empty($label)) { + $elementNames[] = $element->getName(); + } + } + return $elementNames; + } + +} diff --git a/CRM/Ogp/Utils.php b/CRM/Ogp/Utils.php new file mode 100644 index 0000000000000000000000000000000000000000..5ad1128ed893968b8ef4aded09d1ce82f116072f --- /dev/null +++ b/CRM/Ogp/Utils.php @@ -0,0 +1,31 @@ +<?php + +class CRM_Ogp_Utils { + + /** + * Returns the default site logo, as configured in the settings. + */ + public static function getSiteLogo() { + if (CRM_Core_I18n::isMultilingual()) { + $tsLocale = CRM_Core_I18n::getLocale(); + return Civi::settings()->get('ogp_sitelogo_' . $tsLocale); + } + + return Civi::settings()->get('ogp_sitelogo'); + } + + /** + * Returns the default PCP page logo, as configured in the settings. + * Note that we use the block_id, since that is unique to both the + * contribution and event pages. + */ + public static function getPcpDefaultLogo($block_id) { + if (CRM_Core_I18n::isMultilingual()) { + $tsLocale = CRM_Core_I18n::getLocale(); + return Civi::settings()->get('ogp_pcp_' . $block_id . '_' . $tsLocale); + } + + return Civi::settings()->get('ogp_pcp_' . $block_id); + } + +} diff --git a/README.md b/README.md index 38b5d13d900f2ea23de96ab14e3caacf5d3091e7..2f050adc9ddeee06f6c110ffc18a11fc7891510b 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,13 @@ where you can share links. For more information: http://ogp.me/ -Once the extension is enabled, it will automatically generate the tags for -PCP pages, no further configuration is required. It supports the page -title and description. +Once the extension is enabled, it will automatically generate the og:description +tags for PCP pages (og:title is disabled for now, since usually provided by the CMS). +For PCP pages, it can also display the PCP logo. + +There are settings at `/civicrm/admin/setting/ogp` (todo: add menu item) where you +can configure a fallback site logo, fallback PCP page logo, etc. For example, Facebook +requires that images be minimum 200x200 pixels. This extension replaces the [civicrmogp](https://github.com/mlutfy/civicrmogp) Drupal-specific module. @@ -22,6 +26,10 @@ This extension is licensed under [AGPL-3.0](LICENSE.txt). Install as a regular CiviCRM extension. -## Known Issues +## Support + +Community issue tracking: +https://lab.civicrm.org/extensions/ogp/issues -It currently only supports Personal Campaign Pages (PCP). +Support also available from Coop Symbiotic: +https://www.symbiotic.coop/en diff --git a/ogp.php b/ogp.php index 7d39b92aaa9a9d46affe329bc612a8ee04c621fb..ab92e21873f92495630164047ee79f6dae02e8e4 100644 --- a/ogp.php +++ b/ogp.php @@ -87,19 +87,6 @@ function ogp_civicrm_managed(&$entities) { _ogp_civix_civicrm_managed($entities); } -/** - * Implements hook_civicrm_caseTypes(). - * - * Generate a list of case-types. - * - * Note: This hook only runs in CiviCRM 4.4+. - * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes - */ -function ogp_civicrm_caseTypes(&$caseTypes) { - _ogp_civix_civicrm_caseTypes($caseTypes); -} - /** * Implements hook_civicrm_angularModules(). * @@ -123,41 +110,62 @@ function ogp_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) { _ogp_civix_civicrm_alterSettingsFolders($metaDataFolders); } -/** - * Implements hook_civicrm_entityTypes(). - * - * Declare entity types provided by this module. - * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_entityTypes - */ -function ogp_civicrm_entityTypes(&$entityTypes) { - _ogp_civix_civicrm_entityTypes($entityTypes); +function ogp_civicrm_buildForm($formName, &$form) { + if ($formName == 'CRM_Contribute_Form_Contribution_Main') { + // og:title disabled for now, since the CMS should already generating this. + // CRM_Utils_System::addHTMLHead('<meta property="og:title" content="' . $form->_values['title'] . '">'); + + if ($image = CRM_Ogp_Utils::getSiteLogo()) { + CRM_Utils_System::addHTMLHead('<meta property="og:image" content="' . $image . '">'); + } + + $description = $form->_values['intro_text']; + $description = strip_tags($description); + $description = htmlspecialchars($description); + + CRM_Utils_System::addHTMLHead('<meta property="og:description" content="' . $description . '">'); + } } -// --- Functions below this ship commented out. Uncomment as required. --- +function ogp_civicrm_pageRun(&$page) { + $pageName = get_class($page); -/** - * Implements hook_civicrm_preProcess(). - * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_preProcess - * -function ogp_civicrm_preProcess($formName, &$form) { + if ($pageName == 'CRM_PCP_Page_PCPInfo') { + $id = $page->get('id'); -} // */ + $dao = new CRM_PCP_DAO_PCP(); + $dao->id = $id; -/** - * Implements hook_civicrm_navigationMenu(). - * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_navigationMenu - * -function ogp_civicrm_navigationMenu(&$menu) { - _ogp_civix_insert_navigation_menu($menu, 'Mailings', array( - 'label' => E::ts('New subliminal message'), - 'name' => 'mailing_subliminal_message', - 'url' => 'civicrm/mailing/subliminal', - 'permission' => 'access CiviMail', - 'operator' => 'OR', - 'separator' => 0, - )); - _ogp_civix_navigationMenu($menu); -} // */ + if ($dao->find(true)) { + $description = $dao->intro_text; + $description = strip_tags($description); + $description = htmlspecialchars($description); + + // Provided by the CMS? + // CRM_Utils_System::addHTMLHead('<meta property="og:title" content="' . $dao->title . '">'); + + CRM_Utils_System::addHTMLHead('<meta property="og:description" content="' . $description . '">'); + + // Add the PCP image + $entityFile = CRM_Core_BAO_File::getEntityFile('civicrm_pcp', $id); + + if (!empty($entityFile)) { + $fileInfo = reset($entityFile); + $fileId = $fileInfo['fileID']; + $fileHash = CRM_Core_BAO_File::generateFileHash($id, $fileId); + + // Using UF function adds language prefix and htmlencodes parameters.. breaks Facebook + $image = CRM_Utils_System::url('civicrm/file', "reset=1&id=$fileId&eid={$id}&fcs={$fileHash}", TRUE); + + // adds: <meta property="og:image" content="http://[...]" /> + CRM_Utils_System::addHTMLHead('<meta property="og:image" content="' . $image . '">'); + } + elseif ($image = CRM_Ogp_Utils::getPcpDefaultLogo($dao->pcp_block_id)) { + CRM_Utils_System::addHTMLHead('<meta property="og:image" content="' . $image . '">'); + } + elseif ($image = CRM_Ogp_Utils::getSiteLogo()) { + CRM_Utils_System::addHTMLHead('<meta property="og:image" content="' . $image . '">'); + } + } + } +} diff --git a/settings/ogp.setting.php b/settings/ogp.setting.php new file mode 100644 index 0000000000000000000000000000000000000000..64c5763f83d363ea3be638fa85587c75a54f8a11 --- /dev/null +++ b/settings/ogp.setting.php @@ -0,0 +1,108 @@ +<?php + +use CRM_Ogp_ExtensionUtil as E; + +$settings = []; +$weight = 10; + +if (CRM_Core_I18n::isMultilingual()) { + $languages = CRM_Core_I18n::languages(true); + + foreach ($languages as $key => $label) { + $settings['ogp_sitelogo_' . $key] = [ + 'name' => 'ogp_sitelogo_' . $key, + 'type' => 'String', + 'default' => null, + 'html_type' => 'text', + 'add' => '1.0', + 'title' => E::ts('Default site logo (%1)', [1 => $label]), + 'description' => E::ts('Enter the full URL to the image, ex: http://example.org/logo.png - It might be a different logo than the logo displayed on your website, because Facebook requires that the image be at least 200x200 pixels.'), + 'is_domain' => 1, + 'is_contact' => 0, + 'settings_pages' => [ + 'ogp' => [ + 'weight' => $weight++, + ], + ], + ]; + } +} +else { + $settings['ogp_sitelogo'] = [ + 'name' => 'ogp_sitelogo', + 'type' => 'String', + 'default' => null, + 'html_type' => 'text', + 'add' => '1.0', + 'title' => E::ts('Default site logo'), + 'description' => E::ts('Enter the full URL to the image, ex: http://example.org/logo.png - It might be a different logo than the logo displayed on your website, because Facebook requires that the image be at least 200x200 pixels.'), + 'is_domain' => 1, + 'is_contact' => 0, + 'settings_pages' => [ + 'ogp' => [ + 'weight' => $weight++, + ], + ], + ]; +} + +$pcp_pages = []; + +// TODO move to a function +$dao = CRM_Core_DAO::executeQuery("select p.id, cp.title from civicrm_pcp_block as p left join civicrm_contribution_page cp on (cp.id = p.target_entity_id) where p.target_entity_type = 'contribute' and p.is_active = 1"); + +while ($dao->fetch()) { + $pcp_pages[$dao->id] = $dao->title; +} + +// events +$dao = CRM_Core_DAO::executeQuery("select p.id, cp.title from civicrm_pcp_block as p left join civicrm_contribution_page cp on (cp.id = p.target_entity_id) where p.target_entity_type = 'event' and p.is_active = 1"); + +while ($dao->fetch()) { + $pcp_pages[$dao->id] = $dao->title; +} + +if (CRM_Core_I18n::isMultilingual()) { + $languages = CRM_Core_I18n::languages(true); + + foreach ($pcp_pages as $pcp_id => $title) { + foreach ($languages as $lang => $langlabel) { + $settings['ogp_pcp_' . $pcp_id . '_' . $lang] = [ + 'name' => 'ogp_pcp_' . $pcp_id . '_' . $lang, + 'type' => 'String', + 'default' => null, + 'html_type' => 'text', + 'add' => '1.0', + 'title' => E::ts('Default PCP logo for: %1 (%2)', [1 => $title, 2 => $langlabel]), + 'is_domain' => 1, + 'is_contact' => 0, + 'settings_pages' => [ + 'ogp' => [ + 'weight' => $weight++, + ], + ], + ]; + } + } +} +else { + foreach ($pcp_pages as $pcp_id => $title) { + $settings['ogp_pcp_' . $pcp_id] = [ + 'name' => 'ogp_pcp_' . $pcp_id, + 'type' => 'String', + 'default' => null, + 'html_type' => 'text', + 'add' => '1.0', + 'title' => E::ts('Default PCP logo for: %1', [1 => $title]), + 'is_domain' => 1, + 'is_contact' => 0, + 'settings_pages' => [ + 'ogp' => [ + 'weight' => $weight++, + ], + ], + ]; + } +} + +return $settings; diff --git a/xml/Menu/ogp.xml b/xml/Menu/ogp.xml new file mode 100644 index 0000000000000000000000000000000000000000..3de190e609e7cf65a2f06ca51e04b953aacc4b6b --- /dev/null +++ b/xml/Menu/ogp.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<menu> + <item> + <path>civicrm/admin/setting/ogp</path> + <page_callback>CRM_Admin_Form_Generic</page_callback> + <title>Open Graph Protocol (OGP) Settings</title> + <access_arguments>administer CiviCRM</access_arguments> + </item> +</menu>