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>