hypeJunction

Build modern social media applications with an ever-growing collection of high-quality plugins for Elgg 3+

Installation

Using ZIP files

Distribution (.zip) plugin files can be downloaded from hypeJunction website. To add a plugin, unzip it into your /mod directory, making sure the directories are not nested, and that manifest.xml is in the root of the plugin folder.

Using Composer

To use composer, you need to have an active subscription that gives you access to individual packages.

## Add your satis credentials to global config
## You can find your username and token by logging into https://hypejunction.com/ and navigating to one of the downloads.

composer config --global --auth http-basic.hypejunction.com <username> <token>

Update your composer.json to include:

"repositories": [
    {
        "type": "composer",
        "url": "https://hypejunction.com/satis"
    }
]

New Project

The easiest way to create an Elgg project with hypeJunction plugins installed is by running the following commands.

## Create a new Elgg project with hypeJunction Pro plugins pre-installed

composer create-project hypejunction/hypejunction:dev-master ./project-name

cd ./project-name

composer install
composer install # 2nd call is currently required

./elgg-cli install
./elgg-cli plugins:activate hypeCli
./elgg-cli hypejunction:install

Existing Project

You can add plugins to an existing project, using

composer require hypejunction/<plugin_name>

Additional Info

Learn about installation in Elgg docs.

hypeActivity

Replaces profile pages with an activity stream

  • Activity streams as main attribute of the profile page
  • Extendable with custom modules/widgets

hypeAjax

Utilities for AJAX requests

  • Deferred view rendering

Developer Notes

Deferred Rendering

To defer view rendering, simply add 'deferred' => true to view vars.

echo elgg_view('my_view', [
   // tells the view system to defer view render
   'deferred' => true,

   // if set to false, placeholder will not be rendered
   // if set to a value, that value will be used as the placeholder
   // if not set, default ajax loader will be used
   'placeholder' => false,

   // you can pass other view vars, as you would with normal views
   // various Elgg data will be serialized and available to the deferred view
   // some of the values may need to be wrapped into a Serializable instance
   'entity' => get_entity(123),
   'user' => get_user(234),
]);

hypeAttachments

  • API and UI for attaching files and other entities
  • Form input for uploading file attachments
  • Views for displaying attachments

Register allowed subtypes

If you add your entity subtype to a list of entities supporting attachments, the plugin will attempt to create all of the UI, necessary to upload and display attachments:

elgg_register_plugin_hook_handler('allow_attachments', 'object:my_subtype', '\Elgg\Values::getTrue');

Note that this generic approach might not work with all plugins, and may require additional customizations on your side.

Display an attachment input

echo elgg_view('input/attachments');

To add an attachments input to your comment and discussion replies forms, use the following code. You will not need to add any code to your save action.

echo elgg_view('input/attachments', [
   'name' => 'comment_attachments',
]);

To add an attachments input to your personal messages and replies forms, use the following code. You will not need to add any code to your save action.

echo elgg_view('input/attachments', [
   'name' => 'message_attachments',
]);

Note that if you are not using hypeDropzone, your form must have it’s encoding set to multipart/form-data.

Attach uploaded files in an action

hypeapps_attach_uploaded_files($entity, 'upload', [
   'access_id' => $entity->access_id, // change the access level of uploaded files
]);

Attach an object

hypeapps_attach($entity, $attachment);

Display attachments

echo elgg_view('output/attachments', [
   'entity' => $entity,
]);

Acknowledgements

hypeAutocomplete

Autocomplete input

  • Replaces selects with autocomplete inputs that support images and icons
  • Adds typeahead support for tags input
  • Replaces autocomplete and userpicker inputs
  • Adds versatile input/guids

hypeBlog

Customized blog

  • Uses extendable form interface
  • Rich-media oriented

hypeBraintreePayments

A wrapper for Braintree’s PHP SDK

Webhooks

Configure your Braintree application to send webhooks to `https://<your-elgg-site>/payments/braintree/webhooks`

To digest a webhook, register a plugin hook handler:

elgg_register_plugin_hook_handler('subscription_went_past_due', 'braintree', HandleExpiredSubscription::class);

class HandleExpiredSubscription {
   public function __invoke(\Elgg\Hook $hook) {
      $webhook = $hook->getParam('webhook');
      /* @var $webhook \Briantree\WebhookNotification */

      // ... do stuff

      return $result; // data to send back to braintree
   }
}

Card Input

To display a card input:

// Card number, expiry and CVC
echo elgg_view_field([
   '#type' => 'braintree/card',
   '#label' => 'Credit or Debit Card',
   'required' => true,
]);

You can then retrieve the value of the Braintree token in your action:

$token = get_input('braintree_token'); // Corresponds to payment_method_nonce

elgg()->{'payments.gateways.braintree'}->pay($transaction, [
   'braintree_token' => $token,
]);

hypeBraintreeSubscriptions

Braintree integration for hypeSubscriptions

Currencies

If you are using multiple currencies, make sure to set up a Braintree merchant account for each currency.

Subscriptions

Braintree API does not allow plans to be created via API calls, so you will need to setup your plans via Braintree control panel and then import them. Plans will be matched by their plan_id, so you can duplicate your existing plans on Braintree.

hypeCapabilities

Capabilities and roles API

Registering a role

elgg()->roles->register('role_name');

Assigning a role to a user

// Site wide role
elgg()->roles->assign('role_name', $user);

// Group specific role
elgg()->roles->assign('role_name', $user, $group);

Remove a role from a user

// Site wide role
elgg()->roles->unassign('role_name', $user);

// Group specific role
elgg()->roles->unassign('role_name', $user, $group);

Configuring role permissions

Creating entities of a specific type

// Prevent users with given role from creating entities of a given type
elgg()->roles->role_name->onCreate('object', 'blog', Role::DENY);

// Allow users to create entities of a given type regardless of context
elgg()->roles->role_name->onCreate('object', 'blog', Role::ALLOW, Role::OVERRIDE);

// Allow users to create entities of a given type if all other container permissins are met
elgg()->roles->role_name->onCreate('object', 'blog', Role::ALLOW, Role::STACK);

// Allow users to create entities when specific conditions are met
// Only allow group blogs
elgg()->roles->role_name->onCreate('object', 'blog', Role::DENY, function(\hypeJunction\Capabilities\Context $context) {
   $container = $context->getTarget();
   if (!$container instanceof ElggGroup) {
      return Role::DENY;
   }
});

Update and delete permissions

Similar to above, you can use `onUpdate` and `onDelete` methods;

Granting administrative permissions

Administrative permissions imply high-level administrative action on entities, e.g. approving a certain post after moderation. By default, core does not use this privilege level, but you can check if the user has admin permissions over an entity like so:

$params = [
   'entity' => $entity,
   'user' => $user,
];
if (!elgg_trigger_plugin_hook('permissions_check:administer', "$entity->type:$entity->subtype", $params, false)) {
   // No permissions to approve
   throw new EntityPermissionsException();
}

// Do something that requires high level permissions, e.g.
$entity->published_status = 'published';

Granting/denying admin permissions

// Prevent users with given role from creating entities of a given type
// Allow moderator role to administer all blogs regardless of owner/container
elgg()->roles->moderator->onAdminister('object', 'blog', Role::ALLOW, Role::OVERRIDE);

// Allow users to create entities when specific conditions are met
// Allow teacher to administer all group blogs
elgg()->roles->teacher->canAdminister('object', 'blog', Role::ALLOW, function(\hypeJunction\Capabilities\Context $context) {
   $entity = $context->getTarget();
   $actor = $context->getActor();

   $container = $entity->getContainerEntity();
   return $container->canEdit($actor->guid);
});

Routes

You can allow/deny access to certain routes by route name

// Context parameter contain matched route elements
// e.g. prevent access to user profile if users are not friends
elgg()->roles->user->onRouteAccess('view:user', Role::DENY, function(\hypeJunction\Capabilities\Context $context) {
   $actor = $context->getActor();

   $username = $context->getParam('username');
   $user = get_user_by_username($username);

   if (!$actor || !$user instanceof ElggUser || !$actor->isFriendOf($user->guid)) {
      register_error('You must be friends to access user profiles');
      return Role::DENY;
   }
});

// Here is an example of how to prevent access to member pages to non-logged in users:
elgg()->roles->guest->onRouteAccess('collection:user:user', Role::DENY);
elgg()->roles->guest->onRouteAccess('collection:user:user:alpha', Role::DENY);
elgg()->roles->guest->onRouteAccess('collection:user:user:newest', Role::DENY);
elgg()->roles->guest->onRouteAccess('collection:user:user:online', Role::DENY);
elgg()->roles->guest->onRouteAccess('collection:user:user:popular', Role::DENY);
elgg()->roles->guest->onRouteAccess('search:user:user', Role::DENY);
elgg()->roles->guest->onRouteAccess('view:user', Role::DENY);

Custom (component) capabilities

You can check and alter custom capabilities:

// Check a custom role
elgg()->roles->can('read', 'discussions');

// Define how role responds to capability check
elgg()->roles->guest->on('read', 'discussions', Role::DENY);

// Override role response
elgg_register_plugin_hook_handler('capability', 'read:discussions', function(Hook $hook) {

});

hypeCaptcha

Protects the site from bots using reCaptcha

Usage

echo elgg_view_field(['#type' => 'captcha']);

Users are only requested to solve a captcha one. If they proved they are human, they won’t be bothered again.

hypeCli

CLI tools for working with hypeJunction plugins

Commands

`elgg-cli hypejunction:install [--pack|-p]`

Install all plugins within a pack.

Packs include:

core - plugins that most other plugins depend on content - plugins for authoring content tools - various site tools theming - theming tools commerce - payments and subscriptions

hypeCountries

Country utilities

  • Country info, including name, ISO, ISO-3, ISO numeric, FIPS, TLD, currency code, postal code format and other
  • Country input view

Country select

echo elgg_view('input/country', array(
   'name' => 'country',
   'value' => 'CZ',
));

List countries

$countries = elgg()->countries->getCountries();
foreach ($countries as $country) {
   /* @var $country \hypeJunction\Country */
   echo "$country->name ($country->iso)";
}

Country info

Get a list of countries with extended details

$fields = array(
   'name',
   'iso',
   'iso3',
   //'iso_numeric',
   //'fips',
   'capital',
   //'area',
   //'population',
   //'continent',
   'tld',
   'currency_code',
   'currency_name',
   'phone_code',
   'postal_code_format',
   'postal_code_regex',
   'languages',
   //'geoname_id',
   'neighbours'
);

// Get a list of countries ordered by currency_code
$countries = elgg_get_country_info($fields, 'currency_code');

hypeDiscussions

  • Implements threaded discussions (using comment system)
  • Integrates with hypeInteractions for real time updates
  • Enables replies from river
  • Adds attachments to discussions (requires hypeAttachments)
  • Adds discussions widget to the group and user profile
  • Restricted discussion (only group admins can start new discussions)
  • Enables discussions outside of groups

hypeDownloads

Digital product downloads

hypeDraft

Implements a publishing workflow for content items.

  • Allow users to save draft posts hidden from other users
  • Autosave posts
  • Maintain revision history

hypeDropzone

Drag&Drop File Uploads for Elgg

  • Cross-browser support for drag&drop file uploads
  • Easy to integrate into existing forms
  • Supports chunked uploads of large files

Adding a drag&drop file input and processing uploads

To add a drag&drop input to your form, add the following:

echo elgg_view('input/dropzone', array(
      'name' => 'upload_guids',
      'accept' => "image/*",
      'max' => 25,
      'multiple' => true,
      'container_guid' => $container_guid, // optional file container
      'subtype' => $subtype, // subtype of the file entities to be created
      // see the view for more options
));

In your action, you can retrieve uploaded files with `get_input('upload_guids');`

You also need to implement a fallback solution for when the browser does not support drag and drop. Check hypeJunction\DropzoneService for an example.

Initializing and resetting dropzone

You can instantiate and clear dropzone by triggering jQuery events on the containing form:

$('.elgg-form').trigger('initialize'); // will instantiate dropzone inputs contained within the form
$('.elgg-form').trigger('reset'); // will clear previews and hidden guid inputs

Acknowledgements

  • Dropzone.js is a really cool library by Matias Meno

http://www.dropzonejs.com/

hypeEmbed

  • Search, upload and embed files on the spot
  • Search and embed all other registered object types on the spot
  • Embed URL previews and rich-media players
  • [admin] Embed buttons that match the site styles
  • [admin] Embed “insecure” HTML embeds (forms, calendars etc)

Shortcodes

The plugin supports the following shortcodes:

embed shortcode:

  • guid - GUID of an entity to embed

button shortcode:

  • text - call to action
  • type - One of the following types action, submit, delete, cancel (these values only affect styling and do not carry any functional value)
  • url - URL to link to
  • target - Default self, blank or lightbox

Examples:

[embed guid="555"]
[button type="action" text="Read Terms" url="/terms" target="lightbox"]

Unlisted shortcode attributes will be parsed and passed to the view after sanitization, so extending plugins can add additional options.

By default, only shortcodes passed to output/longtext view will be expanded automatically.

Static assets

If you are using the same images across multiple posts, you may way to use static assets, as they allow you to take advantage of simplecache, thus offering better performance than file entities.

Create a folder in your dataroot /embed/ and place your image files in there, flush the caches, and you will see your images in the Assets tab of the embed lightbox window.

Acknowledgements

  • Upgrade for Elgg 2.3 has been sponsored by ApostleTree, LLC

hypeGroups

  • Extended search and sort functionality
  • API to add new group subtypes
  • API to manage group hierarchies
  • API for managing group fields
  • API for restricting group tools, as well as using preset tools

Group Subtypes

Registering new subtypes and configuring them is made easy.

Here is an example of how to remove groups from the top level of the site, and making them subgroups of a new subtype called classroom.

     $svc = elgg()->groups;
     /* @var $svc \hypeJunction\Groups\GroupsService */

     $svc->registerSubtype('classroom', [
             'labels' => [
                     'en' => [
                             'item' => 'Classroom',
                             'collection' => 'Classrooms',
                     ],
             ],
             'root' => true,
             'identifier' => 'classrooms',
             'class' => \CustomPlugin\Classroom::class,
             'collections' => [
                     'all' => \CustomPlugin\DefaultClassroomCollection::class,
                     'owner' => \CustomPlugin\OwnedClassroomCollection::class,
                     'member' => \CustomPlugin\JoinedClassroomCollection::class,
             ],
     ]);

     $svc->registerSubtype('group', [
   'site_menu' => false,
             'labels' => [
                     'en' => [
                             'item' => 'Group',
                             'collection' => 'Groups',
                     ],
             ],
             'root' => false,
             'parents' => ['classroom'],
             'identifier' => 'groups',
]);

You can put multiple subtypes into a collection by assigning them to the same identifier, e.g. you could create usa_state and canada_province subtypes and register them for regions identifier.

Fields

Fields are managed by hypePost. Please see the documentation there for more information.

hypeHero

Replaces owner block with a hero

hypeIllustration

Unsplash integration

hypeInteractions

Enhanced commenting and liking UX for Elgg

  • Extendable interactions module
  • Real-time comments and likes (requires hypeLists)
  • Comment attachments (requires hypeAttachments)
  • Multi-level comment threads
  • Inline comment search (requires hypeLists)
  • Inline comment sorting (requires hypeLists)

hypeInvite

  • Allows users to invite new users by email
  • An option to create an invite-only network
  • Keeps track of all invitations to the same email address
  • Creates friend requests when invitations are accepted
  • Group owners can allow members to invite other members
  • Site admins can allow group invitations of non-friends
  • Site admins can allow group invitations by email

Gotchas

  • Registration must be enabled on the site for this plugin to work
  • In an invite-only network, uservalidationbyemail will be bypassed, as it is assumed that users would have received their invitation code by email
  • When invited by email to group, non-existing users will first have to create an account. Upon registration, invitations will be created for every group the email has been invited to before registration.

Creating Invites

Other plugins may centralize off-site invitations and attach custom behavior to the invites. For example, to invite non-registered users to an event by their email:

$invite = users_invite_create_user_invite($email);
add_entity_relationship($invite->guid, 'invited_to', $event->guid);
add_entity_relationship($invite->guid, 'invited_by', $inviter->guid);

// generate a registration link to include in the notification
$registration_link = users_invite_get_registration_link($email, $inviter->guid);


// implement a custom handler
elgg_register_plugin_hook_handler('accept', 'invite', function($hook, $type, $return, $params) {

   $invite = $params['invite'];
   $user = $params['user'];

   $events = elgg_get_entities_from_relationship([
        'types' => 'object',
        'subtypes' => 'event',
      'relationship' => 'invited_to',
      'relationship_guid' => $invite->guid,
      'limit' => 0,
   ]);

   if (!$events) {
      return;
   }

   foreach ($events as $event) {
      add_entity_relationship($user->guid, 'attending', $event->guid);
   }
});

hypeLists

A set of tools that improve UX and simplify common list patterns for developers.

  • Seamless integration with core and existing plugins
  • AJAXed list pagination and infinite scroll
  • Lazy loading of preceeding and succeeding list pages
  • Auto refreshing of lists
  • An interface for creating sortable/searchable lists

Server-Side

The following options are accepted by `elgg_list_entities()`, `elgg_view_entity_list()`, and by `page/components/list` and `page/components/gallery` views. These parameters will only take effect, if you have `'pagination' => true` in your options. Additional options, that need to be passed to the jQuery plugin, can be prefixed with `data-`

  • `'list_id'` STRING is an optional parameter, but it is strongly recommended to pass it to your list. List id must be unique to the page.
  • `'pagination_type'` STRING `default` (pagination bar with page number navigation) or `infinite` (before and after navigation)
  • `'position'` STRING can be used to specify the position of pagination items. `before`, `after`, `both`
  • `'num_pages'` INT can be used to specify how many page number navigation items to show, use 0 to only show Next and Prev links
  • `'lazy_load'` INT can be used to initialize lazy loading of pages
  • `'auto_refresh'` INT can be used to specify at which interval in seconds new items should be fetched
  • `'reversed'` BOOL can be used to specify reversed lists. If list is reversed, it is assumed that the new items will be located at the end of the list

Client-Side

Lists that have received the necessary parameters server-side will be instantiated automatically. If you need to instantiate a list programmatically, use `$.hypeList(options)`.

// Instantiate a new list
$('.elgg-list.my-list').hypeList({
      baseUrl: false, // Data source
      count: 0, // Number of items in the list
      offset: 0, // Current offset from the beginning of the list
      offsetKey: 'offset', // Offset key
      limit: 10, // Number of items per page
      listId: '', // List identifier unique to the page
      pagination: 'default', // Pagination type: 'default', 'infinite'
      paginationPosition: 'after', // Pagination position: 'before', 'after', 'both'
      paginationNumPages: 10, // Number of page links to display in the pager
      classActive: 'elgg-state-selected', // CSS class pertinent to active elements
      classDisabled: 'elgg-state-disabled', // CSS class pertinent to disabled elements
      classLoading: 'elgg-state-loading', // CSS class pertinent to pending elements
      textNoResults: '', // Text displayed when no items were found in the list
      textNext: elgg.echo('next'), // Text for next link
      textPrev: elgg.echo('previous'), // Text for previous link
      keyTextBefore: 'lists:add:before', // Language key for before link (will receive limit as parameter)
      keyTextAfter: 'lists:add:after', // Language key for before link (will receive limit as parameter)
      lazyLoad: 10, // Number of pages to lazy load
      autoRefresh: 60, // Fetch new items at this interval (in seconds)
      reversed: false, // List is reversed that is new items are appended to the end of the list
      scrollTopOffset: -100, // Additional offset in pixels for when the page is scrolled to the top of the list
      listTime: 0, // Timestamp at which the list was generated, sent with AJAX requests
      showEffect: 'highlight', // jQuery UI effect used for toggling item visibility
      selectorDelete: '.elgg-menu-item-delete > a', // CSS selector of an anchor that will trigger a delete action
});

// Public methods

// Navigate to a page with a certain index
// For default pagination type, page with pageIndex is loaded and displayed
// For infinite pagination type, all pages in range from currently visible pages to the page with pageIndex are loaded and displayed
$('.elgg-list').trigger('goToPage', [pageIndex]);

// Trigger refresh
// Reloads the page and appends new items if any
// If no pageIndex is provided, it's determined by pagination type
// goToPage parameter can be used to navigate to the page once new items have been fetched
// goToPage flag is useful when a new post was made and you want to display the post to the user
$('.elgg-list').trigger('fetchNewItems', [pageIndex, goToPage]);

// Remove items from the list and reindex
$('.elgg-list').trigger('removeItems', [$items]);

// Add new items to the list
$('.elgg-list').trigger('addFetchedItems', [ajaxData]);


// Events

// Event triggered whenever the list is first rendered
// Callback will receive list options as a second parameter
$('.elgg-list').on('ready', callback);

// Event triggered whenever an item is added, removed or hidden from a list
// Callback will receive list options as a second parameter
$('.elgg-list').on('change', callback);

hypeMapsOpen

API and UI for maps built with open technology

  • Geocoding and reverse geocoding via Nominatim
  • Maps built with Leaflet.js
  • Default map tiles provided by Open Street Maps (customizagle in views)
  • User map
  • Groups map
  • Group members map

A map of arbitrary locations

echo elgg_view('page/components/map', [
   'markers' => [
      'Berlin, Germany',
      'London, UK',
      'Paris, France',
   ]
]);

A map with custom icons

$berlin = hypeJunction\MapsOpen\Marker::fromLocation('Berlin, Germany');
$berlin->icon = 'smile-o';
$berlin->color = 'green';
$berlin->tooltip = '<b>Berlin is a happy place</b>';

$paris = hypeJunction\MapsOpen\Marker::fromLocation('Paris, France');
$paris->icon = 'coffee';
$paris->color = 'black';
$paris->tooltip = '<img src="https://s-media-cache-ak0.pinimg.com/736x/ca/ea/57/caea57268e1dee696f3c20a5a0f895f2.jpg" alt="Paris" />';

echo elgg_view('page/components/map', [
   'markers' => [
      $berlin,
      $paris,
   ],
]);

A map of entities

echo elgg_view('page/components/map', [
   'markers' => elgg_get_entities_from_metadata([
      'types' => 'object',
      'subtypes' => 'place',
      'metadata_name_value_pairs' => [
         'venue_type' => 'cafe',
      ],
      'limit' => 0,
   ]),
   'center' => hypeJunction\MapsOpen\Marker::fromLocation('London, UK');
]);

Change marker icon and color

Use ‘marker’,’<entity_type>’ hook. Supported colors: ‘red’, ‘darkred’, ‘orange’, ‘green’, ‘darkgreen’, ‘blue’, ‘purple’, ‘darkpuple’, ‘cadetblue’

elgg_register_plugin_hook_handler('marker', 'object', function($hook, $type, $return, $params) {

   $entity = elgg_extract('entity', $params);

   if ($entity instanceof Event) {
      $return->icon = 'calendar';
      $return->color = 'darkpurple'
   }

   return $return;
})

Change popup content

Add a view for maps/tooltip/<entity_type>/<entity_subtype> or maps/tooltip/<entity_type>/default;

Acknowledgements

hypeMedia

Media albums

  • Support for image and video files
  • Support for image and video embed via URLs

hypeMentions

Mentions

  • Allows mentioning users and groups in various text fields @username
  • Hashtag autocomplete #hashtag
  • Emoji support :heart:

Acknowledgements

hypeMenus

Menu editor

  • Add/remove items from menus using admin interface
  • Easily customize menu icons, text, tooltip, URL
  • Drag&Drop reordering of menu items and children
  • Easily add new menu sections
  • Build dynamic URLs using extrapolation or linking an item to an entity

hypeModerator

Implements moderator role

Approval Workflow

Approval workflow only works with entities that use publish event.

To queue entities for approval use a hook handler:

elgg_register_plugin_hook_handler('uses:moderation', 'object:<entity_subtype>`, '\Elgg\Values::getTrue`);

hypeNotifications

  • Facebook-style site notifications
  • Email digest: users can specify at which interval they receive notifications for each type
  • A tool to update preferred notification methods for all site users
  • Leverages Zend_Mail (email library used in core) to send out HTML emails
  • Allows to configure email transports (Sendmail, SMTP, File Transport, SendGrid, Mailgun, SparkPost)
  • Allows to send file attachments
  • Inlines CSS styles for improved email client experience
  • Simpler testing experience: catch all email address, email/domain whitelist

Notification preferences

Go to Admin > Administer > Utilities > Notification Methods to update personal and subscription notification preferences globally.

Notification event types

Notification event types can be filtered using 'notification_events','notifications' hook. Users will be given an option to unsubscribe from notifications about these events or batch them into a digest. Note that some instant notification events should not be added this list, e.g. password reset and other account related notifications should remain instant.

Notification testing

You can disable outgoing email by switching to File Transport in plugin settings, this will instead write email as txt files to the filestore under /notifications_log/zend/

Sample SMTP config for GMail

To use GMail as your SMTP relay, you will likely need to Allow less secure apps: https://support.google.com/accounts/answer/6010255?hl=en

  • Host: smtp.gmail.com
  • Port: 587
  • Secure Connection: TLS
  • Auth: SMTP with AUTH LOGIN
  • Username: <your gmail email>
  • Password: <your gmail password>

Sample SMTP config for SendGrid

  • Host: smtp.sendgrid.com
  • Port: 587
  • Secure Connection: TLS
  • Auth: SMTP with AUTH LOGIN
  • Username: apikey
  • Password: <your api key>

File Attachments

To add attachments to your email, add an array of ElggFile objects to notification parameters:

notify_user($to, $from, $subject, $body, array(
   'attachments' => array(
      $file1, $file2,
   )
));

hypePayments

  • Standardized API for handling payments and product sales
  • Interface for logging and refunding payments

New payment

namespace hypeJunction\Payments;

// First, we create an itemized order/invoice
$order = new Order();
$order->setCurrency('EUR');

// Add a new product
$order->add($product, 2);

// Add additional fees and charges
$shipping = Amount::fromString('25.25', 'EUR');
$charges[] = new ShippingFee('shipping', 0, $shipping);

$charges[] = new ProcessingFee('paypal_fee', 3.9);

$order->setCharges($charges);

$address = new Address();
$address->street_address = 'Some street 25';
// add other address parts
$address->country_code = 'CZ';

$order->setShippingAddress($address);

// Now create a transaction
$transaction = new Transaction();
$transaction->setOrder($order);
$transaction->setPaymentMethod('paypal');

// Be sure to correctly set the owner and container and access id
// to ensure that both the merchant and the customer have access
// to the transaction entity
$transaction->owner_guid = $payer->guid;
$transaction->container_guid = $payee->guid;

// You can use access_grant to give access to the merchant,
// or create a new acccess collection that contains both the payer and the payee
$transaction->access_id = ACCESS_PRIVATE;

$transaction->save();

// Instantiate a gateway of choice
$gateway = new \hypeJunction\PayPal\API\Adapter();

// What you do with response may depend on where you are executing
// this code. From an action file, you can just return the $response.
$response = $adapter->pay($transaction);

hypePaypalPayments

A wrapper for Paypal’s PHP SDK

Webhooks

Configure your Paypal application to send webhooks to `https://<your-elgg-site>/payments/paypal/webhooks`

To digest a webhook, register a plugin hook handler:

elgg_register_plugin_hook_handler('BILLING.SUBSCRIPTION.EXPIRED', 'paypal', HandleExpiredSubscription::class);

class HandleExpiredSubscription {
   public function __invoke(\Elgg\Hook $hook) {
      $webhook_data = $hook->getParam('data');

      // ... do stuff

      return $result; // Result will be reported back to paypal
   }
}

Paypal Button

To display a pay button:

echo elgg_view_field([
   '#type' => 'paypal/paypal',
   'required' => true,
]);

You can then retrieve the value of the Paypal’s payment and payer ID your action:

$payment_id = get_input('paypal_payment_id');
$payer_id = get_input('payer_id');

elgg()->{'payments.gateways.paypal'}->pay($transaction, [
   'paypal_payment_id' => $payment_id,
   'paypal_payer_id' => $payer_id,
]);

hypePaypalSubscriptions

Paypal integration for hypeSubscriptions

Disclaimer

PayPal sucks and so does its API. I have written this plugin to test the flexibility of the subscriptions API. Personally, I would discourage anyone from using PayPal, until they get their act together, hire an army of developers and get up to speed with the developments in the financial e-services.

During testing, I have noticed that PayPal doesn’t properly synchronize payment information with billing agreements, so it’s really impossible to keep track of changes in real-time. You may end up having to manually consolidate transactions and refunds.

hypePost

Provides utilities for creating and editing posts.

Extendable form fields Post forms are built using an extended field API layer, which makes it easier to define all fields in one place, and not have to worry about maintaining form, action and profile logic separate from each other.

Reusable views Plugins can recycle existing resource views, saving lots of time needed to bootstrap new entity types.

Client site validation Client side form validation

AJAX form save Forms are saved using AJAX with saves user a few steps should the action fail.

Form Fields

To extend post form, use fields, <entity_type>:<entity_subtype> (or less granular fields, <entity_type> ) plugin hook.

The hook receives an instance of \hypeJunction\Fields\Collection, which allows you to easily manipulate fields:

elgg_register_plugin_hook_handler('fields', 'object:blog', function(\Elgg\Hook $hook) {

   $fields = $hook->getValue();
   /* @var $fields \hypeJunction\Fields\Collection */

   $fields->add('published_date', new MetaField([
      'type' => 'date',
      'required' => true,
   ]);

   $fields->get('description')->required = false;

   return $fields;
});

Common Properties

Icons

To enable or disable icons, use uses:icon, <entity_type>:<entity_subtype> hook. The handler should return true or false

Cover Images

To enable or disable cover images, use uses:cover, <entity_type>:<entity_subtype> hook. The handler should return true or false

Comments

To enable or disable comments, use uses:comments, <entity_type>:<entity_subtype> hook. The handler should return true or false

hypePaywall

  • Restrict access to content items to paying site members
  • Restrict downloads to paying site members
  • Allow access with to content and downloads with one-off payments

hypeProfile

  • Extended member search and sort functionality
  • API for managing profile and registration fields
  • API for adding fields to search
  • Registration form validation
  • Admin options to simplify registration form
  • An option to validate email before account is created

hypeSatis

Allows hosting composer repository with private repositories as part of the Elgg site, extending hypeDownloads plugin.

Satis Build

To build Satis composer repository:

vendor/bin/elgg-cli satis:build

You may want to configure a cron job to run this command to pull in new versions of packages at a given interval.

Client Setup

First, add username and token of the Elgg account to the client server:

composer global config http-basic.{{host}} {{username}} {{token}}

In composer.json of the client project add:

{
    "repositories": [
        {
            "type": "composer",
            "url": "https://{{host}}/satis"
        }
    ]
}

Where:

  • {{host}} is the hostname of your Elgg installation
  • {{username}} is the username of the Elgg user
  • {{token}} is the password of the Elgg user

hypeScraper

A tool for scraping, caching and embedding remote resources.

  • Scrapes URLs and turns them in responsive preview cards
  • Aggressive caching of scraped resources for enhanced performance
  • Linkifies #hashtags, @usernames, links and emails

Card

To display a URL card with an image preview, title and brief description, use output/card view:

echo elgg_view('output/card', array(
   'href' => 'https://www.youtube.com/watch?v=Dlf1_vuIR4I',
));

Player

To dipslay a rich media player use output/player view:

echo elgg_view('output/player', array(
   'href' => 'https://www.youtube.com/watch?v=Dlf1_vuIR4I',
));

Linkify

To linkify all URLs, usernames, emails and hashtags that are not wrapped in html tags, use `output/linkify` view. Pass your text in a `value` parameter. You can use `parse_` flags to skip certain qualifiers.

$text = '@someone needs to #linkify this article http://example.com and email it to someone@example.com';
if (elgg_view_exists('output/linkify')) {
   $text = elgg_view('output/linkify', array(
      'value' => $text,
      //'parse_urls' => false,
      //'parse_hashtags' => false,
      //'parse_usernames' => false,
      //'parse_emails' => false,
   ));
}

To generate a preview for multiple URLs extracted from text, use `output/url_preview` view. Pass your text as a `value` parameter. The view will parse all URLs and generate previews.

$text = 'This video is really cool https://vimeo.com/channels/staffpicks/116498390';
if (elgg_view_exists('output/url_preview')) {
   $text = elgg_view('output/url_preview', array(
      'value' => $text,
   ));
}

hypeShortcode

Add support for custom BB-style shortcodes

Register shortcode

elgg()->shortcodes->register('mycode');

// then add a view in shortcodes/mycode
// view vars will contain attributes of the shortcode

Generate a shortcode tag

elgg()->shortcodes->generate('mycode', [
   'foo' => 'bar',
]);

Expand shortcodes

elgg()->shortcodes->expand($text);

Strip shortcodes

elgg()->shortcodes->strip($text);

hypeShutdown

API to offset code execution until system shutdown. Allows plugins to execute expensive code until after the page has been rendered in the browser.

Shutdown event

All shutdown event handlers will be executed after the request has been sent to the browser and the buffer has been flushed.

You can either register a shutdown event handler:

elgg_register_event_handler('shutdown', 'system', function() {
   // your long running script
});

You can also use a runtime queue:

\hypeJunction\Shutdown\Queue::instance()->queue(function() use ($video) {
   $video->convert();
});

hypeSlug

Provides slug support

Adding slugs

If you have hypePost enabled, slug input will be automatically available. Otherwise, extend your forms and actions to store slug metadata on an entity.

hypeStash

API for caching common entity data to reduce DB queries

  • Caches entity likes count
  • Caches entity comments count
  • Caches last comment
  • Caches user friends count
  • Caches group members count

Stashing Logic

The plugin uses preloader classes to load values from the database on first request. The value is cached and returned on consequent calls. Preloader::up() can be used to define when the cached value should be reset. For example, the value of likes is constant until a new like annotation is created, or an old is deleted, so we register our reset function for those events.

Helpers

You can use helper functions to retrieve counts using caching framework. All available shortcut functions can be found in /lib/functions.php

elgg_get_total_likes($entity);
elgg_get_total_comments($entity);

Custom Properties

$stash = \hypeJunction\Stash\Stash::instance();

// Register a new cacheable property
$stash->register(new CustomProperty()); // Custom property must implement Preloader interface

// Get property value
$prop = $stash->get(CustomProperty::PROPERTY, $entity);

hypeStaticPages

Admin tool for creating static pages

hypeStripePayments

A wrapper for Stripe’s PHP SDK

Webhooks

Configure your Stripe application to send webhooks to `https://<your-elgg-site>/payments/stripe/webhooks`

To digest a webhook, register a plugin hook handler:

elgg_register_plugin_hook_handler('customer.subscription.deleted', 'stripe', HandleExpiredSubscription::class);

class HandleExpiredSubscription {
   public function __invoke(\Elgg\Hook $hook) {
      $stripe_event = $hook->getParam('event');
      /* @var $stripe_event \Stripe\Event */

      $subscription = $stripe_event->data->object;

      // ... do stuff

      return $result; // Result will be reported back to stripe
   }
}

Card Input

To display a card input:

// Card number, expiry and CVC
echo elgg_view_field([
   '#type' => 'stripe/card',
   '#label' => 'Credit or Debit Card',
   'required' => true,
]);

// Cardholder name
echo elgg_view_field([
   '#type' => 'stripe/cardholder',
   '#label' => 'Cardholder',
   'required' => true,
]);

// Billing address
// Requires hypeCountries plugin
echo elgg_view_field([
   '#type' => 'stripe/address',
   '#label' => 'Billing address',
   'required' => true,
]);

You can then retrieve the value of the Stripe token in your action:

$token = get_input('stripe_token');
$address = get_input('address');
$name = get_input('cardholder');

// Use stripe API to create a new card object
// or use the token as the source of the payment

hypeStripeSubscriptions

Stripe integration for hypeSubscriptions

hypeSubscriptions

API for implementing paid subscriptions

  • Agnostic API that can be extended with any payment provider
  • Implement site subscriptions and optionally restrict access to paying subscribers only
  • API to implement entity/group specific subscriptions
  • API to restrict access to posts and downloads

Events

To implement custom logic when the subscription is created, listen to create, subscription event.

To implement custom logic when the subscription cancelled, listing to cancel, subscription. Note that the sbuscription can be cancelled at period end, so check current_period_end metadata, before terminating access to features.

hypeTime

Utilities for working with dates and time

  • Adds form fields for date and time input
  • Allows users to configure their time output preferences

hypeTrees

  • Simple API for managing hierarchies of entities

hypeVue

Vue.js bootstrap for Elgg

Developer Tools

To enable Vue dev tools, set environment config value to development

elgg_set_config('environment', 'development');

hypeWall

Rich user interface for sharing status updates, links and content via user walls.

  • URL-parsing with embeddable content view
  • Geotagging (based on browser location)
  • Inline multi-file upload
  • Friend tagging
  • Content attachments

Gotchas

Reverse geocoding (i.e. browser position coordinates to human readable address) will not work in https. Implement a custom solution using a paid/free/proprietary service that does the same

  • Icons are not included with the plugin. You will need to load FontAwesome CSS,

either by registering it in your theme, or using one of the available Elgg plugins.

  • You can add wall tabs and forms by extending the `'framework/wall/container/extend'` view