diff --git a/composer.json b/composer.json
index 62187d73f395aa9e8f9efab499e2f993addf56fd..01fd73edbf5c8ae08f1c7fb33b8bcb6bb5327644 100644
--- a/composer.json
+++ b/composer.json
@@ -75,6 +75,7 @@
         "drupal/administerusersbyrole": "2.0-alpha6",
         "drupal/allowed_formats": "1.1",
         "drupal/better_exposed_filters": "3.0-alpha4",
+        "drupal/block_field": "^1.0@alpha",
         "drupal/block_permissions": "^1.0",
         "drupal/block_region_permissions": "^1.2",
         "drupal/bootstrap": "3.16",
diff --git a/composer.lock b/composer.lock
index 25c3e981e33670932dda35b7a1cfa7cd11dfd4e5..21cc15adf087bd31a5bff805bf98668b2a0700d9 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "fb899f580a58525b7613147181feb19a",
+    "content-hash": "f610ca861b2413536928a19a8bdc73a9",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -1627,6 +1627,61 @@
                 "source": "http://cgit.drupalcode.org/better_exposed_filters"
             }
         },
+        {
+            "name": "drupal/block_field",
+            "version": "1.0.0-alpha8",
+            "source": {
+                "type": "git",
+                "url": "https://git.drupal.org/project/block_field",
+                "reference": "8.x-1.0-alpha8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://ftp.drupal.org/files/projects/block_field-8.x-1.0-alpha8.zip",
+                "reference": "8.x-1.0-alpha8",
+                "shasum": "faffdd869263c3103f5c6a7a8d71ac440df1115f"
+            },
+            "require": {
+                "drupal/core": "~8.0"
+            },
+            "type": "drupal-module",
+            "extra": {
+                "branch-alias": {
+                    "dev-1.x": "1.x-dev"
+                },
+                "drupal": {
+                    "version": "8.x-1.0-alpha8",
+                    "datestamp": "1536732480",
+                    "security-coverage": {
+                        "status": "not-covered",
+                        "message": "Project has not opted into security advisory coverage!"
+                    }
+                }
+            },
+            "notification-url": "https://packages.drupal.org/8/downloads",
+            "license": [
+                "GPL-2.0-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "acbramley",
+                    "homepage": "https://www.drupal.org/user/1036766"
+                },
+                {
+                    "name": "fenstrat",
+                    "homepage": "https://www.drupal.org/user/362649"
+                },
+                {
+                    "name": "jrockowitz",
+                    "homepage": "https://www.drupal.org/user/371407"
+                }
+            ],
+            "description": "Provides a field that allows a content entity to create and configure custom block instances.",
+            "homepage": "https://www.drupal.org/project/block_field",
+            "support": {
+                "source": "http://cgit.drupalcode.org/block_field"
+            }
+        },
         {
             "name": "drupal/block_permissions",
             "version": "1.0.0",
@@ -10712,6 +10767,7 @@
     "aliases": [],
     "minimum-stability": "dev",
     "stability-flags": {
+        "drupal/block_field": 15,
         "drupal/entity_clone": 10,
         "drupal/migrate_devel": 20,
         "drupal/roleassign": 15,
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 667af4c9f22d436b596889ff5d9af126ccdec010..93a3dd808c608d6c96d9ea3879af7a01b7ad9194 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1680,6 +1680,63 @@
             "source": "http://cgit.drupalcode.org/better_exposed_filters"
         }
     },
+    {
+        "name": "drupal/block_field",
+        "version": "1.0.0-alpha8",
+        "version_normalized": "1.0.0.0-alpha8",
+        "source": {
+            "type": "git",
+            "url": "https://git.drupal.org/project/block_field",
+            "reference": "8.x-1.0-alpha8"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://ftp.drupal.org/files/projects/block_field-8.x-1.0-alpha8.zip",
+            "reference": "8.x-1.0-alpha8",
+            "shasum": "faffdd869263c3103f5c6a7a8d71ac440df1115f"
+        },
+        "require": {
+            "drupal/core": "~8.0"
+        },
+        "type": "drupal-module",
+        "extra": {
+            "branch-alias": {
+                "dev-1.x": "1.x-dev"
+            },
+            "drupal": {
+                "version": "8.x-1.0-alpha8",
+                "datestamp": "1536732480",
+                "security-coverage": {
+                    "status": "not-covered",
+                    "message": "Project has not opted into security advisory coverage!"
+                }
+            }
+        },
+        "installation-source": "dist",
+        "notification-url": "https://packages.drupal.org/8/downloads",
+        "license": [
+            "GPL-2.0-or-later"
+        ],
+        "authors": [
+            {
+                "name": "acbramley",
+                "homepage": "https://www.drupal.org/user/1036766"
+            },
+            {
+                "name": "fenstrat",
+                "homepage": "https://www.drupal.org/user/362649"
+            },
+            {
+                "name": "jrockowitz",
+                "homepage": "https://www.drupal.org/user/371407"
+            }
+        ],
+        "description": "Provides a field that allows a content entity to create and configure custom block instances.",
+        "homepage": "https://www.drupal.org/project/block_field",
+        "support": {
+            "source": "http://cgit.drupalcode.org/block_field"
+        }
+    },
     {
         "name": "drupal/block_permissions",
         "version": "1.0.0",
diff --git a/web/modules/block_field/LICENSE.txt b/web/modules/block_field/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1
--- /dev/null
+++ b/web/modules/block_field/LICENSE.txt
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/web/modules/block_field/NOTES.md b/web/modules/block_field/NOTES.md
new file mode 100644
index 0000000000000000000000000000000000000000..c2d62a346205ddf39ef97c71e5fc448c72a254f6
--- /dev/null
+++ b/web/modules/block_field/NOTES.md
@@ -0,0 +1,73 @@
+
+Steps for creating a new release
+--------------------------------
+
+  1. Cleanup code
+  2. Review code
+  3. Run tests
+  4. Generate release notes
+  5. Tag and create a new release
+  6. Update project page
+
+
+1. Cleanup code
+---------------
+
+[Convert to short array syntax](https://www.drupal.org/project/short_array_syntax)
+
+    drush short-array-syntax block_field
+
+
+2. Review code
+--------------
+
+[Online](http://pareview.sh)
+
+    http://git.drupal.org/project/block_field.git 8.x-1.x
+
+[Commandline](https://www.drupal.org/node/1587138)
+
+    # Check Drupal coding standards
+    phpcs --standard=Drupal --extensions=php,module,inc,install,test,profile,theme,js,css,info modules/sandbox/block_field
+
+    # Check Drupal best practices
+    phpcs --standard=DrupalPractice --extensions=php,module,inc,install,test,profile,theme,js,css,info modules/sandbox/block_field
+
+
+3. Run tests
+------------
+
+[SimpleTest](https://www.drupal.org/node/645286)
+
+    # Run all tests
+    php core/scripts/run-tests.sh --url http://localhost/d8_dev --module block_field
+
+
+4. Generate release notes
+-------------------------
+
+[Git Release Notes for Drush](https://www.drupal.org/project/grn)
+
+    drush release-notes 8.x-1.0-VERSION 8.x-1.x
+
+
+5. Tag and create a new release
+-------------------------------
+
+[Tag a release](https://www.drupal.org/node/1066342)
+
+    git tag 8.x-1.0-VERSION
+    git push --tags
+    git push origin tag 8.x-1.0-VERSION
+
+[Create new release](https://www.drupal.org/node/add/project-release/2728453)
+
+
+6. Update project page
+----------------------
+
+[Export README.md](https://www.drupal.org/project/readme)
+    
+     drush readme-export --project block_field
+
+[Edit project page](https://www.drupal.org/node/2728453/edit)
diff --git a/web/modules/block_field/README.md b/web/modules/block_field/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..41ea0eb5d3d3c5280caeab258172bd29a1d5495f
--- /dev/null
+++ b/web/modules/block_field/README.md
@@ -0,0 +1,73 @@
+
+Contents of this file
+---------------------
+
+ * About this module
+ * Use cases
+ * Demo
+ * Installation
+ * Notes
+ * Known Issues/Limitations
+ * Todo
+
+
+About this Module
+-----------------
+
+Provides a field that allows a content entity to create and configure custom 
+block instances.
+
+
+Use Cases
+---------
+
+- Add blocks to a node's sidebar.
+- Add blocks to paragraph.
+- Create a carousel of content and configurable blocks.
+
+
+Demo
+----
+
+> Evaluate this project online using [simplytest.me](https://simplytest.me/project/block_field).
+ 
+ 
+Installation
+------------
+
+1. Copy/upload the `block_field.module` to the modules directory of your 
+   Drupal installation.
+
+2. Enable the 'Block field' module in 'Extend'. (/admin/modules)
+
+3. Add the 'Block (plugin)' field to any content entity
+
+
+Notes
+-----
+
+- The Block field's block instances are stored as configuration, which is good 
+  thing, since site builders and editors can easily tweak them with impacting 
+  any configuration management.
+
+- All content blocks from the 'Custom Block Library' are available.
+
+
+Known Issues/Limitations
+------------------------
+
+- Context aware plugins are not currently supported. This includes ctools 
+  entity view blocks.
+  See: \Drupal\block_field\BlockFieldManager::getBlockDefinitions
+
+
+Todo
+----
+
+- Write additional test for block field plugin ids setting.
+
+
+Author/Maintainer
+-----------------
+
+- [Jacob Rockowitz](http://drupal.org/user/371407)
diff --git a/web/modules/block_field/block_field.info.yml b/web/modules/block_field/block_field.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9b1a1a65c6c219e570777bbbf802ef8a9498f498
--- /dev/null
+++ b/web/modules/block_field/block_field.info.yml
@@ -0,0 +1,11 @@
+name: 'Block Field'
+type: module
+description: 'Provides a field that allows a content entity to create and configure custom block instances.'
+package: Field
+# core: 8.x
+
+# Information added by Drupal.org packaging script on 2018-09-12
+version: '8.x-1.0-alpha8'
+core: '8.x'
+project: 'block_field'
+datestamp: 1536732484
diff --git a/web/modules/block_field/block_field.services.yml b/web/modules/block_field/block_field.services.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f8bdc233f5b007608abd3b11e398687e4dd2f1b8
--- /dev/null
+++ b/web/modules/block_field/block_field.services.yml
@@ -0,0 +1,4 @@
+services:
+  block_field.manager:
+    class: Drupal\block_field\BlockFieldManager
+    arguments: ['@plugin.manager.block', '@context.repository']
diff --git a/web/modules/block_field/config/schema/block_field.yml b/web/modules/block_field/config/schema/block_field.yml
new file mode 100644
index 0000000000000000000000000000000000000000..44f2e40b2aa1c4ca86c9b90ba373c5f89774c7f0
--- /dev/null
+++ b/web/modules/block_field/config/schema/block_field.yml
@@ -0,0 +1,48 @@
+# Schema for the configuration files of the Link module.
+
+field.formatter.settings.block_field:
+  type: mapping
+  label: 'Link format settings'
+  mapping: {  }
+
+field.widget.settings.block_field_default:
+  type: mapping
+  label: 'Link format settings'
+  mapping:
+    plugin_id:
+      type: string
+      label: 'Plugin ID'
+    settings:
+      type: sequence
+      label: 'Settings'
+      sequence:
+        type: string
+    configuration_form:
+      type: string
+
+field.storage_settings.block_field:
+  type: mapping
+  label: 'Block field settings'
+
+field.field_settings.block_field:
+  type: mapping
+  label: 'Block field settings'
+  mapping:
+    plugin_ids:
+      type: sequence
+      label: 'Plugin ids'
+      sequence:
+        type: string
+
+field.value.block_field:
+  type: mapping
+  label: 'Default value'
+  mapping:
+    plugin_id:
+      type: string
+      label: 'Plugin ID'
+    settings:
+      type: sequence
+      label: 'Settings'
+      sequence:
+        type: string
diff --git a/web/modules/block_field/phpcs.xml b/web/modules/block_field/phpcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3327b88c0de8db4928dfd7f7a56d8512739d722c
--- /dev/null
+++ b/web/modules/block_field/phpcs.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<ruleset name="Block field coding standards">
+  <description>Drupal 8 coding standards</description>
+
+  <file>.</file>
+  <arg name="extensions" value="inc,install,module,php,profile,test,theme,yml"/>
+
+  <!-- Ignore markdown. -->
+  <exclude-pattern>README\.md</exclude-pattern>
+  <exclude-pattern>NOTES\.md</exclude-pattern>
+
+  <rule ref="Drupal"/>
+</ruleset>
diff --git a/web/modules/block_field/src/BlockFieldItemInterface.php b/web/modules/block_field/src/BlockFieldItemInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..734424d6cebc316a632aa4f94a002f2f7b99d24b
--- /dev/null
+++ b/web/modules/block_field/src/BlockFieldItemInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\block_field;
+
+use Drupal\Core\Field\FieldItemInterface;
+
+/**
+ * Defines an interface for the block field item.
+ */
+interface BlockFieldItemInterface extends FieldItemInterface {
+
+  /**
+   * Get block instance.
+   *
+   * @return null|\Drupal\Core\Block\BlockPluginInterface
+   *   Return the block instance or NULL if the block does not exist.
+   */
+  public function getBlock();
+
+}
diff --git a/web/modules/block_field/src/BlockFieldManager.php b/web/modules/block_field/src/BlockFieldManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..87a5166e69be108a326b87e600edf81f034b677e
--- /dev/null
+++ b/web/modules/block_field/src/BlockFieldManager.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\block_field;
+
+use Drupal\Core\Block\BlockManagerInterface;
+use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
+
+/**
+ * Defines a service that manages block plugins for the block field.
+ */
+class BlockFieldManager implements BlockFieldManagerInterface {
+
+  /**
+   * The block plugin manager.
+   *
+   * @var \Drupal\Core\Block\BlockManagerInterface
+   */
+  protected $blockManager;
+
+  /**
+   * The context repository.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
+   */
+  protected $contextRepository;
+
+  /**
+   * Constructs a new BlockFieldManager.
+   *
+   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
+   *   The block plugin manager.
+   * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
+   *   The context repository.
+   */
+  public function __construct(BlockManagerInterface $block_manager, ContextRepositoryInterface $context_repository) {
+    $this->blockManager = $block_manager;
+    $this->contextRepository = $context_repository;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBlockDefinitions() {
+    $definitions = $this->blockManager->getDefinitionsForContexts($this->contextRepository->getAvailableContexts());
+    return $this->blockManager->getSortedDefinitions($definitions);
+  }
+
+}
diff --git a/web/modules/block_field/src/BlockFieldManagerInterface.php b/web/modules/block_field/src/BlockFieldManagerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..e57580f1ba26e5d82f56af94c1d336370a3e29b1
--- /dev/null
+++ b/web/modules/block_field/src/BlockFieldManagerInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\block_field;
+
+/**
+ * Provides an interface defining a BLock field manager.
+ */
+interface BlockFieldManagerInterface {
+
+  /**
+   * Get sorted listed of supported block definitions.
+   *
+   * @return array
+   *   An associative array of supported block definitions.
+   */
+  public function getBlockDefinitions();
+
+}
diff --git a/web/modules/block_field/src/Plugin/Field/FieldFormatter/BlockFieldFormatter.php b/web/modules/block_field/src/Plugin/Field/FieldFormatter/BlockFieldFormatter.php
new file mode 100644
index 0000000000000000000000000000000000000000..39e86988447c7d1eebee63b18699220bb53e0d21
--- /dev/null
+++ b/web/modules/block_field/src/Plugin/Field/FieldFormatter/BlockFieldFormatter.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Drupal\block_field\Plugin\Field\FieldFormatter;
+
+use Drupal\Component\Plugin\Exception\ContextException;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\FormatterBase;
+use Drupal\Core\Plugin\ContextAwarePluginInterface;
+
+/**
+ * Plugin implementation of the 'block_field' formatter.
+ *
+ * @FieldFormatter(
+ *   id = "block_field",
+ *   label = @Translation("Block field"),
+ *   field_types = {
+ *     "block_field"
+ *   }
+ * )
+ */
+class BlockFieldFormatter extends FormatterBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function viewElements(FieldItemListInterface $items, $langcode) {
+    $elements = [];
+    foreach ($items as $delta => $item) {
+      /** @var \Drupal\block_field\BlockFieldItemInterface $item */
+      $block_instance = $item->getBlock();
+
+      // Inject runtime contexts.
+      if ($block_instance instanceof ContextAwarePluginInterface) {
+        try {
+          $contexts = \Drupal::service('context.repository')->getRuntimeContexts($block_instance->getContextMapping());
+          \Drupal::service('context.handler')->applyContextMapping($block_instance, $contexts);
+        }
+        catch (ContextException $e) {
+          continue;
+        }
+      }
+
+      // Make sure the block exists and is accessible.
+      if (!$block_instance || !$block_instance->access(\Drupal::currentUser())) {
+        continue;
+      }
+
+      // See \Drupal\block\BlockViewBuilder::buildPreRenderableBlock
+      // See template_preprocess_block()
+      $elements[$delta] = [
+        '#theme' => 'block',
+        '#attributes' => [],
+        '#configuration' => $block_instance->getConfiguration(),
+        '#plugin_id' => $block_instance->getPluginId(),
+        '#base_plugin_id' => $block_instance->getBaseId(),
+        '#derivative_plugin_id' => $block_instance->getDerivativeId(),
+        'content' => $block_instance->build(),
+      ];
+
+      /** @var \Drupal\Core\Render\RendererInterface $renderer */
+      $renderer = \Drupal::service('renderer');
+      $renderer->addCacheableDependency($elements[$delta], $block_instance);
+    }
+    return $elements;
+  }
+
+}
diff --git a/web/modules/block_field/src/Plugin/Field/FieldFormatter/BlockFieldLabelFormatter.php b/web/modules/block_field/src/Plugin/Field/FieldFormatter/BlockFieldLabelFormatter.php
new file mode 100644
index 0000000000000000000000000000000000000000..ad1835496fab286303abfd937b7c4abd4fb8ff2c
--- /dev/null
+++ b/web/modules/block_field/src/Plugin/Field/FieldFormatter/BlockFieldLabelFormatter.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\block_field\Plugin\Field\FieldFormatter;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\FormatterBase;
+
+/**
+ * Plugin implementation of the 'block_field_label' formatter.
+ *
+ * @FieldFormatter(
+ *   id = "block_field_label",
+ *   label = @Translation("Block field label"),
+ *   field_types = {
+ *     "block_field"
+ *   }
+ * )
+ */
+class BlockFieldLabelFormatter extends FormatterBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function viewElements(FieldItemListInterface $items, $langcode) {
+    $elements = [];
+    foreach ($items as $delta => $item) {
+      /** @var \Drupal\block_field\BlockFieldItemInterface $item */
+      $block_instance = $item->getBlock();
+      // Make sure the block exists and is accessible.
+      if (!$block_instance || !$block_instance->access(\Drupal::currentUser())) {
+        continue;
+      }
+
+      $elements[$delta] = [
+        '#markup' => $block_instance->label(),
+      ];
+
+      /** @var \Drupal\Core\Render\RendererInterface $renderer */
+      $renderer = \Drupal::service('renderer');
+      $renderer->addCacheableDependency($elements[$delta], $block_instance);
+    }
+    return $elements;
+  }
+
+}
diff --git a/web/modules/block_field/src/Plugin/Field/FieldType/BlockFieldItem.php b/web/modules/block_field/src/Plugin/Field/FieldType/BlockFieldItem.php
new file mode 100644
index 0000000000000000000000000000000000000000..80634e1a27709d38e98f339b54ab389cdfff24e0
--- /dev/null
+++ b/web/modules/block_field/src/Plugin/Field/FieldType/BlockFieldItem.php
@@ -0,0 +1,197 @@
+<?php
+
+namespace Drupal\block_field\Plugin\Field\FieldType;
+
+use Drupal\block_field\BlockFieldItemInterface;
+use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\TypedData\MapDataDefinition;
+
+/**
+ * Plugin implementation of the 'block_field' field type.
+ *
+ * @FieldType(
+ *   id = "block_field",
+ *   label = @Translation("Block (plugin)"),
+ *   description = @Translation("Stores an instance of a configurable or custom block."),
+ *   category = @Translation("Reference"),
+ *   default_widget = "block_field_default",
+ *   default_formatter = "block_field",
+ * )
+ */
+class BlockFieldItem extends FieldItemBase implements BlockFieldItemInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultFieldSettings() {
+    return [
+      'plugin_ids' => [],
+    ] + parent::defaultFieldSettings();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function mainPropertyName() {
+    return 'plugin_id';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
+    $properties['plugin_id'] = DataDefinition::create('string')
+      ->setLabel(t('Plugin ID'))
+      ->setRequired(TRUE);
+
+    $properties['settings'] = MapDataDefinition::create()
+      ->setLabel(t('Settings'));
+
+    return $properties;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function schema(FieldStorageDefinitionInterface $field_definition) {
+    return [
+      'columns' => [
+        'plugin_id' => [
+          'description' => 'The block plugin id',
+          'type' => 'varchar',
+          'length' => 255,
+        ],
+        'settings' => [
+          'description' => 'Serialized array of settings for the block.',
+          'type' => 'blob',
+          'size' => 'big',
+          'serialize' => TRUE,
+        ],
+      ],
+      'indexes' => ['plugin_id' => ['plugin_id']],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
+    $field = $form_state->getFormObject()->getEntity();
+
+    /** @var \Drupal\block_field\BlockFieldManagerInterface $block_field_manager */
+    $block_field_manager = \Drupal::service('block_field.manager');
+    $definitions = $block_field_manager->getBlockDefinitions();
+    foreach ($definitions as $plugin_id => $definition) {
+      $options[$plugin_id] = [
+        ['category' => (string) $definition['category']],
+        ['label' => $definition['admin_label'] . ' (' . $plugin_id . ')'],
+        ['provider' => $definition['provider']],
+      ];
+    }
+
+    $default_value = $field->getSetting('plugin_ids') ?: array_keys($options);
+
+    $element = [];
+    $element['blocks'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Blocks'),
+      '#description' => $this->t('Please select available blocks.'),
+      '#open' => $field->getSetting('plugin_ids') ? TRUE : FALSE,
+    ];
+    $element['blocks']['plugin_ids'] = [
+      '#type' => 'tableselect',
+      '#header' => [
+        'Category',
+        'Label/ID',
+        'Provider',
+      ],
+      '#options' => $options,
+      '#js_select' => TRUE,
+      '#required' => TRUE,
+      '#empty' => t('No blocks are available.'),
+      '#parents' => ['settings', 'plugin_ids'],
+      '#element_validate' => [[get_called_class(), 'validatePluginIds']],
+      '#default_value' => array_combine($default_value, $default_value),
+    ];
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    $value = $this->get('plugin_id')->getValue();
+    return $value === NULL || $value === '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as property value of the main property, if no array is
+    // given.
+    if (isset($values) && !is_array($values)) {
+      $values = [static::mainPropertyName() => $values];
+    }
+    if (isset($values)) {
+      $values += [
+        'settings' => [],
+      ];
+    }
+    // Unserialize the values.
+    if (is_string($values['settings'])) {
+      $values['settings'] = unserialize($values['settings']);
+    }
+    parent::setValue($values, $notify);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBlock() {
+    if (empty($this->plugin_id)) {
+      return NULL;
+    }
+
+    /** @var \Drupal\Core\Block\BlockManagerInterface $block_manager */
+    $block_manager = \Drupal::service('plugin.manager.block');
+
+    /** @var \Drupal\Core\Block\BlockPluginInterface $block_instance */
+    $block_instance = $block_manager->createInstance($this->plugin_id, $this->settings);
+
+    $plugin_definition = $block_instance->getPluginDefinition();
+
+    // Don't return broken block plugin instances.
+    if ($plugin_definition['id'] == 'broken') {
+      return NULL;
+    }
+
+    // Don't return broken block content instances.
+    if ($plugin_definition['id'] == 'block_content') {
+      $uuid = $block_instance->getDerivativeId();
+      if (!\Drupal::service('entity.repository')->loadEntityByUuid('block_content', $uuid)) {
+        return NULL;
+      }
+    }
+
+    return $block_instance;
+  }
+
+  /**
+   * Validates plugin_ids table select element.
+   */
+  public static function validatePluginIds(array &$element, FormStateInterface $form_state, &$complete_form) {
+    $value = array_filter($element['#value']);
+    if (array_keys($element['#options']) == array_keys($value)) {
+      $form_state->setValueForElement($element, []);
+    }
+    else {
+      $form_state->setValueForElement($element, $value);
+    }
+    return $element;
+  }
+
+}
diff --git a/web/modules/block_field/src/Plugin/Field/FieldWidget/BlockFieldWidget.php b/web/modules/block_field/src/Plugin/Field/FieldWidget/BlockFieldWidget.php
new file mode 100644
index 0000000000000000000000000000000000000000..90c51231c8e0a7b3b219faa2b0a100fed6353edf
--- /dev/null
+++ b/web/modules/block_field/src/Plugin/Field/FieldWidget/BlockFieldWidget.php
@@ -0,0 +1,301 @@
+<?php
+
+namespace Drupal\block_field\Plugin\Field\FieldWidget;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Block\BlockManagerInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\SubformState;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Plugin\ContextAwarePluginInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Plugin implementation of the 'block_field' widget.
+ *
+ * @FieldWidget(
+ *   id = "block_field_default",
+ *   label = @Translation("Block field"),
+ *   field_types = {
+ *     "block_field"
+ *   }
+ * )
+ */
+class BlockFieldWidget extends WidgetBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The block manager.
+   *
+   * @var \Drupal\Core\Block\BlockManagerInterface
+   */
+  protected $blockManager;
+
+  /**
+   * Set the block manager.
+   *
+   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
+   *   The block manager.
+   */
+  public function setBlockManager(BlockManagerInterface $block_manager) {
+    $this->blockManager = $block_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    $instance = new static(
+      $plugin_id,
+      $plugin_definition,
+      $configuration['field_definition'],
+      $configuration['settings'],
+      $configuration['third_party_settings']
+    );
+    $instance->setBlockManager($container->get('plugin.manager.block'));
+
+    return $instance;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultSettings() {
+    return [
+      'plugin_id' => '',
+      'settings' => [],
+      'configuration_form' => 'full',
+    ] + parent::defaultSettings();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $elements['configuration_form'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Configuration form'),
+      '#description' => $this->t('How the block configuration form will be shown.'),
+      '#options' => [
+        'full' => $this->t('Full'),
+        'hidden' => $this->t('Hidden'),
+      ],
+      '#default_value' => $this->getSetting('configuration_form'),
+      '#required' => TRUE,
+    ];
+
+    return $elements;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsSummary() {
+    $summary[] = $this->t('Configuration form: @configuration_form', ['@configuration_form' => $this->getSetting('configuration_form')]);
+    return $summary;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
+    /** @var \Drupal\block_field\BlockFieldItemInterface $item */
+    $item =& $items[$delta];
+
+    $field_name = $this->fieldDefinition->getName();
+    $settings_id = implode('-', array_merge(
+      $element['#field_parents'],
+      [$field_name, $delta, 'settings']
+    ));
+
+    $plugin_ids = $this->fieldDefinition->getSetting('plugin_ids');
+
+    $values = $form_state->getValues();
+    $item->plugin_id = (isset($values[$field_name][$delta]['plugin_id'])) ? $values[$field_name][$delta]['plugin_id'] : $item->plugin_id;
+    if (!empty($values[$field_name][$delta]['settings'])) {
+      $item->settings = $values[$field_name][$delta]['settings'];
+    }
+    else {
+      $item->settings = $item->settings ?: [];
+    }
+
+    $options = [];
+    /** @var \Drupal\block_field\BlockFieldManagerInterface $block_field_manager */
+    $block_field_manager = \Drupal::service('block_field.manager');
+    $definitions = $block_field_manager->getBlockDefinitions();
+    foreach ($definitions as $id => $definition) {
+      // If allowed plugin ids are set then check that this block should be
+      // included.
+      if ($plugin_ids && !isset($plugin_ids[$id])) {
+        // Remove the definition, so that we have an accurate list of allowed
+        // blocks definitions.
+        unset($definitions[$id]);
+        continue;
+      }
+      $category = (string) $definition['category'];
+      $options[$category][$id] = $definition['admin_label'];
+    }
+
+    // Make sure the plugin id is allowed, if not clear all settings.
+    if ($item->plugin_id && !isset($definitions[$item->plugin_id])) {
+      $item->plugin_id = '';
+      $item->setting = [];
+    }
+
+    $element['plugin_id'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Block'),
+      '#options' => $options,
+      '#empty_option' => $this->t('- None -'),
+      '#default_value' => $item->plugin_id,
+      '#required' => $element['#required'],
+    ];
+
+    // Show configuration form if required.
+    if ($this->getSetting('configuration_form') === 'full') {
+      $element['plugin_id']['#ajax'] = [
+        'callback' => [$this, 'configurationForm'],
+        'wrapper' => $settings_id,
+      ];
+
+      // Build configuration container.
+      $element['settings'] = [
+        '#type' => 'container',
+        '#attributes' => ['id' => $settings_id],
+        '#tree' => TRUE,
+      ];
+
+      // If block plugin exists get the block's configuration form.
+      if ($block_instance = $item->getBlock()) {
+        /** @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository */
+        $context_repository = \Drupal::service('context.repository');
+        $form_state->setTemporaryValue('gathered_contexts', $context_repository->getAvailableContexts());
+
+        $element['settings'] += $block_instance->buildConfigurationForm([], $form_state);
+
+        // Hide admin label (aka description).
+        if (isset($element['settings']['admin_label'])) {
+          $element['settings']['admin_label']['#access'] = FALSE;
+        }
+
+        $element['#element_validate'] = [[$this, 'validate']];
+      }
+    }
+
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function formSingleElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
+    $element = parent::formSingleElement($items, $delta, $element, $form, $form_state);
+    // For single element set the plugin id title and description to use the
+    // field's title and description.
+    $element['plugin_id']['#title'] = $element['#title'];
+    $element['plugin_id']['#title_display'] = $element['#title_display'];
+    $element['plugin_id']['#description'] = $element['#description'];
+    return $element;
+  }
+
+  /**
+   * Ajax callback that return block configuration setting form.
+   */
+  public function configurationForm(array $form, FormStateInterface $form_state) {
+    $trigger_element = $form_state->getTriggeringElement();
+    $array_parents = $trigger_element['#array_parents'];
+    $array_parents[(count($array_parents) - 1)] = 'settings';
+    $settings_element = NestedArray::getValue($form, $array_parents);
+
+    // Set the label #value to the default block instance's label.
+    $plugin_id = $trigger_element['#value'];
+    /** @var \Drupal\Core\Block\BlockManagerInterface $block_manager */
+    $block_manager = \Drupal::service('plugin.manager.block');
+    /** @var \Drupal\Core\Block\BlockPluginInterface $block_instance */
+    if ($block_instance = $block_manager->createInstance($plugin_id)) {
+      $settings_element['label']['#value'] = $block_instance->label();
+    }
+
+    return $settings_element;
+  }
+
+  /**
+   * Form element validation handler.
+   */
+  public static function validate($element, FormStateInterface $form_state, $form) {
+    /** @var \Drupal\Core\Block\BlockManagerInterface $block_manager */
+    $block_manager = \Drupal::service('plugin.manager.block');
+
+    $values = $form_state->getValues();
+    $plugin_id = NestedArray::getValue($values, $element['plugin_id']['#parents']);
+
+    if (!empty($plugin_id) && $block_manager->hasDefinition($plugin_id)) {
+      // Clean up configuration settings.
+      $settings = NestedArray::getValue($values, $element['settings']['#parents']);
+
+      // Convert label display to FALSE instead of 0. This allow the label to be
+      // hidden.
+      if ($settings['label_display'] === 0) {
+        $settings['label_display'] = FALSE;
+      }
+
+      // Execute block validate configuration.
+      $block_instance = $block_manager->createInstance($plugin_id, $settings);
+      $settings = (new FormState())->setValues($settings);
+      $block_instance->validateConfigurationForm($element['settings'], $settings);
+
+      // Pass along errors from the block validation.
+      foreach ($settings->getErrors() as $key => $error) {
+        $parents = implode('][', $element['settings']['#parents']);
+        // If the block form used setError() then the parents will already be
+        // part of the key since we are passing along the element in the context
+        // of the whole form. If the block form used setErrorByName we need to
+        // add the parents in.
+        if (strpos($key, $parents) === FALSE) {
+          $key = sprintf('%s][%s', $parents, $key);
+        }
+        $form_state->setErrorByName($key, $error);
+      }
+
+      NestedArray::setValue($values, $element['settings']['#parents'], $settings->getValues());
+      $form_state->setValues($values);
+    }
+    else {
+      // Clear all configuration settings.
+      NestedArray::setValue($values, $element['settings']['#parents'], []);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
+    $field_name = $this->fieldDefinition->getName();
+
+    // Some blocks clean the processed values in form state. However, entity
+    // forms extract the form values twice during submission. For the second
+    // submission to work as well, we need to prevent the removal of the form
+    // values during the first submission.
+    $form_state = clone $form_state;
+
+    foreach ($values as $delta => &$value) {
+      // Execute block submit configuration in order to transform the form
+      // values into block configuration.
+      if (!empty($value['plugin_id']) && !empty($value['settings']) && $block = $this->blockManager->createInstance($value['plugin_id'])) {
+        $elements = &$form[$field_name]['widget'][$value['_original_delta']]['settings'];
+        $subform_state = SubformState::createForSubform($elements, $form_state->getCompleteForm(), $form_state);
+        $block->submitConfigurationForm($elements, $subform_state);
+        // If this block is context-aware, set the context mapping.
+        if ($block instanceof ContextAwarePluginInterface && $block->getContextDefinitions()) {
+          $context_mapping = $subform_state->getValue('context_mapping', []);
+          $block->setContextMapping($context_mapping);
+        }
+        $value['settings'] = $block->getConfiguration();
+      }
+    }
+    return $values;
+  }
+
+}
diff --git a/web/modules/block_field/tests/modules/block_field_test/block_field_test.features.yml b/web/modules/block_field/tests/modules/block_field_test/block_field_test.features.yml
new file mode 100644
index 0000000000000000000000000000000000000000..060a98e7a2f994a5c4cfd7618bc3d4c05edb4adb
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/block_field_test.features.yml
@@ -0,0 +1 @@
+required: true
diff --git a/web/modules/block_field/tests/modules/block_field_test/block_field_test.info.yml b/web/modules/block_field/tests/modules/block_field_test/block_field_test.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fe380c16585718fece15485d35538cbc99edd344
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/block_field_test.info.yml
@@ -0,0 +1,18 @@
+name: 'Block field module tests'
+type: module
+description: 'Support module for Block field that provides a working example of a block field.'
+package: Testing
+# core: 8.x
+dependencies:
+  - block_field
+  - field
+  - menu_ui
+  - node
+  - path
+  - user
+
+# Information added by Drupal.org packaging script on 2018-09-12
+version: '8.x-1.0-alpha8'
+core: '8.x'
+project: 'block_field'
+datestamp: 1536732484
diff --git a/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_form_display.node.block_field_test.default.yml b/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_form_display.node.block_field_test.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f4bd7095346f2279fe3da447415c2c10318ae197
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_form_display.node.block_field_test.default.yml
@@ -0,0 +1,73 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.node.block_field_test.field_block_field_test
+    - node.type.block_field_test
+  module:
+    - block_field
+    - path
+id: node.block_field_test.default
+targetEntityType: node
+bundle: block_field_test
+mode: default
+content:
+  created:
+    type: datetime_timestamp
+    weight: 10
+    settings: {  }
+    third_party_settings: {  }
+    region: content
+  field_block_field_test:
+    weight: 32
+    settings:
+      settings: {  }
+      plugin_id: ''
+    third_party_settings: {  }
+    type: block_field_default
+    region: content
+  path:
+    type: path
+    weight: 30
+    settings: {  }
+    third_party_settings: {  }
+    region: content
+  promote:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 15
+    third_party_settings: {  }
+    region: content
+  status:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 120
+    region: content
+    third_party_settings: {  }
+  sticky:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 16
+    third_party_settings: {  }
+    region: content
+  title:
+    type: string_textfield
+    weight: -5
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    region: content
+  uid:
+    type: entity_reference_autocomplete
+    weight: 5
+    settings:
+      match_operator: CONTAINS
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    region: content
+hidden: {  }
diff --git a/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_view_display.node.block_field_test.default.yml b/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_view_display.node.block_field_test.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a9b30494d873a3f290a258c2a431ba5109040c0e
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_view_display.node.block_field_test.default.yml
@@ -0,0 +1,27 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.node.block_field_test.field_block_field_test
+    - node.type.block_field_test
+  module:
+    - block_field
+    - user
+id: node.block_field_test.default
+targetEntityType: node
+bundle: block_field_test
+mode: default
+content:
+  field_block_field_test:
+    weight: 102
+    label: above
+    settings: {  }
+    third_party_settings: {  }
+    type: block_field
+    region: content
+  links:
+    weight: 100
+    settings: {  }
+    third_party_settings: {  }
+    region: content
+hidden: {  }
diff --git a/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_view_display.node.block_field_test.teaser.yml b/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_view_display.node.block_field_test.teaser.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8aafc60de4fa5cb174ed690d901ae7fbff545916
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/config/install/core.entity_view_display.node.block_field_test.teaser.yml
@@ -0,0 +1,19 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.node.teaser
+    - field.field.node.block_field_test.field_block_field_test
+    - node.type.block_field_test
+  module:
+    - user
+id: node.block_field_test.teaser
+targetEntityType: node
+bundle: block_field_test
+mode: teaser
+content:
+  links:
+    weight: 100
+    region: content
+hidden:
+  field_block_field_test: true
diff --git a/web/modules/block_field/tests/modules/block_field_test/config/install/field.field.node.block_field_test.field_block_field_test.yml b/web/modules/block_field/tests/modules/block_field_test/config/install/field.field.node.block_field_test.field_block_field_test.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b5f05cf0f27845c659cda2150f566f3b5c545f82
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/config/install/field.field.node.block_field_test.field_block_field_test.yml
@@ -0,0 +1,21 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.node.field_block_field_test
+    - node.type.block_field_test
+  module:
+    - block_field
+id: node.block_field_test.field_block_field_test
+field_name: field_block_field_test
+entity_type: node
+bundle: block_field_test
+label: 'Block field test'
+description: ''
+required: false
+translatable: false
+default_value: {  }
+default_value_callback: ''
+settings:
+  plugin_ids: {  }
+field_type: block_field
diff --git a/web/modules/block_field/tests/modules/block_field_test/config/install/field.storage.node.field_block_field_test.yml b/web/modules/block_field/tests/modules/block_field_test/config/install/field.storage.node.field_block_field_test.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e963be06e9d8e86acb165126b2fa521c74ffd30d
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/config/install/field.storage.node.field_block_field_test.yml
@@ -0,0 +1,18 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - block_field
+    - node
+id: node.field_block_field_test
+field_name: field_block_field_test
+entity_type: node
+type: block_field
+settings: {  }
+module: block_field
+locked: false
+cardinality: -1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/web/modules/block_field/tests/modules/block_field_test/config/install/node.type.block_field_test.yml b/web/modules/block_field/tests/modules/block_field_test/config/install/node.type.block_field_test.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9e0f8039f02bcf9741c6a6d59e17661ac86bdcff
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/config/install/node.type.block_field_test.yml
@@ -0,0 +1,17 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - menu_ui
+third_party_settings:
+  menu_ui:
+    available_menus:
+      - main
+    parent: 'main:'
+name: 'Block field test'
+type: block_field_test
+description: ''
+help: ''
+new_revision: false
+preview_mode: 1
+display_submitted: true
diff --git a/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestAuthenticatedBlock.php b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestAuthenticatedBlock.php
new file mode 100644
index 0000000000000000000000000000000000000000..d9c895ac401f2894d001803587969265bf77dbd3
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestAuthenticatedBlock.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\block_field_test\Plugin\Block;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Block\BlockBase;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Provides a 'Block field test authenticated' block.
+ *
+ * @Block(
+ *   id = "block_field_test_authenticated",
+ *   admin_label = @Translation("You are logged in as..."),
+ *   category = @Translation("Block field test")
+ * )
+ */
+class BlockFieldTestAuthenticatedBlock extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    return [
+      '#theme' => 'username',
+      '#account' => \Drupal::currentUser()->getAccount(),
+      '#prefix' => '<p>',
+      '#suffix' => '</p>',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function blockAccess(AccountInterface $account) {
+    return AccessResult::allowedIf($account->isAuthenticated());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheContexts() {
+    return ['user'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return ['user:' . \Drupal::currentUser()->id()];
+  }
+
+}
diff --git a/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestContentBlock.php b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestContentBlock.php
new file mode 100644
index 0000000000000000000000000000000000000000..26ecf067f2572e8fa0ee6ef29a692efcd8150ee0
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestContentBlock.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\block_field_test\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a 'Block field test content' block.
+ *
+ * @Block(
+ *   id = "block_field_test_content",
+ *   admin_label = @Translation("Block field test content"),
+ *   category = @Translation("Block field test")
+ * )
+ */
+class BlockFieldTestContentBlock extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [
+      'content' => $this->t('A default value. This block was created at @time', ['@time' => date('Y-m-d h:i:sa')]),
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockForm($form, FormStateInterface $form_state) {
+    $form['content'] = [
+      '#type' => 'textarea',
+      '#title' => $this->t('Content'),
+      '#default_value' => $this->configuration['content'],
+    ];
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockSubmit($form, FormStateInterface $form_state) {
+    $this->configuration['content'] = $form_state->getValue('content');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    return [
+      '#type' => 'markup',
+      '#markup' => $this->configuration['content'],
+    ];
+  }
+
+}
diff --git a/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestTimeBlock.php b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestTimeBlock.php
new file mode 100644
index 0000000000000000000000000000000000000000..e7398deda2016e676415bb913919bb8a8bf36c76
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestTimeBlock.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\block_field_test\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+
+/**
+ * Provides a 'Block field test time' block.
+ *
+ * @Block(
+ *   id = "block_field_test_time",
+ *   admin_label = @Translation("The time is..."),
+ *   category = @Translation("Block field test")
+ * )
+ */
+class BlockFieldTestTimeBlock extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    return [
+      '#type' => 'markup',
+      '#markup' => date('H:i:s') . ' (' . time() . ')',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheMaxAge() {
+    return 0;
+  }
+
+}
diff --git a/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestValidationBlock.php b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestValidationBlock.php
new file mode 100644
index 0000000000000000000000000000000000000000..476c4a291b80d892474bc6c1318984a2aea40825
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_test/src/Plugin/Block/BlockFieldTestValidationBlock.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\block_field_test\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a 'Block field test validation' block.
+ *
+ * @Block(
+ *   id = "block_field_test_validation",
+ *   admin_label = @Translation("Block field test validation"),
+ *   category = @Translation("Block field test")
+ * )
+ */
+class BlockFieldTestValidationBlock extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [
+      'content' => '',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockForm($form, FormStateInterface $form_state) {
+    $form['content'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Content'),
+      '#default_value' => $this->configuration['content'],
+    ];
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockSubmit($form, FormStateInterface $form_state) {
+    $this->configuration['content'] = $form_state->getValue('content');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function blockValidate($form, FormStateInterface $form_state) {
+    if ($form_state->getValue('content') == 'error by name') {
+      $form_state->setErrorByName('content', 'Come ere boi!');
+    }
+    if ($form_state->getValue('content') == 'error by element') {
+      $form_state->setError($form['content'], 'Gimmie them toez!');
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    return [
+      '#type' => 'markup',
+      '#markup' => $this->configuration['content'],
+    ];
+  }
+
+}
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/block_field_widget_test.info.yml b/web/modules/block_field/tests/modules/block_field_widget_test/block_field_widget_test.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..80150bc4983ccc8cbf34e7d6bf5a5fb905b9b48f
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/block_field_widget_test.info.yml
@@ -0,0 +1,19 @@
+name: 'Block field module widget tests'
+type: module
+description: 'Support module for block field that provides some default configuration to test the field widget.'
+package: Testing
+# core: 8.x
+dependencies:
+  - block
+  - block_field
+  - field
+  - node
+  - path
+  - user
+  - views
+
+# Information added by Drupal.org packaging script on 2018-09-12
+version: '8.x-1.0-alpha8'
+core: '8.x'
+project: 'block_field'
+datestamp: 1536732484
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/config/install/core.entity_form_display.node.block_node.default.yml b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/core.entity_form_display.node.block_node.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0cc9252ba2f0b9b8eb921a2c08539bbf6365a4c0
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/core.entity_form_display.node.block_node.default.yml
@@ -0,0 +1,73 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.node.block_node.field_block
+    - node.type.block_node
+  module:
+    - block_field
+    - path
+id: node.block_node.default
+targetEntityType: node
+bundle: block_node
+mode: default
+content:
+  created:
+    type: datetime_timestamp
+    weight: 10
+    settings: {  }
+    third_party_settings: {  }
+    region: content
+  field_block:
+    weight: 31
+    settings:
+      plugin_id: ''
+      settings: {  }
+    third_party_settings: {  }
+    type: block_field_default
+    region: content
+  path:
+    type: path
+    weight: 30
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  promote:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 15
+    third_party_settings: {  }
+    region: content
+  status:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 120
+    region: content
+    third_party_settings: {  }
+  sticky:
+    type: boolean_checkbox
+    settings:
+      display_label: true
+    weight: 16
+    third_party_settings: {  }
+    region: content
+  title:
+    type: string_textfield
+    weight: -5
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    region: content
+  uid:
+    type: entity_reference_autocomplete
+    weight: 5
+    settings:
+      match_operator: CONTAINS
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    region: content
+hidden: {  }
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/config/install/core.entity_view_display.node.block_node.default.yml b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/core.entity_view_display.node.block_node.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..10e2c62641aedd3964fdcb4213a20a2caca44994
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/core.entity_view_display.node.block_node.default.yml
@@ -0,0 +1,25 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.node.block_node.field_block
+    - node.type.block_node
+  module:
+    - block_field
+    - user
+id: node.block_node.default
+targetEntityType: node
+bundle: block_node
+mode: default
+content:
+  field_block:
+    weight: 101
+    label: above
+    settings: {  }
+    third_party_settings: {  }
+    type: block_field
+    region: content
+  links:
+    weight: 100
+    region: content
+hidden: {  }
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/config/install/field.field.node.block_node.field_block.yml b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/field.field.node.block_node.field_block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..35e3279ba2a1d328dc6cc9219de188549c80beca
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/field.field.node.block_node.field_block.yml
@@ -0,0 +1,21 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.node.field_block
+    - node.type.block_node
+  module:
+    - block_field
+id: node.block_node.field_block
+field_name: field_block
+entity_type: node
+bundle: block_node
+label: Block
+description: ''
+required: false
+translatable: false
+default_value: {  }
+default_value_callback: ''
+settings:
+  plugin_ids: {  }
+field_type: block_field
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/config/install/field.storage.node.field_block.yml b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/field.storage.node.field_block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..867506d72ef79514e2ffb363a9bdc9bf1c3ff185
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/field.storage.node.field_block.yml
@@ -0,0 +1,18 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - block_field
+    - node
+id: node.field_block
+field_name: field_block
+entity_type: node
+type: block_field
+settings: {  }
+module: block_field
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/config/install/node.type.block_node.yml b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/node.type.block_node.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fb3fa2d4a2250521995d7e1f127aabcf6284af1a
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/node.type.block_node.yml
@@ -0,0 +1,10 @@
+langcode: en
+status: true
+dependencies: {  }
+name: 'Block node'
+type: block_node
+description: ''
+help: ''
+new_revision: false
+preview_mode: 0
+display_submitted: false
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/config/install/node.type.item.yml b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/node.type.item.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3f7405d3dbfdef8c64e339c9dfde8cfadbba19d
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/config/install/node.type.item.yml
@@ -0,0 +1,10 @@
+langcode: en
+status: true
+dependencies: {  }
+name: Item
+type: item
+description: ''
+help: ''
+new_revision: false
+preview_mode: 1
+display_submitted: true
diff --git a/web/modules/block_field/tests/modules/block_field_widget_test/config/optional/views.view.items.yml b/web/modules/block_field/tests/modules/block_field_widget_test/config/optional/views.view.items.yml
new file mode 100644
index 0000000000000000000000000000000000000000..407488574edfd6038c5d666dabaefc54ca53eba0
--- /dev/null
+++ b/web/modules/block_field/tests/modules/block_field_widget_test/config/optional/views.view.items.yml
@@ -0,0 +1,215 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+    - user
+id: items
+label: Items
+module: views
+description: ''
+tag: ''
+base_table: node_field_data
+base_field: nid
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Toepassen
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sorteren op'
+          expose_sort_order: true
+          sort_asc_label: Oplopend
+          sort_desc_label: Aflopend
+      pager:
+        type: some
+        options:
+          items_per_page: 1
+          offset: 0
+      style:
+        type: default
+        options:
+          grouping: {  }
+          row_class: ''
+          default_row_class: true
+          uses_fields: false
+      row:
+        type: fields
+        options:
+          inline: {  }
+          separator: ''
+          hide_empty: false
+          default_field_elements: true
+      fields:
+        title:
+          id: title
+          table: node_field_data
+          field: title
+          entity_type: node
+          entity_field: title
+          label: ''
+          alter:
+            alter_text: false
+            make_link: false
+            absolute: false
+            trim: false
+            word_boundary: false
+            ellipsis: false
+            strip_tags: false
+            html: false
+          hide_empty: false
+          empty_zero: false
+          settings:
+            link_to_entity: true
+          plugin_id: field
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exclude: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+      filters:
+        status:
+          value: '1'
+          table: node_field_data
+          field: status
+          plugin_id: boolean
+          entity_type: node
+          entity_field: status
+          id: status
+          expose:
+            operator: ''
+          group: 1
+      sorts:
+        created:
+          id: created
+          table: node_field_data
+          field: created
+          order: DESC
+          entity_type: node
+          entity_field: created
+          plugin_id: date
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exposed: false
+          expose:
+            label: ''
+          granularity: second
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments:
+        nid:
+          id: nid
+          table: node_field_data
+          field: nid
+          relationship: none
+          group_type: group
+          admin_label: Exclude
+          default_action: ignore
+          exception:
+            value: all
+            title_enable: false
+            title: All
+          title_enable: false
+          title: ''
+          default_argument_type: fixed
+          default_argument_options:
+            argument: ''
+          default_argument_skip_url: false
+          summary_options:
+            base_path: ''
+            count: true
+            items_per_page: 25
+            override: false
+          summary:
+            sort_order: asc
+            number_of_records: 0
+            format: default_summary
+          specify_validation: true
+          validate:
+            type: 'entity:node'
+            fail: 'not found'
+          validate_options:
+            operation: view
+            multiple: 0
+            bundles: {  }
+            access: false
+          break_phrase: false
+          not: true
+          entity_type: node
+          entity_field: nid
+          plugin_id: node_nid
+      display_extenders: {  }
+      title: Items
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
+  block_1:
+    display_plugin: block
+    id: block_1
+    display_title: Items
+    position: 1
+    display_options:
+      display_extenders: {  }
+      block_description: items
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
diff --git a/web/modules/block_field/tests/src/Functional/BlockFieldTest.php b/web/modules/block_field/tests/src/Functional/BlockFieldTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..09677eeefd467d3eb8c2aa6d852d9fb11a927c8c
--- /dev/null
+++ b/web/modules/block_field/tests/src/Functional/BlockFieldTest.php
@@ -0,0 +1,166 @@
+<?php
+
+namespace Drupal\Tests\block_field\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests block field widgets and formatters.
+ *
+ * @group block_field
+ */
+class BlockFieldTest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'node',
+    'user',
+    'block',
+    'block_field',
+    'block_field_test',
+    'field_ui',
+  ];
+
+  /**
+   * Tests block field.
+   */
+  public function testBlockField() {
+    $assert = $this->assertSession();
+
+    $admin_user = $this->drupalCreateUser([
+      'access content',
+      'administer nodes',
+      'administer content types',
+      'bypass node access',
+      'administer node fields',
+    ]);
+    $this->drupalLogin($admin_user);
+
+    // Create block field test using the three test blocks.
+    // Check that add more and ajax callbacks are working as expected.
+    $this->drupalPostForm('node/add/block_field_test', [
+      'title[0][value]' => 'Block field test',
+    ], 'Add another item');
+    $this->drupalPostForm(NULL, [], 'Add another item');
+    $this->drupalPostForm(NULL, [
+      'field_block_field_test[0][plugin_id]' => 'block_field_test_authenticated',
+      'field_block_field_test[1][plugin_id]' => 'block_field_test_content',
+      'field_block_field_test[2][plugin_id]' => 'block_field_test_time',
+    ], 'Add another item');
+    $this->drupalPostForm(NULL, [
+      'field_block_field_test[0][plugin_id]' => 'block_field_test_authenticated',
+      'field_block_field_test[1][plugin_id]' => 'block_field_test_content',
+      'field_block_field_test[2][plugin_id]' => 'block_field_test_time',
+    ], 'Add another item');
+    $this->drupalPostForm(NULL, [], 'Save');
+
+    // Check blocks displayed to authenticated.
+    $node = $this->drupalGetNodeByTitle('Block field test');
+    $this->drupalGet($node->toUrl());
+    $selector = '.field--name-field-block-field-test';
+    $assert->elementExists('css', $selector);
+    $assert->elementContains('css', $selector, '<div class="field__label">Block field test</div>');
+    $assert->elementContains('css', $selector, '<h2>You are logged in as...</h2>');
+    $assert->elementTextContains('css', $selector, $admin_user->label());
+    $assert->elementContains('css', $selector, '<h2>Block field test content</h2>');
+    $assert->elementTextContains('css', $selector, 'This block was created at');
+    $assert->elementContains('css', $selector, '<h2>The time is...</h2>');
+    $assert->responseMatches('/\d\d:\d\d:\d\d/');
+
+    // Check adjusting block weights maintains plugin settings.
+    $this->drupalGet($node->toUrl('edit-form'));
+    // Switch the position of block 1 and 2.
+    $this->drupalPostForm(NULL, [
+      'field_block_field_test[0][_weight]' => 1,
+      'field_block_field_test[1][_weight]' => 0,
+    ], 'Save');
+    $this->drupalGet($node->toUrl('edit-form'));
+    // Plugin id and label should be switched.
+    $assert->fieldValueEquals('field_block_field_test[0][plugin_id]', 'block_field_test_content');
+    $assert->fieldValueEquals('field_block_field_test[0][settings][label]', 'Block field test content');
+    $assert->fieldValueEquals('field_block_field_test[1][plugin_id]', 'block_field_test_authenticated');
+    $assert->fieldValueEquals('field_block_field_test[1][settings][label]', 'You are logged in as...');
+
+    // Create a block_field_test node.
+    $block_node = $this->drupalCreateNode([
+      'type' => 'block_field_test',
+    ]);
+
+    // Check authenticated block.
+    $block_node->field_block_field_test->plugin_id = 'block_field_test_authenticated';
+    $block_node->field_block_field_test->settings = [
+      'label' => 'Authenticated',
+      'label_display' => TRUE,
+    ];
+    $block_node->save();
+    $this->drupalGet($block_node->toUrl());
+    $assert->elementContains('css', $selector, '<h2>Authenticated</h2>');
+    $assert->elementTextContains('css', $selector, $admin_user->label());
+
+    // Check block_field_test_authenticated cache dependency is respected when
+    // the user's name is updated.
+    $admin_user->setUsername('admin_user');
+    $admin_user->save();
+    $this->drupalGet($block_node->toUrl());
+    $assert->elementContains('css', $selector, '<h2>Authenticated</h2>');
+    $assert->elementTextContains('css', $selector, 'admin_user');
+
+    // Check authenticated block is not visible to anonymous users.
+    $this->drupalLogout();
+    $this->drupalGet($block_node->toUrl());
+    $assert->elementNotExists('css', $selector);
+
+    // Check content block.
+    $block_node->field_block_field_test->plugin_id = 'block_field_test_content';
+    $block_node->field_block_field_test->settings = [
+      'label' => 'Hello',
+      'label_display' => TRUE,
+      'content' => '<p>World</p>',
+    ];
+    $block_node->save();
+
+    $this->drupalGet($block_node->toUrl());
+    $assert->elementContains('css', $selector, '<h2>Hello</h2>');
+    $assert->elementContains('css', $selector, '<p>World</p>');
+
+    // ISSUE: Drupal's page cache it not respecting the time block max age,
+    // so we need to log in to bypass page caching.
+    $this->drupalLogin($admin_user);
+
+    // Check time block.
+    $block_node->field_block_field_test->plugin_id = 'block_field_test_time';
+    $block_node->field_block_field_test->settings = [
+      'label' => 'Time',
+      'label_display' => TRUE,
+    ];
+    $block_node->save();
+
+    // Check that time is set.
+    $this->drupalGet($block_node->toUrl());
+    $assert->responseMatches('/\d\d:\d\d:\d\d \(\d+\)/');
+
+    // Get the current time.
+    preg_match('/\d\d:\d\d:\d\d \(\d+\)/', $this->getSession()->getPage()->getContent(), $match);
+    $time = $match[0];
+    $assert->responseContains($time);
+
+    // Have delay test one second so that the time is updated.
+    sleep(1);
+
+    // Check that time is never cached by reloading the page.
+    $this->drupalGet($block_node->toUrl());
+    $assert->responseMatches('/\d\d:\d\d:\d\d \(\d+\)/');
+    $assert->responseNotContains($time);
+
+    $this->drupalGet('admin/structure/types/manage/block_field_test/fields/node.block_field_test.field_block_field_test');
+    $this->drupalPostForm(NULL, ['settings[plugin_ids][page_title_block]' => FALSE], 'Save settings');
+
+    $this->drupalGet('admin/structure/types/manage/block_field_test/fields/node.block_field_test.field_block_field_test');
+    $assert->statusCodeEquals(200);
+  }
+
+}
diff --git a/web/modules/block_field/tests/src/Functional/WidgetTest.php b/web/modules/block_field/tests/src/Functional/WidgetTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..51d15d8ec6c0c390e2a58625cf2d8a1a8e1787a7
--- /dev/null
+++ b/web/modules/block_field/tests/src/Functional/WidgetTest.php
@@ -0,0 +1,183 @@
+<?php
+
+namespace Drupal\Tests\block_field\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Test the block field widget.
+ *
+ * @group block_field
+ */
+class WidgetTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'node',
+    'user',
+    'block',
+    'block_field',
+    'block_field_test',
+    'block_field_widget_test',
+    'field_ui',
+  ];
+
+  /**
+   * The test block node.
+   *
+   * @var \Drupal\node\NodeInterface
+   */
+  protected $blockNode;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $this->drupalLogin($this->drupalCreateUser([
+      'access administration pages',
+      'access content',
+      'administer content types',
+      'administer node fields',
+      'administer node form display',
+      'administer nodes',
+      'bypass node access',
+    ]));
+
+    $this->drupalPostForm('node/add/block_node', [
+      'title[0][value]' => 'Block field test',
+      'field_block[0][plugin_id]' => 'views_block:items-block_1',
+    ], 'Save');
+
+    $this->blockNode = $this->drupalGetNodeByTitle('Block field test');
+  }
+
+  /**
+   * Test block settings are stored correctly.
+   */
+  public function testBlockSettingsAreStoredCorrectly() {
+    $page = $this->getSession()->getPage();
+    $assert_session = $this->assertSession();
+
+    $items = $this->createDummyNodes('item', 5);
+
+    $this->drupalGet($this->blockNode->toUrl('edit-form'));
+    $assert_session->checkboxChecked('Display title');
+    $assert_session->checkboxNotChecked('Override title');
+    $items_per_page_element = $page->findField('Items per block');
+    $this->assertNotNull($items_per_page_element);
+    $this->assertEquals('none', $items_per_page_element->getValue());
+    $this->assertContains('1 (default setting)', $items_per_page_element->getText());
+    $page->selectFieldOption('Items per block', 10);
+    // This view has a contextual filter to exclude the node from the URL from
+    // showing up if the context is present. Initially we do not choose that
+    // context when placing the block.
+    $exclude_element = $page->findField('Exclude');
+    $this->assertNotNull($exclude_element);
+    $this->assertEmpty($exclude_element->getValue());
+    // Save the node and check the view items.
+    $page->pressButton('Save');
+    $assert_session->pageTextContains("Block node {$this->blockNode->getTitle()} has been updated");
+
+    foreach ($items as $item) {
+      $this->assertSession()->pageTextContains($item->getTitle());
+    }
+    // The node we are visiting shows up in the views results.
+    $first_result = $this->assertSession()->elementExists('css', '.view-items .view-content > .views-row:nth-child(1)');
+    $this->assertEquals('Block field test', $first_result->getText());
+
+    // Select the context to exclude the node from the URL and try again.
+    $this->drupalGet($this->blockNode->toUrl('edit-form'));
+    $page->selectFieldOption('Exclude', 'Node from URL');
+    $page->pressButton('Save');
+    $assert_session->pageTextContains("Block node {$this->blockNode->getTitle()} has been updated");
+
+    foreach ($items as $item) {
+      $this->assertSession()->pageTextContains($item->getTitle());
+    }
+    // The node we are visiting does not show up anymore.
+    $first_result = $this->assertSession()->elementExists('css', '.view-items .view-content > .views-row:nth-child(1)');
+    $this->assertNotEquals('Block field test', $first_result->getText());
+    $this->assertEquals($items[0]->getTitle(), $first_result->getText());
+  }
+
+  /**
+   * Test configuration form options.
+   */
+  public function testConfigurationFormOptions() {
+    $assert = $this->assertSession();
+
+    // Configuration form: full (the default).
+    $this->drupalGet($this->blockNode->toUrl('edit-form'));
+    $assert->fieldExists('field_block[0][settings][label_display]');
+    $assert->fieldExists('field_block[0][settings][override][items_per_page]');
+    $assert->fieldExists('field_block[0][settings][views_label_checkbox]');
+    $assert->fieldExists('field_block[0][settings][views_label]');
+
+    // Configuration form: hidden.
+    $this->drupalGet('admin/structure/types/manage/block_node/form-display');
+    $this->drupalPostForm(NULL, [], 'field_block_settings_edit');
+    $edit = [
+      'fields[field_block][settings_edit_form][settings][configuration_form]' => 'hidden',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->drupalGet($this->blockNode->toUrl('edit-form'));
+    $assert->fieldNotExists('field_block[0][settings][label_display]');
+    $assert->fieldNotExists('field_block[0][settings][override][items_per_page]');
+    $assert->fieldNotExists('field_block[0][settings][views_label_checkbox]');
+    $assert->fieldNotExists('field_block[0][settings][views_label]');
+  }
+
+  /**
+   * Tests that validation errors from the block form are bubbled up.
+   */
+  public function testBlockFieldValidation() {
+    $assert = $this->assertSession();
+    $this->drupalPostForm('node/add/block_node', [
+      'title[0][value]' => 'Block field validation test',
+      'field_block[0][plugin_id]' => 'block_field_test_validation',
+    ], 'Save');
+
+    $node = $this->drupalGetNodeByTitle('Block field validation test');
+    $this->drupalGet($node->toUrl('edit-form'));
+    $this->submitForm([
+      'field_block[0][settings][content]' => 'error by name',
+    ], 'Save');
+    $assert->pageTextContains('Come ere boi!');
+    $assert->elementAttributeContains('css', 'input[name="field_block[0][settings][content]"]', 'class', 'error');
+    $this->submitForm([
+      'field_block[0][settings][content]' => 'error by element',
+    ], 'Save');
+    $assert->pageTextContains('Gimmie them toez!');
+    $assert->elementAttributeContains('css', 'input[name="field_block[0][settings][content]"]', 'class', 'error');
+    $this->submitForm([
+      'field_block[0][settings][content]' => 'something else',
+    ], 'Save');
+    $assert->pageTextContains('Block node Block field validation test has been updated.');
+  }
+
+  /**
+   * Create dummy nodes.
+   *
+   * @param string $bundle
+   *   The bundle type to create.
+   * @param int $numberOfNodes
+   *   The number of nodes to create.
+   *
+   * @return \Drupal\node\NodeInterface[]
+   *   And array of created nodes.
+   */
+  private function createDummyNodes($bundle, $numberOfNodes) {
+    $nodes = [];
+
+    for ($i = 0; $i < $numberOfNodes; $i++) {
+      $nodes[] = $this->createNode(['type' => $bundle]);
+    }
+
+    return $nodes;
+  }
+
+}