A few things...
1) A many_many relation is reciprocated by $belongs_many_many, not $has_one.
2) DataObject names should always be singular, because the class only controls one record at a time. "Speaker" instead of "Speakers."
3) Use the conventional getCMSFields() in lieu of the _forPopup function. That way if you ever scale it to ModelAdmin or another LeftAndMain interface, you don't have to repeat yourself.
4) Use $summary_fields for the same reason as above.
5) I just pushed a patch for the field list bug into the Github repo.
Here's your new code:
<?php
class SpeakersPage extends SiteTree {
public static $db = array(
'RightContent' => 'HTMLText',
);
public static $many_many = array(
'Speakers' => 'Speaker',
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab( 'Root.Content.Speakers', new ManyManyDataObjectManager(
$this,
'Speakers',
'Speaker'
));
return $fields;
}
}
class SpeakersPage_Controller extends ContentController {}
Speaker.php
<?php
class Speaker extends DataObject {
static $db = array(
'FirstName' => 'Text',
'LastName' => 'Text',
'Position' => 'Text',
'Company' => 'Text',
);
public static $has_one = array(
'SpeakerImage' => 'Image'
);
static $belongs_many_many = array (
'SpeakerPages' => 'SpeakersPage'
);
static $summary_fields = array(
'FirstName' => 'FirstName',
'LastName' => 'FamilyName',
'Position' => 'Position',
'Company' => 'Company',
'SpeakerImage' => 'SpeakerImage',
);
function getCMSFields() {
$fields = new FieldSet();
$fields->push( new TextField( 'FirstName', 'First Name' ) );
$fields->push( new TextField( 'LastName' ) );
$fields->push( new TextField( 'Position' ) );
$fields->push( new TextField( 'Company' ) );
$fields->push( new ImageField('SpeakerImage') );
return $fields;
}
}